一、结构体的定义
语法:使用struct
关键字来定义结构体。基本形式为struct结构体名称{成员列表; };
。例如:
struct Point {
int x;
int y;
};
这里定义了一个名为Point
的结构体,它包含两个整型成员x
和y
,用于表示平面直角坐标系中的一个点。
成员类型:成员可以是基本数据类型(如int
、char
、float
等),也可以是数组类型或者指针类型。例如:
struct String {
char* str;
int length;
};
此结构体String
有一个字符指针str
用于指向字符串,还有一个整型length
用于记录字符串长度。
二、结构体变量的声明与初始化
声明:在定义结构体后,可以声明结构体变量。有两种常见方式。一是分开声明,如struct Point p1;
,这里声明了一个Point
结构体类型的变量p1
。二是在定义结构体时声明,例如:
struct Rectangle {
int width;
int height;
} r1, r2;
这里在定义Rectangle
结构体的同时声明了r1
和r2
两个变量。
初始化:可以在声明变量时初始化。对于简单的结构体,按照成员顺序初始化,例如struct Point p3 = {3, 4};
,将p3
的x
成员初始化为3,y
成员初始化为4。对于较复杂的结构体,如果有字符数组等成员,要注意初始化的格式。例如:
struct Student {
char name[20];
int age;
float score;
} s1 = {"Tom", 20, 90.5};
三、结构体成员的访问
操作符:使用.
(点)操作符来访问结构体变量的成员。例如,对于前面定义的Point p1
,可以通过p1.x
和p1.y
来访问和修改x
和y
成员。如p1.x = 5;
会将p1
的x
成员的值修改为5。
四、结构体作为函数参数
值传递:当结构体作为函数参数进行值传递时,会在函数内部创建一个结构体变量的副本。例如:
这里printPoint
函数接收一个Point
结构体变量p
,在函数内部对p
的操作不会影响到外部调用时传入的结构体变量。
void printPoint(struct Point p) {
cout << "(" << p.x << ", " << p.y << ")" << endl;
}
引用传递:使用引用传递可以避免创建副本,函数内对结构体的修改会影响到外部变量。格式为void func(struct 结构体名称&变量名称)
。例如:
void movePoint(struct Point& p, int dx, int dy) {
p.x += dx;
p.y += dy;
}
指针传递:传递结构体指针也很常见。通过指针访问结构体成员需要使用->
操作符。例如:
void updatePoint(struct Point* p, int newX, int newY) {
p->x = newX;
p->y = newY;
}
五、结构体的嵌套
定义嵌套结构体:结构体可以嵌套其他结构体。例如:
struct ComplexNumber {
struct Point realPart;
struct Point imaginaryPart;
};
这里ComplexNumber
结构体嵌套了两个Point
结构体,用于分别表示复数的实部和虚部。
访问嵌套结构体成员:访问嵌套结构体的成员需要使用多层.
操作符。例如,对于ComplexNumber c;
,可以通过c.realPart.x
来访问实部的x
坐标。
六、结构体与类的关系
相似性:在C++中,结构体和类很相似。结构体默认的成员访问权限是public
,而类默认是private
。结构体也可以有成员函数,例如:
struct Circle {
double radius;
double area() {
return 3.14159 * radius * radius;
}
};
这里Circle
结构体有一个成员函数area
用于计算圆的面积。
七、结构体的内存布局
存储规则:结构体成员在内存中按照定义的顺序存储,不过编译器会考虑对齐问题。例如,对于一个包含char
和int
成员的结构体,char
成员可能会被填充字节,使得int
成员的存储地址是一个能被4整除的地址(在32位系统中),以提高访问效率。
八、结构体数组
定义与访问:可以定义结构体数组。例如struct Student students[10];
定义了一个包含10个Student
结构体的数组。可以通过索引访问数组中的结构体元素,如students[0].age = 18;
用于设置数组中第一个Student
结构体元素的age
成员。