0

I've looked enough about this problem on this site and still haven't found a solution. I have an array of struct, and I want to read from a file some records and store them in the structs. The problem is the allocation of the memory. This is the struct I use:

struct Rec{
    int mat;
    char *nome;
    char *cognome;
};
typedef struct Rec* Record; 

This is the readFromFile function:

void readFromFile(char* fileName, Record** data, int* pn) 
{
   char line[LINE_LENGTH];
   int n, i;
   char* token;
   printf("\n\nReading file %s\n", fileName);
   FILE* fin = fopen(fileName, "r"); 
   if (fin == NULL) 
   {  printf("Error readinf file\n");getch();
      goto end;
   }
   n = 0;         // first read to know the number of lines
   while (fgets(line, LINE_LENGTH, fin) != NULL) n++;
   n = (n < MAX_LENGTH ? n : MAX_LENGTH);
   printf("N: %d\n", n);
   *pn = n;

   //Then I allocate the memory for the n lines I previously read
   *data = (Record*)malloc(n * sizeof(Record));
   if(*data == NULL){
    printf("Problem allocating memory\n");
    exit(0);
   }
   i = 0;
   for(i = 0; i < n; i++){
        (*data)[i].nome = malloc(sizeof(char) * MAX_LENGTH + 1);
        if((*data)[i]->nome == NULL){
            printf("Problem allocating memory\n");
            exit(1);
        }
        //Here comes the problem, the allocation of the second string fails and the program exit
        (*data)[i]->cognome = malloc((sizeof(char) * MAX_LENGTH + 1));
        if((*data)[i]->cognome == NULL){
            printf("Problem allocating memory\n");
            exit(2);
        }
   }
   rewind(fin);                         
   n = 0;
   while (fgets(line, LINE_LENGTH, fin) != NULL && n < MAX_LENGTH)
   {
        token = strtok(line, ";");
        strcpy((*data)[n]->nome, token);
        token = strtok(line, ";");
        strcpy((*data)[n]->cognome, token);
        token = strtok(line, ";");
        (*data)[n]->mat = atoi(token);
        n++;

   }
   fclose(fin);                         
   end:return;
}

I've tried to modify the structure and the code in many ways but have not found a solution, I think that probably is a pointer problem but I can't figure it out. The readFromFile function was provided from the professor and was built to read int from file and I had to modify it to read records.

SnpShot
  • 13
  • 3
  • `Record** data,` That adds up to three stars. (Record already is the dreaded typedeffed pointer) – joop May 17 '16 at 09:45
  • 2
    You should not hide pointers behind `typedef`. – user694733 May 17 '16 at 09:53
  • See also: https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc – user4520 May 17 '16 at 09:57
  • Please, use `return;` instead of `goto end;` and was the typedeffed pointer provided by your professor too? – Bob__ May 17 '16 at 11:02
  • Besides, if the strings in the data struct are all supposed to have the same size, you can define that struct as: `typedef struct { int mat; char nome[SIZE]; char cognome[SIZE]; } Record;` and their memory will be automatically allocated with the struct allocation. – Bob__ May 17 '16 at 11:08

2 Answers2

0

Record is defined as

typedef struct Rec* Record;

therefore it is pointer to struct Rec. malloc returns pointer to allocated memory (or NULL) but you cast this to pointer to pointer

*data = (Record*)malloc(n * sizeof(Record));
//    =  Rec**
4pie0
  • 29,204
  • 9
  • 82
  • 118
0

There's a big difference between:

(*data)[i].nome = malloc(sizeof(char) * MAX_LENGTH + 1);

and:

(*data)[i]->cognome = malloc((sizeof(char) * MAX_LENGTH + 1));

The first line with the dot notation used, is implying, access to a member of a struct, whereas the -> implies accessing a member of a struct using pointer notation, i.e. pointer to a structure.

The confusion is showing there, as (*data) is a pointer to a struct of type Record which is a type definition of Rec.

typedef struct Rec* Record; 

Since data when stripped down, is type definition of Record, aliased to a pointer to struct of Rec. The double pointer as part of parameter, which will be modified through pass by reference, is declared, after determining the number of lines in input dataset, as an array of pointers:

*data = (Record*)malloc(n * sizeof(Record));

Accessing the member data, for each entry in the array would be:

(*data)[i] dot name_of_member

The rule would have changed, had the type definition be like this:

typedef struct Rec Record;

i.e. a normal struct, no pointer usage.

Then access to the member data would have been, if allocation was achieved,

(*data)[i]->name_of_member

However, do not try hide pointers behind a typedef as that will give grief, come back to the code again in the future, and wondering why it failed, the hidden pointer has bitten you!

t0mm13b
  • 34,087
  • 8
  • 78
  • 110