?
Solved

Passing an array to funciton, part of the array object is lost ?

Posted on 2003-03-25
2
Medium Priority
?
294 Views
Last Modified: 2012-05-04
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fstream.h>
#include <iostream.h>
#include <iomanip.h>

int partNumber;
double noRounds;       

class Player {

public:
  char id[3];
  char* name;
  char* ranking;
  int intRanking;

  Player() {
   
    name = 0;
    ranking = 0;
    intRanking =0;
  }

  ~Player() {
    if (id) delete [] id;
    if (name) delete [] name;
    if (ranking) delete [] ranking;
  }
 
  void setDetails (char *array);
  void setIds(char *ids, int startPos);  
  void convertRanking(char* ranking);
  void resetName(Player player, Player* playerArray);

}; //end of player class

//////////////////////////////Player functions////////////////////////////////////////////

 void Player::setDetails (char *array) {
   
    //set the name of the player
    char tmpNameArray[13];
    int n=3;
    int y =0;
   
    while(array[n] != ' '){
      tmpNameArray[y] = array[n];
      y++;      
      n++;
    } // end of the do while loop
   
    tmpNameArray[y] = '\0';
   
    name = new char[strlen(tmpNameArray)];
   
    //set the players ranking
    char tmpRankingArray[5];
   
    int z=0;
   
      for (n; n<strlen(array); n++){      
        if (array[n] != ' '){
          tmpRankingArray [z]= array[n];
          z++;
        }
      }
      
      tmpRankingArray[z] = '\0';
      
      ranking = new char [strlen(tmpRankingArray)];

      strcpy(name, tmpNameArray);
      strcpy(ranking, tmpRankingArray);

  }//end of set details
 
 void Player::setIds(char *ids, int startPos){
    id[0] = ids[startPos];
      id[1] = ids[startPos+1];
      id[2] = '\0';

}// end of setIds

void Player::convertRanking(char* ranking){
   
      for (int x=0; x < partNumber; x++){
            char * ch;
            intRanking = int(strtod (ranking, &ch));
      }

} // end of convert ranking

void Player::resetName(Player player, Player *playerArray){
      
      cout << player.name;
      cout << playerArray[1].name;

}

//////////////////////////Matches class/////////////////////////////////////////
class Match{

      public:

      Player player1;
      Player player2;
      int matchNumber;

}; // end of Matches class

///////////////////////////////Match Functions////////////////////////////////////////////////////////



////////////////////////////////////////////////////////General class//////////////////////////////////////
class General {
      
      public:

      General(){
      }

      ~General(){
      }

      void participantsCount(int &count);
      char* removeSpaces(char *text);
      void sortRank(Player *playerArray);
      Player* createMatches1(Player *playerArray, int number);
      Match* setMatches1(Match* matchArray, Player* playerArray);
      void createTheTree(Player* playerArray, Match* matchArray);
      
}; // end of general class

////////////////////////////////////////////General Class Functions////////////////////////////////////////////////////

//Count the number of participants function
void General::participantsCount(int &count) {
 
  ifstream partStream ("participants.dat");
 
  while (!partStream.eof()){
    //remove first line
    partStream.ignore(50, '\n');
    //remove the second line
    partStream.ignore(50, '\n');
    while (!partStream.eof()){
      char ch;
      partStream.get(ch);
      if (ch == ' '){
      count++;
      }
    }
   
  }
 
} // end of participants count

//remove the first 2 spaces from each line
char* General::removeSpaces(char *text){
    int x;
   
    do {
      for (x = 0; x < strlen(text); x++){
      text[x] = text[x+1];
        }
     
      text[strlen(text)] = '\0';
    }while (text[0] == ' ');
   
    return text;
}

void General::sortRank (Player *playerArray){
      
      int a,b;
      Player temp;

      for ( b = 0; b < partNumber - 1; b++){
         for  (a = 0; a < partNumber - 1; a++){
               if (playerArray[a].intRanking < playerArray[a+1].intRanking){
                   temp = playerArray[a];
                   playerArray[a] = playerArray[a+1];
                   playerArray[a+1] = temp;

                     }
             }
      }
} // end of sort Players by rank

