结构体#
结构体是一个或多个变量的集合,和数组一样,也是一种复合数据类型。结构体将不同数据类型的变量组合到一个名称中,不管是逻辑上还是编程操作上都比较便利,常用于创建较为复杂的数据结构。
声明和定义#
结构体可以利用基本数据类型来自定义新的数据类型。通过结构体变量访问成员,可以使用点 .
操作符;通过结构体变量的指针访问成员变量,可以使用间接引用 *
操作符,也可以使用成员访问 ->
操作符。
struct point { // declaring a struct type
int x;
int y; // members of each date structure
};
struct point pt;
pt.x = 1;
pt.y = 2;
// or
struct point pt2 = {1, 2};
struct point* ptPtr = &pt;
(*ptPtr).x = 3;
// or
ptPtr->x = 3;
typedef 别名#
上述定义方式,每次都要添加 struct
关键字,使用 typedef
可以定义类型的别名,避免这个问题。
typedef struct point {
int x;
int y;
} point;
typedef struct point* point_ptr;
point pt = {1, 2};
point_ptr pt_p = &pt;
printf("pt(%d, %d)\n", pt.x, pt.y);
printf("pt(%d, %d)\n", pt_p->x, pt_p->y);
函数参数——传值 or 传地址#
将结构体传递给函数,和基本类型一致,都是传值。这一定要区别于数组。
为了避免数组拷贝造成的性能问题,可以通过传递指针的方式解决。
void add_points(point_ptr lhs, point_ptr rhs) {
lhs->x += rhs->x;
lhs->y += rhs->y;
}
int main(int argc, char* argv[]) {
point pt = {1, 2};
point pt2 = {2, 1};
add_points(&pt, &pt2);
printf("pt(%d, %d)\n", pt.x, pt.y); // pt(3, 3)
return 0;
}
上述方式,通过指针传递结构体,虽然避免了拷贝,但是却修改了 lhs
的值。某些情况下,这是一种不太好的设计。
函数返回值#
C 允许通过函数返回结构体,所以上述案例可以通过返回值创建一个新的结构体,并利用 const
关键字防止修改参数的实体。
point add_points(const point_ptr lhs, const point_ptr rhs) {
point pt;
pt.x = lhs->x + rhs->x;
pt.y = lhs->y + rhs->y;
return pt;
}
int main(int argc, char* argv[]) {
point pt1 = {1, 2};
point pt2 = {2, 1};
point pt3 = add_points(&pt1, &pt2);
printf("pt3(%d, %d)\n", pt3.x, pt3.y);
return 0;
}
结构体字节宽度#
使用 sizeof
可以计算整个结构体占用的字节数。
typedef struct date {
int month;
int day;
} date;
int main(int argc, char *argv[]) {
int size = sizeof(date);
printf("size = %d\n", size); // size = 8
return 0;
}
嵌套数据类型#
数组可以使用结构体作为元素,结构体也可以在内部包含数组成员。
typedef struct date {
int month;
int day;
} date;
data array_of_struct[5];
array_of_struct[0] = (date){3, 1};