数组中的所有元素都设置为C中的最后一个元素?

时间:2018-10-13 03:43:32

标签: c

很抱歉,如果这是一个愚蠢的问题,但是我遇到一个问题,即我数组中的所有元素都被设置为C中的最后一个元素。我想我正在重写某些东西,并且想要另一双眼睛。我的目标是创建一个随机类型为char类型的数组。代码如下:

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;

所有这些的结果是:

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

我只是想知道我正在做些什么来掩盖所有这些价值观。谢谢。

3 个答案:

答案 0 :(得分:2)

在您的代码中,p是8个指向char的指针的“数组”。这意味着您将在数组p中存储一个地址位置。 如果您像这样打印地址和数据-

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

您会注意到,数组(p)中的所有值都是相同的,即数组中的所有元素都是“相同”的,这恰好是第二个for()循环输出的结果。该地址是局部变量random_number_string的地址。 第一个循环将打印不同的数据,因为第一个循环将在每次迭代中更改数据,并且在最后一次迭代后,此地址位置包含“ last”值集。

希望这可以澄清您所看到的行为。

答案 1 :(得分:0)

第一个循环的每次迭代都会创建其本地char random_number_string[8];数组的新实例,然后在末尾销毁它。在该循环的每次迭代中,您将在random_number_string中存储指向该p[i]数组开头的指针。每个指针p[i]在每次第i次迭代的结尾都变成“酸”(悬挂)。因此,所有p[i]值最终都无效。任何尝试访问这些值的操作都将导致未定义的行为。

这正是您第二个周期所做的。您的程序的行为是不确定的。

注意,顺便说一句,说所有数组元素都指向相同的内存位置是不正确的(就像这里的一些答案一样)。您的数组p包含无效不确定的指针值。关于这些值,无话可说。

答案 2 :(得分:0)

您的第一个循环的每次迭代都定义了'char random_number_string [8]',为此空间从堆栈帧中分配。每次迭代都不会增加堆栈帧的大小,但是会重用与先前迭代相同的堆栈空间,这意味着在random_number_string周围的每次都将在完全相同的地址处找到。并且由于您将random_number_string的地址放入“ p”数组的每个元素中,因此每个元素都具有相同的值。无论您放置在该地址的什么内容,都将由数组中的每个元素指向。

但是还有另一个问题,就是您的代码。您已经将自动变量的地址放置在另一个数据结构中,问题在于,包含random_number_string的堆栈帧在第一个循环的每次迭代结束时从堆栈中弹出,并将被后续的堆栈帧/代码块重用。

如果您事先知道所有这些字符串的最大大小,则可以简单地使用二维数组预先分配其中的大部分。这是用这种方法编写的代码:

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;
}

或者,您可以动态地(从堆中)分配它们。完成程序后,可能需要释放它们,具体取决于您的程序。

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;
}