结构体与联合体练习
18. 结构体和联合体练习题
1. 定义和初始化结构体
题目描述:
编写一个 C 程序,定义一个名为Person的结构体,包含成员name(字符串)、age(整数)和height(浮点数)。然后,初始化一个Person类型的变量,并输出其成员的值。
解题思路:
首先,定义一个结构体Person,包含所需的成员。然后,在主函数中声明一个Person变量,并使用初始化列表为其成员赋值。最后,使用printf函数输出各成员的值。
详细代码:
#include <stdio.h>
// 定义结构体Person
struct Person {
char name[50];
int age;
float height;
};
int main() {
// 初始化结构体变量
struct Person person = {"Alice", 30, 5.6f};
// 输出结构体成员的值
printf("姓名: %s\n", person.name);
printf("年龄: %d\n", person.age);
printf("身高: %.1f 英尺\n", person.height);
return 0;
}
代码注释:
struct Person:定义一个结构体类型Person,包含name、age和height三个成员。char name[50];:声明一个字符数组用于存储姓名,最大长度为 49 个字符(留出一个字符用于字符串结束符\0)。struct Person person = {"Alice", 30, 5.6f};:使用初始化列表为结构体变量person的成员赋值。printf:分别输出结构体成员的值。
2. 访问结构体成员
题目描述:
编写一个 C 程序,定义一个结构体Rectangle,包含成员length和width(均为浮点数)。输入一个Rectangle的length和width,计算并输出其面积和周长。
解题思路:
定义结构体Rectangle,包含length和width。在主函数中声明一个Rectangle变量,使用scanf函数读取用户输入的长度和宽度。然后,计算面积(length × width)和周长(2 × (length + width)),并输出结果。
详细代码:
#include <stdio.h>
// 定义结构体Rectangle
struct Rectangle {
float length;
float width;
};
int main() {
struct Rectangle rect;
float area, perimeter;
// 输入长度和宽度
printf("请输入矩形的长度: ");
scanf("%f", &rect.length);
printf("请输入矩形的宽度: ");
scanf("%f", &rect.width);
// 计算面积和周长
area = rect.length * rect.width;
perimeter = 2 * (rect.length + rect.width);
// 输出结果
printf("矩形的面积是: %.2f\n", area);
printf("矩形的周长是: %.2f\n", perimeter);
return 0;
}
代码注释:
struct Rectangle:定义一个结构体类型Rectangle,包含length和width两个浮点数成员。scanf:读取用户输入的长度和宽度,并存储到结构体变量rect的相应成员中。area和perimeter:计算并存储面积和周长。printf:输出计算结果。
3. 嵌套结构体
题目描述:
编写一个 C 程序,定义两个结构体Date和Employee。Date包含成员day、month和year。Employee包含成员name(字符串)、id(整数)和birthdate(类型为Date的结构体)。输入一个员工的详细信息,并输出。
解题思路:
首先,定义结构体Date和Employee,其中Employee包含一个Date类型的成员birthdate。在主函数中声明一个Employee变量,使用嵌套的scanf函数读取员工的姓名、ID 和生日。最后,使用printf函数输出员工的详细信息。
详细代码:
#include <stdio.h>
// 定义结构体Date
struct Date {
int day;
int month;
int year;
};
// 定义结构体Employee,包含Date类型的成员birthdate
struct Employee {
char name[50];
int id;
struct Date birthdate;
};
int main() {
struct Employee emp;
// 输入员工姓名
printf("请输入员工姓名: ");
fgets(emp.name, sizeof(emp.name), stdin);
// 去除换行符
int i = 0;
while(emp.name[i] != '\0') {
if(emp.name[i] == '\n') {
emp.name[i] = '\0';
break;
}
i++;
}
// 输入员工ID
printf("请输入员工ID: ");
scanf("%d", &emp.id);
// 输入员工生日
printf("请输入员工生日(格式: 日 月 年): ");
scanf("%d %d %d", &emp.birthdate.day, &emp.birthdate.month, &emp.birthdate.year);
// 输出员工信息
printf("\n--- 员工信息 ---\n");
printf("姓名: %s\n", emp.name);
printf("ID: %d\n", emp.id);
printf("生日: %02d/%02d/%04d\n", emp.birthdate.day, emp.birthdate.month, emp.birthdate.year);
return 0;
}
代码注释:
struct Date和struct Employee:定义两个结构体类型,Employee中嵌套了Date结构体。fgets(emp.name, sizeof(emp.name), stdin);:读取员工姓名,包括空格。- 去除
fgets读取的换行符:遍历字符串,遇到\n则替换为\0。 scanf:读取员工 ID 和生日信息。printf:输出员工的详细信息,包括姓名、ID 和生日。
4. 数组中的结构体
题目描述:
编写一个 C 程序,定义一个结构体Student,包含成员name(字符串)、roll(整数)和marks(浮点数)。创建一个包含 5 个Student的数组,输入每个学生的信息,并计算并输出所有学生的平均分。
解题思路:
定义结构体Student,包含所需成员。声明一个包含 5 个Student的数组。使用for循环读取每个学生的信息,并累加他们的分数。最后,计算平均分并输出。
详细代码:
#include <stdio.h>
// 定义结构体Student
struct Student {
char name[50];
int roll;
float marks;
};
int main() {
struct Student students[5];
float totalMarks = 0.0, average;
// 输入5个学生的信息
for(int i = 0; i < 5; i++) {
printf("请输入第 %d 个学生的姓名: ", i + 1);
fgets(students[i].name, sizeof(students[i].name), stdin);
// 去除换行符
int j = 0;
while(students[i].name[j] != '\0') {
if(students[i].name[j] == '\n') {
students[i].name[j] = '\0';
break;
}
j++;
}
printf("请输入第 %d 个学生的学号: ", i + 1);
scanf("%d", &students[i].roll);
printf("请输入第 %d 个学生的成绩: ", i + 1);
scanf("%f", &students[i].marks);
getchar(); // 清除输入缓冲区的换行符
totalMarks += students[i].marks;
}
// 计算平均分
average = totalMarks / 5;
// 输出平均分
printf("\n所有学生的平均分是: %.2f\n", average);
return 0;
}
代码注释:
struct Student:定义一个结构体类型Student,包含name、roll和marks三个成员。struct Student students[5];:声明一个包含 5 个Student的数组。fgets和去除换行符:读取学生姓名并去除末尾的换行符。scanf:读取学生的学号和成绩。getchar();:清除输入缓冲区的换行符,避免影响下一个fgets的读取。totalMarks += students[i].marks;:累加每个学生的成绩。average = totalMarks / 5;:计算平均分。printf:输出平均分。
5. 结构体与函数
题目描述:
编写一个 C 程序,定义一个结构体Point,包含成员x和y(均为浮点数)。创建一个函数distance,接受两个Point类型的参数,计算并返回两点之间的距离。在主函数中输入两个点的坐标,调用distance函数并输出结果。
解题思路:
定义结构体Point,包含x和y成员。创建函数distance,计算两点之间的欧几里得距离。主函数中读取两个点的坐标,调用distance函数,并输出计算结果。
详细代码:
#include <stdio.h>
#include <math.h>
// 定义结构体Point
struct Point {
float x;
float y;
};
// 函数声明
float distance(struct Point p1, struct Point p2);
int main() {
struct Point point1, point2;
float dist;
// 输入第一个点的坐标
printf("请输入第一个点的x坐标: ");
scanf("%f", &point1.x);
printf("请输入第一个点的y坐标: ");
scanf("%f", &point1.y);
// 输入第二个点的坐标
printf("请输入第二个点的x坐标: ");
scanf("%f", &point2.x);
printf("请输入第二个点的y坐标: ");
scanf("%f", &point2.y);
// 计算距离
dist = distance(point1, point2);
// 输出结果
printf("两点之间的距离是: %.2f\n", dist);
return 0;
}
// 定义distance函数
float distance(struct Point p1, struct Point p2) {
float dx = p2.x - p1.x;
float dy = p2.y - p1.y;
return sqrt(dx * dx + dy * dy);
}
代码注释:
struct Point:定义一个结构体类型Point,包含x和y两个浮点数成员。float distance(struct Point p1, struct Point p2);:声明一个函数distance,接受两个Point参数,返回浮点数。scanf:读取两个点的x和y坐标。dist = distance(point1, point2);:调用distance函数计算两点之间的距离。sqrt(dx * dx + dy * dy);:计算欧几里得距离。
6. 结构体指针
题目描述:
编写一个 C 程序,定义一个结构体Book,包含成员title(字符串)、author(字符串)和price(浮点数)。创建一个Book类型的变量,通过指针访问并修改其成员的值,最后输出修改后的信息。
解题思路:
定义结构体Book,包含所需成员。在主函数中声明一个Book变量,并使用指针指向它。通过指针修改结构体成员的值,然后输出修改后的信息。
详细代码:
#include <stdio.h>
// 定义结构体Book
struct Book {
char title[100];
char author[50];
float price;
};
int main() {
struct Book myBook;
struct Book *ptr = &myBook;
// 通过指针输入书籍信息
printf("请输入书名: ");
fgets(ptr->title, sizeof(ptr->title), stdin);
// 去除换行符
int i = 0;
while(ptr->title[i] != '\0') {
if(ptr->title[i] == '\n') {
ptr->title[i] = '\0';
break;
}
i++;
}
printf("请输入作者: ");
fgets(ptr->author, sizeof(ptr->author), stdin);
// 去除换行符
int j = 0;
while(ptr->author[j] != '\0') {
if(ptr->author[j] == '\n') {
ptr->author[j] = '\0';
break;
}
j++;
}
printf("请输入价格: ");
scanf("%f", &ptr->price);
// 修改价格
printf("请输入新的价格: ");
scanf("%f", &ptr->price);
// 输出修改后的书籍信息
printf("\n--- 修改后的书籍信息 ---\n");
printf("书名: %s\n", ptr->title);
printf("作者: %s\n", ptr->author);
printf("价格: %.2f\n", ptr->price);
return 0;
}
代码注释:
struct Book:定义一个结构体类型Book,包含title、author和price三个成员。struct Book *ptr = &myBook;:声明一个指向Book结构体的指针ptr,并指向变量myBook。ptr->title和ptr->author:通过指针访问和修改结构体成员。fgets和去除换行符:读取字符串输入并去除末尾的换行符。scanf:读取和修改价格。printf:输出修改后的书籍信息。
7. 动态内存分配与结构体
题目描述:
编写一个 C 程序,定义一个结构体Student,包含成员name(字符串)和score(浮点数)。动态分配内存以存储一个Student,输入其信息,输出后释放内存。
解题思路:
定义结构体Student,包含name和score成员。在主函数中使用malloc动态分配内存为一个Student结构体。通过指针访问和修改成员的值,最后使用free释放内存。
详细代码:
#include <stdio.h>
#include <stdlib.h>
// 定义结构体Student
struct Student {
char name[50];
float score;
};
int main() {
// 动态分配内存
struct Student *ptr = (struct Student *)malloc(sizeof(struct Student));
if(ptr == NULL) {
printf("内存分配失败。\n");
return 1;
}
// 输入学生信息
printf("请输入学生姓名: ");
fgets(ptr->name, sizeof(ptr->name), stdin);
// 去除换行符
int i = 0;
while(ptr->name[i] != '\0') {
if(ptr->name[i] == '\n') {
ptr->name[i] = '\0';
break;
}
i++;
}
printf("请输入学生成绩: ");
scanf("%f", &ptr->score);
// 输出学生信息
printf("\n--- 学生信息 ---\n");
printf("姓名: %s\n", ptr->name);
printf("成绩: %.2f\n", ptr->score);
// 释放内存
free(ptr);
return 0;
}
代码注释:
struct Student:定义一个结构体类型Student,包含name和score两个成员。malloc:动态分配内存来存储一个Student结构体。- 检查内存分配是否成功:如果
malloc返回NULL,则输出错误信息并退出程序。 fgets和去除换行符:读取学生姓名并去除末尾的换行符。scanf:读取学生成绩。printf:输出学生信息。free(ptr);:释放动态分配的内存。
8. 结构体比较
题目描述:
编写一个 C 程序,定义一个结构体Point,包含成员x和y(均为整数)。输入两个Point,比较它们是否相同(即x和y都相等),并输出结果。
解题思路:
定义结构体Point,包含x和y两个整数成员。在主函数中声明两个Point变量,读取其坐标值。通过比较两个结构体的x和y成员,判断它们是否相同,并输出相应的结果。
详细代码:
#include <stdio.h>
// 定义结构体Point
struct Point {
int x;
int y;
};
int main() {
struct Point p1, p2;
// 输入第一个点的坐标
printf("请输入第一个点的x坐标: ");
scanf("%d", &p1.x);
printf("请输入第一个点的y坐标: ");
scanf("%d", &p1.y);
// 输入第二个点的坐标
printf("请输入第二个点的x坐标: ");
scanf("%d", &p2.x);
printf("请输入第二个点的y坐标: ");
scanf("%d", &p2.y);
// 比较两个点
if(p1.x == p2.x && p1.y == p2.y) {
printf("两个点是相同的。\n");
} else {
printf("两个点是不相同的。\n");
}
return 0;
}
代码注释:
struct Point:定义一个结构体类型Point,包含x和y两个整数成员。scanf:读取两个点的x和y坐标。if(p1.x == p2.x && p1.y == p2.y):比较两个点的坐标是否相等。printf:输出比较结果。
9. 联合体的定义和使用
题目描述:
编写一个 C 程序,定义一个联合体Data,包含成员i(整数)、f(浮点数)和str(字符串)。输入一个Data类型的变量的类型标识(例如i、f或str),然后输入相应类型的值,并输出存储在联合体中的值。
解题思路:
定义联合体Data,包含i、f和str三个成员。在主函数中声明一个Data变量,读取用户输入的类型标识,然后根据类型输入相应的值。由于联合体的所有成员共用同一块内存,最后根据类型标识输出存储的值。
详细代码:
#include <stdio.h>
#include <string.h>
// 定义联合体Data
union Data {
int i;
float f;
char str[20];
};
int main() {
union Data data;
char type[10];
// 输入类型标识
printf("请输入数据类型(i, f, str): ");
scanf("%s", type);
// 根据类型输入相应的值
if(strcmp(type, "i") == 0) {
printf("请输入整数: ");
scanf("%d", &data.i);
printf("存储的整数是: %d\n", data.i);
}
else if(strcmp(type, "f") == 0) {
printf("请输入浮点数: ");
scanf("%f", &data.f);
printf("存储的浮点数是: %.2f\n", data.f);
}
else if(strcmp(type, "str") == 0) {
printf("请输入字符串: ");
scanf("%s", data.str);
printf("存储的字符串是: %s\n", data.str);
}
else {
printf("无效的类型标识。\n");
}
return 0;
}
代码注释:
union Data:定义一个联合体类型Data,包含i(整数)、f(浮点数)和str(字符串)三个成员。char type[10];:声明一个字符数组用于存储用户输入的类型标识。strcmp:比较用户输入的类型标识与"i"、"f"和"str"是否匹配。- 根据类型输入相应的值,并输出存储在联合体中的值。
- 注意:由于联合体成员共用同一块内存,输入一个成员后,之前输入的其他成员的值将被覆盖。
10. 结构体与联合体的区别
题目描述:
编写一个 C 程序,定义一个结构体ExampleStruct和一个联合体ExampleUnion,都包含成员a(整数)、b(浮点数)和c(字符串)。输入并设置a、b和c的值,分别展示结构体和联合体的内存占用和成员值的变化。
解题思路:
定义结构体和联合体,包含相同的成员。在主函数中声明结构体和联合体变量,分别为其成员赋值。然后,使用sizeof运算符显示它们的内存占用,并观察在为联合体赋值多个成员后,前面赋值的成员是否被覆盖。
详细代码:
#include <stdio.h>
#include <string.h>
// 定义结构体ExampleStruct
struct ExampleStruct {
int a;
float b;
char c[20];
};
// 定义联合体ExampleUnion
union ExampleUnion {
int a;
float b;
char c[20];
};
int main() {
struct ExampleStruct s;
union ExampleUnion u;
// 设置结构体成员
s.a = 10;
s.b = 20.5f;
strcpy(s.c, "Hello Struct");
// 设置联合体成员
u.a = 30;
u.b = 40.5f;
strcpy(u.c, "Hello Union");
// 输出内存占用
printf("结构体ExampleStruct的大小: %lu 字节\n", sizeof(s));
printf("联合体ExampleUnion的大小: %lu 字节\n", sizeof(u));
// 输出成员值
printf("\n--- 结构体成员 ---\n");
printf("a = %d\n", s.a);
printf("b = %.2f\n", s.b);
printf("c = %s\n", s.c);
printf("\n--- 联合体成员 ---\n");
printf("a = %d\n", u.a);
printf("b = %.2f\n", u.b);
printf("c = %s\n", u.c);
return 0;
}
代码注释:
struct ExampleStruct和union ExampleUnion:定义结构体和联合体,包含相同的成员a、b和c。strcpy:将字符串复制到结构体和联合体的c成员中。sizeof:计算结构体和联合体的内存占用。- 输出结构体成员和联合体成员的值,观察联合体成员赋值后前面成员的值是否被覆盖。
运行结果示例:
结构体ExampleStruct的大小: 28 字节
联合体ExampleUnion的大小: 20 字节
--- 结构体成员 ---
a = 10
b = 20.50
c = Hello Struct
--- 联合体成员 ---
a = 1111633920
b = 40.50
c = Hello Union
解释:
- 结构体
ExampleStruct的大小是所有成员大小之和(通常更大)。 - 联合体
ExampleUnion的大小是其最大成员的大小(通常较小)。 - 由于联合体所有成员共享同一块内存,最后赋值的
c成员覆盖了之前的a和b成员的值。
11. 嵌套联合体和结构体
题目描述:
编写一个 C 程序,定义一个结构体Employee,包含成员id(整数)、name(字符串)和一个联合体Contact,该联合体包含phone(字符串)和email(字符串)。输入一个员工的信息,包括联系方式(电话或邮箱),并输出。
解题思路:
定义结构体Employee,其中嵌套了一个联合体Contact。在主函数中,声明一个Employee变量,读取员工的 ID、姓名和联系方式。由于联合体只能存储一个联系信息,用户需要选择是输入电话还是邮箱。最后,输出员工的信息。
详细代码:
#include <stdio.h>
#include <string.h>
// 定义联合体Contact
union Contact {
char phone[15];
char email[50];
};
// 定义结构体Employee,包含联合体Contact
struct Employee {
int id;
char name[50];
union Contact contact;
char contactType; // 'p'表示电话,'e'表示邮箱
};
int main() {
struct Employee emp;
// 输入员工ID
printf("请输入员工ID: ");
scanf("%d", &emp.id);
getchar(); // 清除输入缓冲区的换行符
// 输入员工姓名
printf("请输入员工姓名: ");
fgets(emp.name, sizeof(emp.name), stdin);
// 去除换行符
int i = 0;
while(emp.name[i] != '\0') {
if(emp.name[i] == '\n') {
emp.name[i] = '\0';
break;
}
i++;
}
// 输入联系方式类型
printf("请输入联系方式类型(p-电话, e-邮箱): ");
scanf(" %c", &emp.contactType);
getchar(); // 清除输入缓冲区的换行符
// 根据类型输入联系方式
if(emp.contactType == 'p') {
printf("请输入电话号码: ");
fgets(emp.contact.phone, sizeof(emp.contact.phone), stdin);
// 去除换行符
int j = 0;
while(emp.contact.phone[j] != '\0') {
if(emp.contact.phone[j] == '\n') {
emp.contact.phone[j] = '\0';
break;
}
j++;
}
}
else if(emp.contactType == 'e') {
printf("请输入邮箱地址: ");
fgets(emp.contact.email, sizeof(emp.contact.email), stdin);
// 去除换行符
int j = 0;
while(emp.contact.email[j] != '\0') {
if(emp.contact.email[j] == '\n') {
emp.contact.email[j] = '\0';
break;
}
j++;
}
}
else {
printf("无效的联系方式类型。\n");
return 1;
}
// 输出员工信息
printf("\n--- 员工信息 ---\n");
printf("ID: %d\n", emp.id);
printf("姓名: %s\n", emp.name);
if(emp.contactType == 'p') {
printf("电话号码: %s\n", emp.contact.phone);
}
else {
printf("邮箱地址: %s\n", emp.contact.email);
}
return 0;
}
代码注释:
union Contact:定义一个联合体Contact,包含phone和email两个字符串成员。struct Employee:定义一个结构体Employee,包含id、name、contact(联合体)和contactType(字符,表示联系方式类型)。getchar();:在读取字符或字符串后,清除输入缓冲区的换行符,避免影响后续的fgets读取。- 根据
contactType,选择输入电话或邮箱,并存储到联合体的相应成员中。 - 最后,输出员工的所有信息,包括根据类型选择输出的联系方式。
12. 联合体数组
题目描述:
编写一个 C 程序,定义一个联合体Data,包含成员i(整数)、f(浮点数)和str(字符串)。创建一个包含 5 个Data类型的数组,输入每个元素的类型和相应的值,最后输出所有数组元素的值。
解题思路:
定义联合体Data,包含i、f和str三个成员。在主函数中声明一个包含 5 个Data的数组。对于每个数组元素,读取其类型标识(i、f或str),然后根据类型输入相应的值。最后,遍历数组并根据类型标识输出存储的值。
详细代码:
#include <stdio.h>
#include <string.h>
// 定义联合体Data
union Data {
int i;
float f;
char str[20];
};
// 定义结构体用于存储Data和类型标识
struct DataWithType {
union Data data;
char type; // 'i', 'f', 's'分别表示整数、浮点数和字符串
};
int main() {
struct DataWithType array[5];
// 输入数组元素
for(int idx = 0; idx < 5; idx++) {
printf("请输入第 %d 个元素的类型(i-整数, f-浮点数, s-字符串): ", idx + 1);
scanf(" %c", &array[idx].type);
getchar(); // 清除输入缓冲区的换行符
if(array[idx].type == 'i') {
printf("请输入整数值: ");
scanf("%d", &array[idx].data.i);
getchar();
}
else if(array[idx].type == 'f') {
printf("请输入浮点数值: ");
scanf("%f", &array[idx].data.f);
getchar();
}
else if(array[idx].type == 's') {
printf("请输入字符串值: ");
fgets(array[idx].data.str, sizeof(array[idx].data.str), stdin);
// 去除换行符
int i = 0;
while(array[idx].data.str[i] != '\0') {
if(array[idx].data.str[i] == '\n') {
array[idx].data.str[i] = '\0';
break;
}
i++;
}
}
else {
printf("无效的类型标识。\n");
idx--; // 重新输入当前元素
}
}
// 输出数组元素
printf("\n--- 数组元素 ---\n");
for(int idx = 0; idx < 5; idx++) {
printf("第 %d 个元素: ", idx + 1);
if(array[idx].type == 'i') {
printf("整数 = %d\n", array[idx].data.i);
}
else if(array[idx].type == 'f') {
printf("浮点数 = %.2f\n", array[idx].data.f);
}
else if(array[idx].type == 's') {
printf("字符串 = %s\n", array[idx].data.str);
}
}
return 0;
}
代码注释:
union Data:定义一个联合体Data,包含i、f和str三个成员。struct DataWithType:定义一个结构体,用于存储Data和类型标识type。struct DataWithType array[5];:声明一个包含 5 个DataWithType的数组。scanf(" %c", &array[idx].type);:读取每个数组元素的类型标识。- 根据类型标识,读取相应的值并存储在联合体的对应成员中。
fgets和去除换行符:读取字符串输入并去除末尾的换行符。printf:输出数组中的所有元素,根据类型标识选择输出的成员。
13. 结构体中的指针
题目描述:
编写一个 C 程序,定义一个结构体Node,包含成员data(整数)和next(指向Node的指针)。创建一个简单的链表,包含三个节点,输入每个节点的数据,并遍历链表输出每个节点的值。
解题思路:
定义结构体Node,包含data和next成员。动态分配三个节点,链接它们形成链表。读取每个节点的数据,通过遍历链表输出节点的值。最后,释放分配的内存。
详细代码:
#include <stdio.h>
#include <stdlib.h>
// 定义结构体Node
struct Node {
int data;
struct Node *next;
};
int main() {
struct Node *head, *second, *third;
// 动态分配节点
head = (struct Node *)malloc(sizeof(struct Node));
second = (struct Node *)malloc(sizeof(struct Node));
third = (struct Node *)malloc(sizeof(struct Node));
if(head == NULL || second == NULL || third == NULL) {
printf("内存分配失败。\n");
return 1;
}
// 输入第一个节点的数据
printf("请输入第一个节点的数据: ");
scanf("%d", &head->data);
head->next = second;
// 输入第二个节点的数据
printf("请输入第二个节点的数据: ");
scanf("%d", &second->data);
second->next = third;
// 输入第三个节点的数据
printf("请输入第三个节点的数据: ");
scanf("%d", &third->data);
third->next = NULL;
// 遍历链表并输出节点数据
printf("\n链表中的节点数据:\n");
struct Node *current = head;
while(current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
// 释放内存
free(head);
free(second);
free(third);
return 0;
}
代码注释:
struct Node:定义一个结构体类型Node,包含data(整数)和next(指向下一个Node的指针)。malloc:动态分配内存为三个节点。- 检查内存分配是否成功:如果任何一个
malloc返回NULL,则输出错误信息并退出程序。 head->next = second;和second->next = third;:链接节点,形成链表。third->next = NULL;:最后一个节点的next指针指向NULL,表示链表结束。while(current != NULL):遍历链表,输出每个节点的数据。free:释放动态分配的内存,避免内存泄漏。
14. 动态内存分配与链表
题目描述:
编写一个 C 程序,定义一个结构体Node,包含成员data(整数)和next(指向Node的指针)。动态创建一个链表,允许用户输入节点的值,直到用户输入-1 为止。然后,遍历链表并输出所有节点的值。
解题思路:
定义结构体Node,包含data和next成员。在主函数中,动态创建链表节点,根据用户输入的值构建链表。输入-1 时停止创建节点。最后,遍历链表并输出节点的数据。释放所有分配的内存。
详细代码:
#include <stdio.h>
#include <stdlib.h>
// 定义结构体Node
struct Node {
int data;
struct Node *next;
};
int main() {
struct Node *head = NULL, *temp = NULL, *current = NULL;
int value;
// 输入节点数据,-1表示结束
printf("请输入节点的数据(-1结束):\n");
while(1) {
printf("数据: ");
scanf("%d", &value);
if(value == -1)
break;
// 创建新节点
temp = (struct Node *)malloc(sizeof(struct Node));
if(temp == NULL) {
printf("内存分配失败。\n");
return 1;
}
temp->data = value;
temp->next = NULL;
// 如果链表为空,设置为头节点
if(head == NULL) {
head = temp;
current = head;
}
else {
current->next = temp;
current = current->next;
}
}
// 遍历链表并输出数据
printf("\n链表中的节点数据:\n");
current = head;
while(current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
// 释放内存
current = head;
struct Node *nextNode;
while(current != NULL) {
nextNode = current->next;
free(current);
current = nextNode;
}
return 0;
}
代码注释:
struct Node:定义一个结构体类型Node,包含data(整数)和next(指向下一个Node的指针)。head、temp和current:指向链表的头节点、临时节点和当前节点的指针。while(1):无限循环,直到用户输入-1。malloc:动态分配内存为新节点。if(head == NULL):如果链表为空,设置新节点为头节点。current->next = temp; current = current->next;:将新节点添加到链表末尾,并更新当前节点指针。- 遍历链表,输出每个节点的数据。
- 释放链表中所有节点的内存,防止内存泄漏。
15. 使用动态内存实现双向链表
题目描述:
编写一个 C 程序,定义一个结构体DNode,包含成员data(整数)、prev和next(分别指向前一个和后一个DNode的指针)。动态创建一个双向链表,输入节点的值,建立链表,并遍历链表从头到尾和从尾到头输出节点的值。
解题思路:
定义结构体DNode,包含data、prev和next成员。在主函数中,动态创建节点并链接形成双向链表。输入节点值,直到用户输入-1 为止。最后,遍历链表从头到尾输出,然后从尾到头输出。释放所有分配的内存。
详细代码:
#include <stdio.h>
#include <stdlib.h>
// 定义结构体DNode
struct DNode {
int data;
struct DNode *prev;
struct DNode *next;
};
int main() {
struct DNode *head = NULL, *temp = NULL, *current = NULL, *tail = NULL;
int value;
// 输入节点数据,-1表示结束
printf("请输入节点的数据(-1结束):\n");
while(1) {
printf("数据: ");
scanf("%d", &value);
if(value == -1)
break;
// 创建新节点
temp = (struct DNode *)malloc(sizeof(struct DNode));
if(temp == NULL) {
printf("内存分配失败。\n");
return 1;
}
temp->data = value;
temp->prev = NULL;
temp->next = NULL;
// 如果链表为空,设置为头节点
if(head == NULL) {
head = temp;
current = head;
tail = head;
}
else {
current->next = temp;
temp->prev = current;
current = temp;
tail = current;
}
}
// 从头到尾遍历链表
printf("\n从头到尾遍历链表:\n");
current = head;
while(current != NULL) {
printf("%d <-> ", current->data);
current = current->next;
}
printf("NULL\n");
// 从尾到头遍历链表
printf("从尾到头遍历链表:\n");
current = tail;
while(current != NULL) {
printf("%d <-> ", current->data);
current = current->prev;
}
printf("NULL\n");
// 释放内存
current = head;
struct DNode *nextNode;
while(current != NULL) {
nextNode = current->next;
free(current);
current = nextNode;
}
return 0;
}
代码注释:
struct DNode:定义一个结构体类型DNode,包含data(整数)、prev和next(指向前后节点的指针)。head、temp、current和tail:分别指向链表的头节点、临时节点、当前节点和尾节点的指针。malloc:动态分配内存为新节点。if(head == NULL):如果链表为空,设置新节点为头节点,并初始化tail。current->next = temp; temp->prev = current;:链接新节点到链表末尾,并更新current和tail指针。- 遍历链表从头到尾和从尾到头输出节点的数据。
- 释放链表中所有节点的内存,防止内存泄漏。
16. 使用联合体节省内存
题目描述:
编写一个 C 程序,定义一个联合体Value,包含成员intVal(整数)、floatVal(浮点数)和charVal(字符)。创建一个包含 10 个Value类型的数组,输入每个元素的类型和相应的值,展示联合体如何节省内存。
解题思路:
定义联合体Value,包含intVal、floatVal和charVal三个成员。声明一个包含 10 个Value的数组。对于每个数组元素,读取类型标识(i、f或c),并输入相应的值。通过sizeof运算符展示结构体和联合体的内存占用差异。
详细代码:
#include <stdio.h>
#include <string.h>
// 定义联合体Value
union Value {
int intVal;
float floatVal;
char charVal;
};
// 定义结构体ValueStruct用于比较
struct ValueStruct {
int intVal;
float floatVal;
char charVal;
};
int main() {
union Value array[10];
struct ValueStruct sArray[10];
char type;
// 输入数组元素
for(int i = 0; i < 10; i++) {
printf("请输入第 %d 个元素的类型(i-整数, f-浮点数, c-字符): ", i + 1);
scanf(" %c", &type);
getchar(); // 清除输入缓冲区的换行符
if(type == 'i') {
printf("请输入整数值: ");
scanf("%d", &array[i].intVal);
getchar();
}
else if(type == 'f') {
printf("请输入浮点数值: ");
scanf("%f", &array[i].floatVal);
getchar();
}
else if(type == 'c') {
printf("请输入字符值: ");
scanf("%c", &array[i].charVal);
getchar();
}
else {
printf("无效的类型标识。\n");
i--; // 重新输入当前元素
}
}
// 输出内存占用
printf("\n内存占用比较:\n");
printf("联合体Value的大小: %lu 字节\n", sizeof(union Value));
printf("结构体ValueStruct的大小: %lu 字节\n", sizeof(struct ValueStruct));
// 输出数组元素
printf("\n联合体数组中的元素:\n");
for(int i = 0; i < 10; i++) {
printf("第 %d 个元素: ", i + 1);
// 根据最后输入的类型显示值
if(type == 'i') {
printf("整数 = %d\n", array[i].intVal);
}
else if(type == 'f') {
printf("浮点数 = %.2f\n", array[i].floatVal);
}
else if(type == 'c') {
printf("字符 = %c\n", array[i].charVal);
}
}
return 0;
}
代码注释:
union Value:定义一个联合体类型Value,包含intVal、floatVal和charVal三个成员。struct ValueStruct:定义一个结构体类型,用于比较结构体和联合体的内存占用。union Value array[10];和struct ValueStruct sArray[10];:声明分别包含 10 个联合体和结构体的数组。scanf(" %c", &type);:读取每个数组元素的类型标识。- 根据类型标识,输入相应的值并存储到联合体的对应成员中。
sizeof运算符:显示联合体和结构体的内存占用差异。- 注意:由于联合体的成员共享同一块内存,最后输入的类型决定了当前存储的值。
17. 结构体作为函数参数
题目描述:
编写一个 C 程序,定义一个结构体Circle,包含成员radius(浮点数)。创建一个函数area,接受一个Circle类型的参数,计算并返回圆的面积。在主函数中输入圆的半径,调用area函数并输出结果。
解题思路:
定义结构体Circle,包含radius成员。创建函数area,接受一个Circle参数,计算面积(π × radius²)。主函数中读取半径值,创建一个Circle变量,调用area函数并输出结果。
详细代码:
#include <stdio.h>
// 定义结构体Circle
struct Circle {
float radius;
};
// 函数声明
float area(struct Circle c);
int main() {
struct Circle myCircle;
float circleArea;
// 输入圆的半径
printf("请输入圆的半径: ");
scanf("%f", &myCircle.radius);
// 计算面积
circleArea = area(myCircle);
// 输出结果
printf("圆的面积是: %.2f\n", circleArea);
return 0;
}
// 定义area函数
float area(struct Circle c) {
return 3.14159f * c.radius * c.radius;
}
代码注释:
struct Circle:定义一个结构体类型Circle,包含radius成员。float area(struct Circle c);:声明一个函数area,接受一个Circle参数,返回浮点数。scanf:读取圆的半径并存储到结构体变量myCircle中。area(myCircle);:调用area函数计算面积。3.14159f * c.radius * c.radius:计算圆的面积,使用浮点数常量 π。
18. 结构体指针作为函数参数
题目描述:
编写一个 C 程序,定义一个结构体Rectangle,包含成员length和width(均为浮点数)。创建一个函数calculateArea,接受一个指向Rectangle的指针参数,计算并返回矩形的面积。在主函数中输入矩形的长度和宽度,调用calculateArea函数并输出结果。
解题思路:
定义结构体Rectangle,包含length和width成员。创建函数calculateArea,接受一个指向Rectangle的指针参数,计算面积(length × width)。主函数中读取长度和宽度,创建一个Rectangle变量,调用calculateArea函数并输出结果。
详细代码:
#include <stdio.h>
// 定义结构体Rectangle
struct Rectangle {
float length;
float width;
};
// 函数声明
float calculateArea(struct Rectangle *rect);
int main() {
struct Rectangle rect;
float area;
// 输入矩形的长度和宽度
printf("请输入矩形的长度: ");
scanf("%f", &rect.length);
printf("请输入矩形的宽度: ");
scanf("%f", &rect.width);
// 计算面积
area = calculateArea(&rect);
// 输出结果
printf("矩形的面积是: %.2f\n", area);
return 0;
}
// 定义calculateArea函数
float calculateArea(struct Rectangle *rect) {
return rect->length * rect->width;
}
代码注释:
struct Rectangle:定义一个结构体类型Rectangle,包含length和width两个浮点数成员。float calculateArea(struct Rectangle *rect);:声明一个函数calculateArea,接受一个指向Rectangle的指针参数,返回浮点数。scanf:读取矩形的长度和宽度并存储到结构体变量rect中。calculateArea(&rect);:调用calculateArea函数,传递结构体变量的地址。rect->length * rect->width:通过指针访问结构体成员,计算面积。
19. 比较两个结构体是否相同
题目描述:
编写一个 C 程序,定义一个结构体Point,包含成员x和y(均为整数)。输入两个Point,比较它们是否相同(即x和y都相等),并输出结果。
解题思路:
定义结构体Point,包含x和y两个整数成员。在主函数中声明两个Point变量,读取其坐标值。通过比较两个结构体的x和y成员,判断它们是否相同,并输出相应的结果。
详细代码:
#include <stdio.h>
// 定义结构体Point
struct Point {
int x;
int y;
};
int main() {
struct Point p1, p2;
// 输入第一个点的坐标
printf("请输入第一个点的x坐标: ");
scanf("%d", &p1.x);
printf("请输入第一个点的y坐标: ");
scanf("%d", &p1.y);
// 输入第二个点的坐标
printf("请输入第二个点的x坐标: ");
scanf("%d", &p2.x);
printf("请输入第二个点的y坐标: ");
scanf("%d", &p2.y);
// 比较两个点
if(p1.x == p2.x && p1.y == p2.y) {
printf("两个点是相同的。\n");
} else {
printf("两个点是不相同的。\n");
}
return 0;
}
代码注释:
struct Point:定义一个结构体类型Point,包含x和y两个整数成员。scanf:读取两个点的x和y坐标。if(p1.x == p2.x && p1.y == p2.y):比较两个点的坐标是否相等。printf:输出比较结果。
20. 结构体中的字符串
题目描述:
编写一个 C 程序,定义一个结构体Book,包含成员title(字符串)、author(字符串)和price(浮点数)。输入多个Book的信息,存储在结构体数组中,并输出所有书籍的信息。
解题思路:
定义结构体Book,包含title、author和price成员。声明一个包含多个Book的数组。使用for循环读取每本书的标题、作者和价格,并存储在数组中。最后,遍历数组并输出所有书籍的信息。
详细代码:
#include <stdio.h>
#include <string.h>
// 定义结构体Book
struct Book {
char title[100];
char author[50];
float price;
};
int main() {
struct Book library[3];
// 输入3本书的信息
for(int i = 0; i < 3; i++) {
printf("请输入第 %d 本书的标题: ", i + 1);
fgets(library[i].title, sizeof(library[i].title), stdin);
// 去除换行符
int j = 0;
while(library[i].title[j] != '\0') {
if(library[i].title[j] == '\n') {
library[i].title[j] = '\0';
break;
}
j++;
}
printf("请输入第 %d 本书的作者: ", i + 1);
fgets(library[i].author, sizeof(library[i].author), stdin);
// 去除换行符
j = 0;
while(library[i].author[j] != '\0') {
if(library[i].author[j] == '\n') {
library[i].author[j] = '\0';
break;
}
j++;
}
printf("请输入第 %d 本书的价格: ", i + 1);
scanf("%f", &library[i].price);
getchar(); // 清除输入缓冲区的换行符
}
// 输出所有书籍的信息
printf("\n--- 书籍信息 ---\n");
for(int i = 0; i < 3; i++) {
printf("第 %d 本书:\n", i + 1);
printf("标题: %s\n", library[i].title);
printf("作者: %s\n", library[i].author);
printf("价格: %.2f\n\n", library[i].price);
}
return 0;
}
代码注释:
struct Book:定义一个结构体类型Book,包含title、author和price三个成员。struct Book library[3];:声明一个包含 3 个Book的数组。fgets和去除换行符:读取书籍的标题和作者,并去除末尾的换行符。scanf:读取书籍的价格。getchar();:清除输入缓冲区的换行符,避免影响下一个fgets的读取。printf:输出所有书籍的信息,包括标题、作者和价格。