0

This question is tied to Making an Array to Hold Arrays of Character Arrays in C

Borrowing code from there, I have something that looks like this (credit to luser droog for the nice example code):

enum { BUFSZ = 50 };
enum { STRVSZ = 40 };
enum { STRVVSZ = 20 };
char buf[BUFSZ + 1];
char *strv[STRVSZ + 1];
char **strvv[STRVVSZ + 1];

int j;
int i;

while(1){
    fgets(buf, BUFSZ, infile);

    i = 0;
    strv[i] = strdup(buf);
    strv[i+1] = NULL;

    j = 0;
    strvv[j] = calloc(i+1, sizeof *strvv[j]); // assuming i is the count of elements 
    memcpy(strvv[j], strv, i * sizeof *strvv[j]);
    j++;
}

This might not run right out the door, but it illustrates something similar to what I'm running. Basically, the contents of strv needs to be stored in strvv after every iteration of the loop, and strv changes over time based on user input.

Using calloc and memcpy should have caused strvv to maintain copies of strv at each iteration of the loop independent of the values in strv. However, when I print out the contents of strvv, it prints out the same string for every entry, implying that the current approach is still moving pointers around and not making copies of strv in each strvv entry.

I'm not at all sure why this happens or how to fix it. memcpy should be making a byte level copy of what the pointers in strv point to =/.

Community
  • 1
  • 1
Dae314
  • 385
  • 1
  • 2
  • 9
  • 1
    Do you **not** see the resetting of `i` and `j` to zero (0) with each iteration, and the subsequent blatant overwrite of previously saved data thereafter? Forget the code, and state the following. What is it you're **trying to do**? Make a grid of dynamic strings, where each cell is a char*, each row is a char*[], and the entire grid is a char **[]? – WhozCraig Apr 19 '13 at 02:03
  • I deserve some responsibility here. `i` was expected to be an the index of the *last entry added to `strv`*. Since `i` is zero, zero times anything is zero and the memcpy doesn't copy anything. `i` here needs to be the number of elements to copy. – luser droog Apr 19 '13 at 02:13
  • @luserdroog ok. I *think* I almost understand this now. With each "set" of strings, the new set is stored in a new row of what is a pseudo matrix, where each row can, in fact, have an arbitrary number (including zero, but no more than STRVSZ) of strings, tailed with a NULL pointer to indicate the end of the string list for that row. Is that about right? – WhozCraig Apr 19 '13 at 03:22
  • @WhozCraig Yes. That's what I was trying to explain. I *think* that's what OP is trying to do. A of s of strings. Where is implemented as a dynamic array. – luser droog Apr 19 '13 at 03:53

1 Answers1

1

This is closer to what I was trying to suggest earlier.

enum { BUFSZ = 50 };
enum { STRVSZ = 40 };
enum { STRVVSZ = 20 };
char buf[BUFSZ + 1];
char *strv[STRVSZ + 1];
char **strvv[STRVVSZ + 1];

int j; // indexes strv slices in strvv
int i; // indexes strings (char *s) in strv

j = 0; // j is index into strvv

while(!feof(infile)) {

    i = 0; // i is index into strv
    while(i < STRVSZ){
        fgets(buf, BUFSZ, infile);
        if (strcmp(buf,"END")==0) break; // end of a set

        strv[i] = strdup(buf);
        strv[i+1] = NULL;
        i++;
    }  // i is count of strv

    // copy strv into strvv
    strvv[j] = calloc(i+1, sizeof *strvv[j]); // assuming i is the count of elements 
    memcpy(strvv[j], strv, (i+1) * sizeof *strvv[j]);  // i+1 to copy the NULL pointer
    j++; // index next element in strvv and a count of strvv

} // j is count of sets in strvv

It feels like a mess still.

Functions. It needs smaller, clearly defined functions. The variables here are all placeholders for something more meaningful.

luser droog
  • 18,988
  • 3
  • 53
  • 105
  • I didn't notice the i problem in the example because I translated it into the correct variable in my own code that does get the size of the array. I can input data in strvv just fine with that code but it still all points to the same thing when I try to read out the array. – Dae314 Apr 19 '13 at 21:03
  • Hmm. I don't know! It should all work just by following the same pattern exactly for each new level. The `memcpy` should take a copy of all the pointers in `strv`. Then you should reset `i=0;` to populate `strv` with the next *set*. I left those floating because their position depends on what else is going on. – luser droog Apr 19 '13 at 21:19
  • This is turning into a nightmare! I think it's time that I looked for a better way to do what I want (hopefully one that doesn't include 3D arrays...) that will be less convoluted. Thank you so much for your help, I can't technically accept this answer since it's not actually an answer if anyone comes by this question in the future, but I'll +1 it. – Dae314 Apr 19 '13 at 22:51
  • Understood. This kind of mess was the whole reason for C++! – luser droog Apr 19 '13 at 23:03