简体   繁体   中英

All elements in array being set to last element in C?

sorry if this is a stupid question but I'm having an issue where all the elements of my array are being set to the last element in C. I think I'm overriding something and would like another pair of eyes. My goal is create an array of random numbers of type char. Code is below:

int main(int argc, char *argv[]) {
    unsigned int seed = atoi(argv[1]);
    printf("seed = %d\n", seed);
    srand(seed); //NOTE: i seed random from the command line
    unsigned char *p[8];
    for(int i = 0; i < 8; i++){
        int random_number = rand() % 255;
        char random_number_string[8];
        itoa(random_number, random_number_string, 10);
        p[i] = random_number_string;
        //below is just to check
        printf("p[%d] = %s\n", i, p[i]);
    }
    // below i comment out irrelevant parts of the code 
    //unsigned char byte0[8];
    //itoa( (rand() % 256), byte0, 10);
    //printf("byte0 = %s\n", byte0);
    //printf("Binary values: \n");
    for(int n = 0; n < 8; n++){
        printf("p[%d] = %s\n", n, p[n]);
        //PRINTBIN((int)p[i]);
        //printf("\n");
    }
    return 0;

The result of all this is:

seed = 1054480
p[0] = 81
p[1] = 66
p[2] = 36
p[3] = 32
p[4] = 81
p[5] = 245
p[6] = 33
p[7] = 72

p[0] = 72
p[1] = 72
p[2] = 72
p[3] = 72
p[4] = 72
p[5] = 72
p[6] = 72
p[7] = 72

I'm just wondering what I'm doing to overwite all those values. Thanks.

In your code, p is an "array" of 8 pointers to char. This means that you are storing an address location in the array p. If you print the addresses along with the data like so -

printf("p[%d] = %s\n", i, p[i]);
printf("%d\n", p[i]);

You will notice that all the values in the array (p) are same, ie all the elements in the array are "same" and that is exactly what is your output shows from the second for() loop. This address is the address of the local variable random_number_string. The first loop is printing different data as the first loop is changing the data in every iteration and after the last iteration, this address location contains the "last" value set.

Hope this clarifies the behavior that you are seeing.

Each iteration of the first cycle creates a new instance of its local char random_number_string[8]; array and then destroys it at the end. On each iteration of that cycle you are storing a pointer to the beginning of that random_number_string array in p[i] . Each pointer p[i] becomes "sour" (dangling) at the end of each i -th iteration. Thus all p[i] values end up invalid. Any attempts to access these values result in undefined behavior.

And this is exactly what your second cycle does. The behavior of your program is undefined.

Note, BTW, that it is incorrect to say that all of your array elements point to the same memory location (as some answers here do). Your array p contains invalid , indeterminate pointer values. Nothing definitive can be said about these values.

Each iteration of your first loop defines 'char random_number_string[8]' and the space for this is allocated from the stack frame. Each iteration does not increase the size of the stack frame, but is going to reuse the same stack space as the prior iteration, meaning that each time around random_number_string will be found at exactly the same address. And since you are placing the address of random_number_string into every element of your 'p' array, every element holds the same value. Whatever you place at that address will be pointed to by every element in your array.

But there's another, issue with your code. You have placed the address of an auto variable into another data structure, The problem is that stack frame that contained random_number_string is popped off the stack at the end of each iteration of your first loop, and will be reused by subsequent stack frames / code blocks.

If you know in advance the maximum size of all of these strings, then you can simply pre-allocate the lot of them with a two dimensional array. Here is the code written with this approach:

int main(int argc, char *argv[]) {
    unsigned int seed = atoi(argv[1]);
    printf("seed = %d\n", seed);
    srand(seed); //NOTE: i seed random from the command line
    unsigned char p[8][10];
    for(int i = 0; i < 8; i++){
        int random_number = rand() % 255;
        itoa(random_number, p[i], 10);
        printf("p[%d] = %s\n", i, p[i]);
    }
    for(int n = 0; n < 8; n++){
        printf("p[%d] = %s\n", n, p[n]);
    }
    return 0;
}

Alternatively, you could dynamically allocate them (from the heap). Depending your program, you may need to free them when you are done with them.

int main(int argc, char *argv[]) {
        unsigned int seed = atoi(argv[1]);
        printf("seed = %d\n", seed);
        srand(seed); //NOTE: i seed random from the command line
        unsigned char *p[8];
        for(int i = 0; i < 8; i++){
            int random_number = rand() % 255;
            p[i] = (unsigned char *)malloc(10 * sizeof(unsigned char));
            itoa(random_number, p[i], 10);
            printf("p[%d] = %s\n", i, p[i]);
        }
        for(int n = 0; n < 8; n++){
            printf("p[%d] = %s\n", n, p[n]);
        }
        return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM