用最后一个元素覆盖的数组成员

时间:2009-05-21 22:41:32

标签: c

使用以下代码,我得到了一个非常奇怪的结果。为什么最后一个元素的值会覆盖所有先前的数组元素?我怀疑这个问题不仅仅是这个问题。

#include <stdio.h>

main()
{
    int i, cases;
    char num[1000000];

    scanf("%d", &cases);
    char* array[cases];

    //store inputs in array
    for(i=0; i<cases; i++)
    {
        scanf("%s", &num);
        array[i] = &num;
    }

    //print out array items and their memory addresses
    for(i=0; i<cases; i++)
    {
        printf("%d %s\n", i, array[i]);  //print (array index) (array value) 
        printf("%d %p\n", i, &array[i]); //print (array index) (array address) 
    }
}

Inputs:
3 <-- number of lines to follow
0   <-- put in array[0]
1   <-- put in array[1]
2   <-- put in array[2]

Outputs
0 3         <-- why is this being overwritten with the last element?
0 0013BCD0
1 3         <-- why is this being overwritten with the last element?
1 0013BCD4
2 3
2 0013BCD8

7 个答案:

答案 0 :(得分:3)

此处的结果是您将array[i] = &num;元素的值设置为array[i]数组地址的行num;由于array是一个char数组,我怀疑它正在截断你的num数组地址,而低位字节恰好是3。

然而。也就是说,你的char [1000000]是一个可怕的形式,你根本不应该这样做。为了天堂的缘故,在堆上分配并选择较小的数字。此外,scanf(“%s”,&amp; num)实际上并不能满足您的需求。这是一个暗示;使用getc()循环来读取数字;这避免了需要为scanf()做一个数组的预分配。

答案 1 :(得分:2)

这是因为你在数组的每个索引中放入相同的地址(char num [1000000]的地址;)。

这是一个错误,会引导您进行动态分配(calloc,malloc,new等)。

干杯!

答案 2 :(得分:1)

在你的第一个循环中,你应该(但你不是)将每个输入写入num数组的不同元素;相反,你总是写到同一个地方,即&num

答案 3 :(得分:0)

char * array [个案];

这是在编译时分配的,而不是在运行时分配的。并且情况没有被初始化(尽管我认为你希望它无论如何都要动态工作。)所以你要么需要预先分配内存,要么熟悉malloc系列的库函数。

答案 4 :(得分:0)

这是你修复的代码:

#include <stdio.h>

main(void)
{
    int i, cases;

    scanf("%d", &cases);
    char* array[cases];

    //store inputs in array
    for(i=0; i<cases; i++)
    {
        char *num = malloc(100000);
        scanf("%s", num);
        array[i] = num;
    }

    //print out array items and their memory addresses
    for(i=0; i<cases; i++)
    {
        printf("%d %s\n", i, array[i]);  //print (array index) (array value)
        printf("%d %p\n", i, (void*)&array[i]); //print (array index) (array address)
    }
    return 1;
}

您也可以使用

char *num = calloc(100000, sizeof(char));

这有点防守。我不知道为什么你需要100000.你可以使用malloc动态地完成它。这将涉及更多的工作,但非常强大。

您的代码中的hapenning是将字符串%s存储到num的地址(不会更改),然后将array [i]元素分配给该地址。在C中分配只是存储引用,你不存储元素本身 - 这将浪费空间。因此,当所有数组元素都指向地址(仅存储引用)时,地址中的值会发生变化,因此引用也会发生变化,这就是为什么它们都变为2(而不是您在帖子中所说的3)。

答案 5 :(得分:0)

替换

//store inputs in array
for(i=0; i<cases; i++)
{
    scanf("%s", &num);
    array[i] = &num;
}

array[0] = num;
//store inputs in array
for(i=0; i<cases; i++)
{
    scanf("%s", array[i]);
    array[i+1] = array[i] + strlen(array[i]) + 1;
}

将每个字符串扫描到num[]中的第一个可用空间,并将array[]的下一个元素设置为指向下一个可用空间。现在,您的printf()字符串将起作用。原文是将每个字符串扫描到num[]的开头。

注意:scanf()%s一样糟糕,与gets()一样糟糕,因为它对将要插入的数据量没有限制。请勿在实际中使用它代码。

替换

    printf("%d %p\n", i, &array[i]); //print (array index) (array address) 

    printf("%d %p\n", i, (void*)(array[i])); //print (array index) (array address) 

实际打印a[]中存储的地址,而不是a[]元素的地址。强制转换是必需的,因为%p需要指向void的指针,因此您必须提供一个。{/ p>

答案 6 :(得分:0)

这样的事情似乎就是C ++。用户输入解析和动态分配可以更安全地完成,并且轻而易举。 我想不出一个你有这种用户界面的系统,你无法切换到C ++。

当然,如果这只是其他代码遇到问题的测试摘录,那么当然......


您的代码遭遇C初学者的几个常见错误以及现在不应该以这种方式完成的事情。

如果我理解正确,你想保存sereval用户输入字符串(你的示例输出有点误导,因为你只显示数字)。

您正在准备数组以保存指向字符串的所有(案例计数)指针,但您只为一个字符串保留内存。你需要为每个字符串都这样做,所以情况。为了简化“动态内存分配”课程,我建议采用这种方式:char* array[cases][10000];这样可以为您提供10k字符的字符串。

您可能也不希望单独指向数组元素。如果要在数组元素大于指针本身时对元素的元素进行排序,这就开始有意义了。在这种情况下,你的性能提升不是移动(复制)大块,而是只有指针(通常是4个字节)。在您的情况下,int也是4个字节长。而你无论如何都不排序:)。

至少可以说,

scanf()是危险的。在第二个应用程序中,您指示它将字符串写入数组的地址。这似乎是一个简单的错误,但可能会导致许多问题。你可能想这样做:scanf("%d", &array[i]);(不幸的是,我手头没有编译器,所以我不是100%肯定)。放下一行:)


Markdown专家提出的问题:为什么将LISTS与CODE块结合起来真是太可能了?