filpa
filpa

Reputation: 3654

Unintended behaviour after realloc() with dynamic array

I have an assignment where I want to implement a dynamically growing array, but I seem to be having some issues with realloc(). My code works as long as I do not actually get to the realloc() part, where for some reason only some specific values are being changed to something different. Now, I would expect the rows to be completely different if I was writing/reading out of bounds, but I can't seem to pinpoint it. The problem seems to lie between lines 30-40. Here is the code:

1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 typedef struct __student {
6         unsigned long ID;
7         char fname[33];
8         char lname[33];
9         float grade;
10 } student;
11
12 void partA(FILE *fp) {
13
14         int i, r;
15         i = r = 0;
16         int N = 1000;
17         student **S;
18
19         S = malloc(sizeof(student *) * N);
20
21         // While EOF has not been reached
22         while(!feof(fp)){
23                 // Allocate enough memory to hold each student struct
24                 S[i] = malloc(sizeof(student));
25                 // Get each line and, using a scanset, get corresponding
26                 // data into respective struct fields
27                 fscanf(fp, "%d %[^,], %s %f", &S[i]->ID, S[i]->lname, S[i]->fname,  &S[i]->grade );
28                 i++; // Get next line into a new struct
29
30                 // If array size has been reached...
31                 if(i == N){
32                         N *= 2;
33                         // Double it
34                         S = realloc(S, sizeof(student) * N);
35                         if(S == NULL) {
36                                 // realloc has failed
37                                 printf("Memory reallocation failed; Fatal error.");
38                                 break;
39                         }
40                 }
41         }
42         r = i-1;
43         // Output data
44         printf("Name\t\t\t\t\t\t\t\t  [ID]\t\t:\tGrade\n");
45            printf("___________________________________________________________________________________________________\n");
46         for(i=0; i<r; i++){
47                 printf("%-32s %-32s [%lu]\t:\t%.3f\n", S[i]->fname, S[i]->lname, S[i]->ID, S[i]->grade);
48                 free(S[i]);
49         }
50 }

Here is the input file I am using:

58205720 Broke, Jim 95
29571057 Crowe, John 88
12957206 Moore, Kim 22
59376027 Sarasvaki, Joe 79
49027650 Morrigan, Tracy 68
30773967 Trund, Geoffrey 99
34850470 Perry, Tracey 77
70209658 Oatnel, Skye 89

The expected output is the following (which I do get as long as N is high, ie. larger than actual number of lines and does NOT cause realloc() to be invoked):

Name                                                              [ID]          :       Grade
___________________________________________________________________________________________________
Jim                              Broke                            [58205720]    :       95.000
John                             Crowe                            [29571057]    :       88.000
Kim                              Moore                            [12957206]    :       22.000
Joe                              Sarasvaki                        [59376027]    :       79.000
Tracy                            Morrigan                         [49027650]    :       68.000
Geoffrey                         Trund                            [30773967]    :       99.000
Tracey                           Perry                            [34850470]    :       77.000
Skye                             Oatnel                           [70209658]    :       89.000

However, if I set N = 3, I get the following:

Name                                                              [ID]          :       Grade
___________________________________________________________________________________________________
Jim                              Broke                            [58205720]    :       95.000
John                             Crowe                            [29571057]    :       88.000
Kim                              Moore                            [12957206]    :       22.000
Joe                              Sarasvaki                        [59376027]    :       79.000
Tracy                            Morrigan                         [49027650]    :       68.000
Geoffrey                         Trund                            [30773967]    :       99.000
Tracey                           Perry                            [231963084454]        :       77.000
Skye                             Oatnel                           [231998443642]        :       89.000

I am quite at a loss as to what is happening. I've tried examining the stack and local values using gdb, but haven't had much luck yet. I am also conflicted as to why the ID is the only thing to be corrupted. Would it be necessary make a separate function which would return a pointer to the new space I get by realloc()? I wanted to keep my code as compact as possible, so I opted to try it this way first as the man page seemed to back up my assumption about the way realloc() works. Thank you.

Upvotes: 0

Views: 185

Answers (1)

David Schwartz
David Schwartz

Reputation: 182847

     unsigned long ID;

Okay, ID is an unsigned long.

     fscanf(fp, "%d %[^,], %s %f", &S[i]->ID, S[i ...

Hmm, is %d the format specifier for an unsigned long? I don't think so.

Also, feof doesn't predict that a future read will succeed, it only tells you what already happened. You need to check the return value of fscanf to see if the read succeeded.

Lastly, your realloc call allocates too much memory. You're only trying to hold pointers in S itself.

Upvotes: 1

Related Questions