震惊 居然是相同的结果 - HeavyYuan/A-CD-Record-Management-System GitHub Wiki

以下程序逻辑:

  1. 用户输入字符串
  2. 用用户数据赋值结构体
  3. 将结构题加入结构体数组
  4. 打印结构体数组中的所有元素

结果:

3个结构体元素的foo是相同的

struct Foo{
    char *foo;
};
struct Foo *array[10] = {0};
void fulfil_array(char *str,struct Foo *foo, int index)
{
    *foo = (struct Foo){
        .foo = str
    };
    if(index > 2){
        printf("%d, index illegal\n", index);
        return;
    }
    array[index] = foo;

}

int my_test()
{
    int i = 0;
    while( i < 3 ){
        char var[10];
        printf("var: ");
        scanf("%s",var);
        struct Foo *foo = (struct Foo *)malloc(sizeof(struct Foo));
        fulfil_array(var, foo, i);
        i++;

    }
}

void print_foo()
{
   int i;
   for(i = 0 ;i < 3; i++)
    printf("array[%d] = %s\n",i,array[i]->foo);
}

int main(void)
{
    my_test();
    print_foo();
    return 0;
}

原因:

my_test的while循环中,预期逻辑是:

  1. 声明一个字符数组
  2. 用户输入给其赋值
  3. 用字符数组赋值结构体

问题在于每次循环,var的值是相同的,都是同一个指针。 所以var是最后一次用户输入的值。

而在fulfil_array中,结构体的赋值是通过赋值符号直接赋值,因此赋值后foo和var都指向同一个位置。 所以在对var进行用户输入赋值时,实际上也就改变了foo所指向的值。

修改方法:

将对结构体元素foo的赋值方法修改成字符拷贝(strncpy)

这里有新的问题,对于char *foo,其必须先malloc之后再做strncpy

从看qemu和内核的经验,结构体中的字符串声明一般用char foo[MAX_LEN]的方式,这样就可以直接做strncpy

唱片项目也遇到以上问题,也做了如上的修改方式。见commit 3cbcf488d611085a9b0fa07821f85a152e50ec7d