复合数据类型之结构类型
在C语言中,结构类型是一种复合数据类型,它允许用户将不同类型的数据组合成一个单一的数据结构。结构类型为用户提供了自定义数据类型的机制,使得可以将多个相关的数据项组合成一个整体,常用来处理像记录、链表这样的静态和动态数据结构,从而便于管理和操作。
一、结构类型的定义
结构类型的定义使用"struct"关键字,后面跟随结构体的名称和一对大括号。在大括号中,可以定义结构体的成员变量,每个成员变量可以具有不同的数据类型。例如:
struct Student {
char name[50];
int age;
float score;
};
在上面的示例中,定义了一个名为"Student"的结构体,它包含三个成员变量:"name"(一个字符数组,用于存储学生的姓名)、"age"(一个整型变量,用于存储学生的年龄)和"score"(一个浮点型变量,用于存储学生的成绩)。
要创建结构体的实例(即变量),可以使用以下语法:
struct Student stu1;
这将创建一个名为"stu1"的"Student"结构体实例。然后,可以通过点运算符(".")或者
("->")来访问结构体中的成员变量(注意:①"."适合于用结构变量或结构数组元素访问其成员②"->"适合于用结构数组或结构指针访问其成员),例如:
strcpy(stu1.name, "张三");
stu1.age = 18;
stu1.score = 90.5;
上述代码将"stu1"的"name"成员设置为"张三","age"成员设置为18,"score"成员设置为90.5。
二、结构指针的定义
除了定义结构类型外,还可以定义结构体类型的指针,并通过指针来访问结构体的成员。例如:
struct Student *stu_ptr;
stu_ptr = &stu1;
printf("%s的年龄是%d岁,成绩是%.1f分\n", stu_ptr->name, stu_ptr->age, stu_ptr->score);
上述代码首先定义了一个指向"Student"结构体的指针"stu_ptr",然后将"stu1"的地址赋给"stu_ptr"。接下来,使用"->"运算符来通过指针访问结构体的成员,并打印出学生的姓名、年龄和成绩。
三、嵌套结构
在C语言中,结构类型可以嵌套使用,也就是说,一个结构体的成员可以是另一个结构体类型。这种嵌套结构允许我们创建更复杂的数据结构,以表示现实世界中的复杂对象或系统。例如:
#include <stdio.h>
// 定义一个表示地址的结构体
struct Address {
char street[50];
char city[50];
char country[50];
};
// 定义一个表示学生的结构体,其中包含一个地址结构体成员
struct Student {
char name[50];
int age;
float score;
struct Address addr; // 嵌套的地址结构体
};
在这个例子中,"struct Address" 是一个表示地址的结构体,它包含了街道、城市和国家等字段。然后,"struct Student" 是一个表示学生的结构体,它包含了姓名、年龄、成绩以及一个 "struct Address"类型的成员 "addr"。
嵌套结构允许我们构建更加复杂的数据结构,这在处理现实世界中的复杂对象时非常有用。例如,一个公司可能有一个员工结构体,而每个员工都有一个地址结构体作为其成员。这样,我们可以方便地管理和访问员工的所有相关信息。
四、结构类型的赋值
当要为结构体的实例赋值时,可以直接给每个成员赋值,或者使用结构体初始化列表来一次性初始化所有成员。例如:
五、结构数据在函数间的传递
在C语言中,结构数据可以通过多种方式在函数间传递。下面是一些常见的方法:
(1)值传递
当将结构体作为参数传递给函数时,默认情况下是通过值传递的,这意味着函数会接收结构体的一个副本,对副本所做的修改不会影响原始结构体。例如:
#include <stdio.h>
struct Point {
int x;
int y;
};
void printPoint(struct Point p) {
printf("(%d, %d)\n", p.x, p.y);
}
int main() {
struct Point p = {10, 20};
printPoint(p); // 输出: (10, 20)
return 0;
}
(2) 指针传递
如果想要修改原始结构体或避免结构体的复制开销,可以使用指针传递。这样,函数将接收结构体的地址,可以直接操作原始数据。例如:
#include <stdio.h>
struct Point {
int x;
int y;
};
void movePoint(struct Point *p, int dx, int dy) {
p->x += dx;
p->y += dy;
}
int main() {
struct Point p = {10, 20};
movePoint(&p, 5, 10); // 移动点
printf("(%d, %d)\n", p.x, p.y); // 输出: (15, 30)
return 0;
}
(3)返回结构体
函数也可以返回结构体。当函数返回结构体时,实际上返回的是结构体的一个副本。
#include <stdio.h>
struct Point {
int x;
int y;
};
struct Point addPoints(struct Point p1, struct Point p2) {
struct Point result;
result.x = p1.x + p2.x;
result.y = p1.y + p2.y;
return result;
}
int main() {
struct Point p1 = {10, 20};
struct Point p2 = {30, 40};
struct Point p3 = addPoints(p1, p2);
printf("(%d, %d)\n", p3.x, p3.y); // 输出: (40, 60)
return 0;
}
(4) 使用全局变量
结构体也可以作为全局变量,这样它们可以在多个函数之间共享。但这种方法通常不推荐,因为它会破坏封装性并可能导致难以追踪的副作用。
(5)动态内存分配
对于大型结构体或需要多次修改的结构体,可以考虑使用动态内存分配(如"malloc"和"free"函数)。这样,你可以在堆上分配内存,并通过指针在函数间传递这些内存块。
选择哪种方法取决于你的具体需求。在大多数情况下,指针传递是最高效和最灵活的方式,因为它避免了不必要的数据复制,并允许函数直接操作原始数据。然而,这也增加了编程的复杂性,因为需要正确地管理指针和内存。
下面我们利用上述知识实现简单通讯录:
我们利用Input()用来输入通讯录的数据,
display()用来输出通讯录的数据,main()函数向input()和 Display()函数传递结构数,用于函数的数据传递。
程序中main()函数调用Input()函数时,形参和实参都是结构数组名,此时,形参将 自动转换成结构指针;main()函数调用Display()函数时,实参是结构数组名,形参是结构指针,两次调用的传递机制是相同的。
同样的,我们还可以实现简单的成绩统计:
用score数组存3门课成绩,并将score作为结构的一个成员被传递,此时用作计算总分的函数add()只要用指针接收score的首地址即可。
结构类型在C语言中非常有用,它可以用于表示复杂的数据结构,例如记录、链表等。通过定义结构类型,可以方便地组织和操作多个相关的数据项,提高代码的可读性和可维护性。
好啦,今天的分享就到这里了。再次声明:作者水平有限,如有失偏颇,还请各位不吝赐教!