引入结构体
结构体这一语言特性的引入,是为了便于我们更好的抽象问题。考虑一下用C来描述一只猫的特性,比如名字,年龄,体重,花色...
char cat_name[64];
int cat_color;
int cat_age;
float cat_weight;
其实我有一个秘密要告诉你,我有两只猫,不假思索,我们可以这么描述另一只猫的特性。
char cat_name2[64];
int cat_color2;
int cat_age2;
float cat_weight2;
显然,当有更多的小家伙加入队伍时,这并不是好的方法,数组或许可以充当一个奇兵。
char cat_name[2][64];
int cat_color[2];
int cat_age[2];
float cat_weight[2];
cat_name是一个二维数组,现在仅需要知道它可以保存两只猫的名字,每个名字最多64个字符即可(含字符串结束符)。现在,我们可以优雅的使用循环来输出猫的信息了。
for (int i = 0; i < 2; i++)
{
printf("%s: %d, %d, %.2f\n", cat_name[i], cat_color[i], cat_age[i], cat_weight[i]);
}
将输出提取成一个独立的函数,可以便于我们在多个地方查看猫的特性。
void print_cat(const char *name, int color, int age, float weight)
{
printf("%s: %d, %d, %.2f\n", name, color, age, weight);
}
如果我们还要记录猫的品种、生日等更多特性,这将会导致更多分散的变量定义,更加冗长的函数参数列表等...,所以先停下来分析一下:
- 所有变量都与猫相关
- 所有变量是分散的
这就是说:这种属于同一对象的特性,却各自分离!如果C语言能内置一个满足我们需要的Cat类型,那事情会好得多,显然这不现实。好消息是,C语言提供了结构体特性,允许我们将多个属性组织成一个整体,并产生一个类型,这种内部结构由我们自己定义的类型,也称为自定义数据类型;新定义的类型,可以看作是我们对现有事物的抽象。定义一个结构的语法如下:
struct 类型名
{
成员表列
};
现在,可以这样用struct来定义(抽象)出猫这种数据类型。
struct Cat
{
char name[64];
int color;
int age;
float weight;
};
注意Cat类型中成员的命名,如name,而非cat_name。我们去掉了前缀cat,是因为这个name特性已经属于Cat类型了,所以没有必要再次指定了。显然,结构体的优异特性,就是允许我们把一个事物相关的特性集中在一起,更重要的是引入了一种类型,同内置类型相似,我们可以定义这种类型的变量,将其传递到函数、从函数返回等;不同的是,关键字struct是类型定义的一部分。如定义Cat类型变量cat1、cat2
struct Cat cat1;
struct Cat cat2;
定义Cat类型的数组
struct Cat cats[2];
对于函数声明或定义的参数,struct关键字也不可缺失。
void print_cat(struct Cat my_cat)
{
printf( "meow...\n" );
}
可以看到,结构体给程序设计带来本质性变化:将数据组织起来,抽象出新的类型!这种变化使得我们可以建立更好的逻辑。