Player* General::createMatches1(Player *playerArray, int number) {


Player odds[number/2], evens[number/2];
      Player * temp1;
      Player * temp2;

      if (number == 2) {
            return playerArray;
      } else {
            for (int n = 0; n < number-1; n+=2) {
                  evens[n/2] = playerArray[n];
            } // end for

            for (int n = 1; n <= number-1; n+=2) {
                  odds[n/2] = playerArray[n];
            } // end for

            temp1 = createMatches1(evens, number/2);
            temp2 = createMatches1(odds, number/2);
      }

      for (int n = 0; n < number/2; n++){
            playerArray[n] = temp1[n];      
      }

      for (int n = number/2; n < number; n++) {
            playerArray[n] = temp2[n-(number/2)];
      }

      return playerArray;

} // end function create matches 1

Match* General::setMatches1(Match* matchArray, Player* playerArray){

      int y=0;

      for (int x=0; x<partNumber; x+=2){
            matchArray[y].player1 = playerArray[x];
            matchArray[y].player2 = playerArray[x+1];
            matchArray[y].matchNumber = y+1;
            y++;
      }

      return matchArray;
}// end of setMatches

void General::createTheTree(Player* playerArray, Match* matchArray){

      double numberR = noRounds;
      int numberM = partNumber/2;

      ofstream treeDat("tree.dat");
      ofstream treeHtml("tree.html");

      treeDat << "Matches for round 1" << endl;
      treeDat << endl;

      treeHtml << endl;
      treeHtml << endl;
      
      for (int x=0; x <numberR; x++){
            treeHtml << "<table border = 1>" << "<caption align = top><font color=red>" <<"Round "  << x << "</font>" << endl;
            for (int x=0; x <numberM; x++){
                  treeDat << "Match" << setw(3) << matchArray[x].matchNumber <<":  " <<"Player:  " <<  setw(3) << matchArray[x].player1.id << "  will play" << setw(3) << matchArray[x].player2.id << endl;
                  treeHtml << "<tr>" "<td>"<< "<font color=blue>" << "Match " << "</font>" << matchArray[x].matchNumber << ":  " << "</font>" << "Player:  " << matchArray[x].player1.id << "  will play" << setw(3) << matchArray[x].player2.id << "</td></tr>" << endl
                                    << "</table>";
            }// end of outputting matches
      } // end of outputting rounds
      

} // end of create the tree

////////////////////////////////////////////////////MAIN/////////////////////////////////////////

