Nico Nico - 3 months ago 7
C Question

Array of structs inside a loop

I'm learning C and i'm playing around with structures, but i have found some behaviour i can't explain, and i'd like to know why it happens.

This is my code:

struct my_struct{
char *name;
};

int main()
{

struct my_struct arr[3];
int i = 0;
char str[10];

while (i<3)
{
fgets(str, 10, stdin);
arr[i].name = str;
printf("Array number %d: %s", i, arr[i].name);
i++;
}

printf("1 - %s\n2 - %s\n3 - %s", arr[0].name, arr[1].name, arr[2].name);

return 0;
}


The issue is, as long as the while loop keeps running, it seems to be alright; however, when it exits, it seems to set each of the "name" values of the structs in the array to the last one's.

If, once out of the loop and before the last printf(), I set the name of the last struct in the array manually, that is the only one which is updated, but the previous structs' names are still set to the last one entered inside the loop.

I imagine i'm missing sth about memory management like flushing the buffer before calling to fgets() again or sth, but can't figure out what is happening. Does anyone know what this is about?

Ben Ben
Answer

This is what you expect, think about it this way, you have char str[10], this is the memory in which your string is stored. When you set each of the array names with arr[i].name = str you are pointing the char * name at this memory. So here is what your for loop is doing:

0. str = [];         arr[0].name = NULL; arr[1].name = NULL; arr[1].name = NULL;
1. str = [string1];  arr[0].name = str;  arr[1].name = NULL; arr[1].name = NULL;
2. str = [string2];  arr[0].name = str;  arr[1].name = str;  arr[1].name = NULL;
3. str = [string3];  arr[0].name = str;  arr[1].name = str;  arr[1].name = str;

So by the end of the loop, all of the arr.name pointers point at string and you have edited the string each time. If you want the individual arr elements to store their own string then you are better off doing this:

struct my_struct{
  char name[10]; // Note how each instance of `my_struct` now stores its own string.
};

int main() {
  struct my_struct arr[3];
  int i = 0;

  while (i<3) {
    fgets(arr[i].name, 10, stdin);
    printf("Array number %d: %s", i, arr[i].name); 
    i++;
  }

  printf("1 - %s\n2 - %s\n3 - %s", arr[0].name, arr[1].name, arr[2].name);

  return 0;
}

Live example

As a final note you should avoid using fgets (see here). Prefer getline instead.