给结构体变量赋值

39

结构类型被定义为:

typedef struct student{
    int id;
    char* name;
    double score;
} Student;

我创建了一个类型为“Student”的变量,现在想为其赋值。有什么高效的方法吗?

int main(){
    Student s1;

    int id = 3;

    char* name = getName(id);

    double score = getScore(id);

    /*Error
    s1 = {id, name, score};
    */

    /*  Can I avoid assigning values individually?
    s1->id = id;
    s1->name = name;
    s1->score= score;
    */

    return 0;
}

3
除非我没有理解问题,否则这是一个“C基础学习”问题,应该通过学习C结构体及其使用方法自行回答。然而,你正在讨论如何使用唯一ID访问结构体实例。对此,你还应该了解什么是“C指针”。 - Oragon Efreet
3个回答

139
在C99标准中,您可以使用复合字面量(compound literals)来分配值:
Student s1;
s1 = (Student){.id = id, .name = name, .score = score};

45
直到2017年5月10日,我无法相信没有人给出这个答案。 - Nick Lee
1
如果您没有指定所有参数会发生什么?例如,假设s1已经初始化,并且您想要覆盖姓名和分数,但不是id。 您可以只说s1 = (Student) { .name = name, .score = score }吗?还是这会以某种方式覆盖id?并且这个行为是可移植的吗? - gabe appleton
7
结构体赋值操作会用右侧结构体的数据替换左侧结构体。在您给出的示例中,右侧结构体采用指定初始化器,未指定的字段将默认初始化为零。然后,s1将被新结构体的内容所替换。因此id字段将被设置为零。 - Alexander Ushakov
1
@BobtheMagicMoose 在这里提到的“个人作业”是指指定初始化器。它是一种不同于您示例中的值初始化器的初始化器类型。使用指定初始化器,我们可以省略某些字段的值。这种初始化器允许区分结构体初始化和数组初始化,在值初始化器的情况下它们非常相似。在@jerico的链接中,也有关于结构体的指定初始化器示例。 - Alexander Ushakov
1
您可以根据需要使用任何初始化类型。C标准允许两种类型的初始化。 - Alexander Ushakov
显示剩余3条评论

41

注意,结构体和指向结构体的指针是两个不同的东西。

C 语言提供以下功能:

  • 在声明时初始化结构体:

  • struct Student s1 = {1, "foo", 2.0 }, s2;
    
  • 结构体复制:

    struct Student s1 = {1, "foo", 2.0 }, s2;
    s2 = s1;
    
  • 直接元素访问:

  • struct Student s1 ;
    s1.id = 3;
    s1.name = "bar";
    s1.score = 3.0;
    
  • 通过指针进行操作:

    struct Student s1 = {1, "foo", 2.0 }, s2, *ps3;
    ps3 = &s2;
    ps3->id = 3;
    ps3->name = "bar";
    ps3->score = 3.0;
    
  • 初始化函数:

  • void initStudent(struct Student *st, int id, char *name, double score) {
        st->id = id;
        st->name = name;
        st->score = score;
    }
    ...
    int main() {
        ...
        struct Student s1;
        iniStudent(&s1, 1, "foo", 2.0);
        ...
    }
    
    在这些中挑选一个(或者其他符合C标准的),但是s1 = {id, name, score};只会产生语法错误;-)

7

我能避免逐个赋值吗?

如果这些值已经是类似的struct的一部分,那么您可以这样做:

Student s1 = {.id = id, .name = name, .score = score};

这将创建一个Student实例,并初始化您指定的字段。这可能并不比逐个赋值更有效,但它使代码简洁。一旦您拥有现有的Student实例,就可以通过简单的赋值语句复制它:

Student s2;
s2 = s1;    // copies the contents of s1 into s2

如果值都在单独的变量中,而且你没有初始化Student,那么你可能需要逐个分配这些值。但你可以编写一个函数来自动完成,这样就可以像下面这样使用:

setupStudent(s3, id, name, score);

这样做可以让你的代码更简洁,确保结构体每次都以相同方式填充,并在Student的定义发生变化时简化你的工作(而不是如果)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接