int main(){
      
      General general;
  int count = 0;
  general.participantsCount(count);
  partNumber = count -2;
  noRounds = sqrt(partNumber);

  Player player;      //player
  Player *playerArray;
 
  Match match; //match
  Match *matchArray;

  //////////EXTRACT PARTICIPANTS////////////
  int arrayLength = (partNumber * 3) +1;
  char *firstCharArray;
  char *participantsArray; //IDs of partcipants
      
  ifstream partStream ("participants.dat");

  playerArray = new Player [partNumber];

  while (!partStream.eof()){
    //remove first line
    partStream.ignore(100, '\n');
    //remove the second line
    partStream.ignore(100, '\n');
    // extract the the third line
    firstCharArray = new char[arrayLength];
    partStream.getline(firstCharArray, 100, '\n');
    participantsArray = firstCharArray;
    delete [] firstCharArray;
    break;
    //ignore the fourth line
    partStream.ignore(100, '\n');
  }
      
  partStream.close(); // close the file

  //remove spaces from participants
  char IDs [(partNumber*2) + 1];
 
  IDs[0] = *(participantsArray);
  IDs[1] = *(participantsArray +1);
 
  //int z=2;
  int y=2;
 
  for (int x =2; x < arrayLength; x++){
   
    if (*(participantsArray + x) == ' '){
    }else{      
      IDs[y] = *(participantsArray + x);
      y++;
    }
  }

  delete [] participantsArray;
 
  IDs[(partNumber*2)] = '\0';
 
   // create player struct variable IDS.
  int x=0;

  for (int n = 0; n < strlen(IDs); n+=2) {
    player.setIds(IDs, n);
    playerArray[x] = player;
    x++;
  }
 
  ///////////////////////EXTRACT players.dat/////////
 
  ifstream playerStream ("players.dat");
 
  char lineArray[30];
  char *secondCharArray;
  secondCharArray = lineArray;
        
  int currentPlayer=0;
 
  while (!playerStream.eof()){
   
    playerStream.getline(secondCharArray, 100, '\n');
    if (secondCharArray[0] != '/' && secondCharArray[1] != '/'){
      general.removeSpaces(secondCharArray);
      if (secondCharArray[0] == playerArray[currentPlayer].id[0] && secondCharArray[1] == playerArray[currentPlayer].id[1]){
            playerArray[currentPlayer].setDetails(secondCharArray);      
            currentPlayer++;
      }
    }
   
  } // end of reading in the file
  playerStream.close();

  //set all the rankings to integers
  for (int x=0; x <partNumber; x++){
      playerArray[x].convertRanking(playerArray[x].ranking);
  }
 
  //sort players in descending order
  general.sortRank(playerArray);
      
  //produce round 1
      Player* newPlayerArray;
      newPlayerArray = new Player [partNumber];
      newPlayerArray = general.createMatches1(playerArray, partNumber);

       for (int x=0; x <partNumber; x++){
            //cout << newPlayerArray[x].name;
       }
      
 
  //set the matches
      
      matchArray = new Match [partNumber/2];
      matchArray = general.setMatches1(matchArray, newPlayerArray);

      for(int x=0; x < partNumber/2; x++){
            cout << matchArray[x].player1.id;
      }

      general.createTheTree(newPlayerArray, matchArray);

      return 0;
 
}

see previous question (antos) for the problem. Thanks again.

Ant
0
Comment
Question by:carbutt
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
2 Comments
 
LVL 6

Accepted Solution

by:
GaryFx earned 75 total points
ID: 8204652
Simple answer:  Either use strings, or else define a copy constructor and assignment operator for Player.  Furthermore, remove the delete []id from the destructor.  It wasn't created with new, therefore it can't be deleted with delete.  (I'm surprised this hasn't blown up on you.)

Long answer:  Since you don't have your own copy constructor or assignment operator, whenever you copy a Player they wind up sharing the same character pointers for name and ranking.  However, if one of those copies gets deleted, then the character pointers get deleted (by your destructor), leaving the other copy with invalid pointers.

This is known as the Big Three in the C++ FAQ.  It means that any time you write a destuctor, you almost certainly need to write a copy constructor and an assignment operator (and likewise if you write one of the others first).

If you use standard strings, then you no longer need your own destructor, and the problem goes away.

Gary
0
 
LVL 30

Expert Comment

by:Mayank S
ID: 8208171
>> if (id) delete [] id;

Don't do it.... id[] has been defined as an array, not as a pointer. Its not been allocated memory using new, so the delete[] is not needed.

Man, your code is too long to debug but all that I would like to say is that whenever you're using pointer data-members in a class, with a destructor having 'delete' statements, then you should be a little careful while passing objects as arguments. You should never pass them by value, as then, a new object is instantiated (the formal argument in the called function), the values of the data-members are copied (including the pointer data-members), so the pointer data-member of the formal argument in the callED function points to the same location as the actual argument in the callING function, and when this called function finishes execution, the destructor is called for the formal argument which deallocates the memory because of the 'delete' statements, and thus, the actual argument's pointer data-member (in the callING function) is now also pointing to garbage.

Hope that you got that, and its of help to you!

Mayank.
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In days of old, returning something by value from a function in C++ was necessarily avoided because it would, invariably, involve one or even two copies of the object being created and potentially costly calls to a copy-constructor and destructor. A…
Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.
Suggested Courses

764 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question