0
struct Example {
    char* name;
};

struct Example exampleStruct[5];

int i;
for (i = 0; i < 5; i++) {
    //Pretend aString is a different random string each loop
    char* exampleString = strtok(aString, " ");
    exampleStruct[i].name = exampleString;
}

How can I get the contents of exampleString and store it in exampleStruct[i].name on each loop through? When I currently do it by directly setting it, it is setting all of the exampleStructs' values to the same thing (which was the last iteration of the loop).

I understand it has to deal with some sort of pointers I think, but I'm not sure how to deal with this..

yoyo1
  • 35
  • 6

2 Answers2

1

The problem seems to be that "aString" is the same memory location for every iteration of the loop, so all items "exampleStruct[i].name" are pointing to the same place, which ends up having the last value of the iteration loop.

You need to use different memory location to store each of the result-strings for every iteration.

There are several alternatives to resolve this situation.

You can use strdup() which will duplicate the result string in a new "malloc-ed" memory location. This is not standard C function as described here (strdup() - what does it do in C?). Also you have to remember to free() this memory after you finish using it.

[There is also a strdupa() function but it is less portable than strdup() as described in this question strdupa() in C - Dangers and Duplicates ]

If you have already reserved memory locations for the result-strings you can use strcpy(). This is ANSI C standard.

You could also call malloc() yourself before copying the string using memcpy() like this.

struct Example {
    char* name;
};

struct Example exampleStruct[5];

int i;
for (i = 0; i < 5; i++) {
    //Pretend aString is a different random string each loop
    char* exampleString = strtok(aString, " ");
    size_t slen = strlen(exampleString) + 1; /* the +1 is to include the copy of the NULL character */
    char* tstr = malloc(slen);
    memcpy(tstr, exampleString, slen); 
    exampleStruct[i].name = tstr;
}

Remember you have safe versions of these functions: strncpy() and strndup().

Marcos
  • 139
  • 1
  • 6
  • Your `memcpy()` here won't copy the terminating null character. – Crowman Oct 24 '18 at 03:37
  • Also note that `strlen()` returns a `size_t` value, and the third argument to `memcpy()` should also be a `size_t` value, not an `int`. – ad absurdum Oct 24 '18 at 04:06
  • @PaulGriffiths , that's the reason "tstr[slen+1] = 0;" line is there... to correctly terminate the string with a NULL character. – Marcos Oct 24 '18 at 11:36
  • `tstr[slen+1] = 0` is an out-of-bounds array access leading to undefined behavior. Why not copy the `\0` in the call to `memcpy()`? – ad absurdum Oct 24 '18 at 12:39
  • @DavidBowling, it is not an out-of-bound access... notice the "+1" when the array tstr is defined: "char* tstr = malloc(slen+1);". In this case, you could also copy the '\0' in the memcpy(). I modified the code to show that. – Marcos Oct 25 '18 at 16:57
  • 1
    @Marcos -- it was an out-of-bounds access because you allocated space for `slen + 1` values, but tried to access with `tstr[slen + 1]`. The largest index you can use is `slen`, since C uses zero-based indexing (`tstr[slen + 1]` is equivalent to `*(tstr + slen + 1)` in C). Changing to use `memcpy()` to copy the `\0` has fixed the problem; your new solution is more legible, and easier to get right! – ad absurdum Oct 25 '18 at 17:45
0

What about:

exampleStruct[i].name = strdup(exampleString);
user803422
  • 2,636
  • 2
  • 18
  • 36