结构体与联合体练习

Tutorial: 教程一 Category: C语言 Published: 2026-04-07 13:58:26 Views: 20 Likes: 0 Comments: 0
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,包含nameageheight三个成员。
  • char name[50];:声明一个字符数组用于存储姓名,最大长度为 49 个字符(留出一个字符用于字符串结束符\0)。
  • struct Person person = {"Alice", 30, 5.6f};:使用初始化列表为结构体变量person的成员赋值。
  • printf:分别输出结构体成员的值。
2. 访问结构体成员

题目描述: 编写一个 C 程序,定义一个结构体Rectangle,包含成员lengthwidth(均为浮点数)。输入一个Rectanglelengthwidth,计算并输出其面积和周长。

解题思路: 定义结构体Rectangle,包含lengthwidth。在主函数中声明一个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,包含lengthwidth两个浮点数成员。
  • scanf:读取用户输入的长度和宽度,并存储到结构体变量rect的相应成员中。
  • areaperimeter:计算并存储面积和周长。
  • printf:输出计算结果。
3. 嵌套结构体

题目描述: 编写一个 C 程序,定义两个结构体DateEmployeeDate包含成员daymonthyearEmployee包含成员name(字符串)、id(整数)和birthdate(类型为Date的结构体)。输入一个员工的详细信息,并输出。

解题思路: 首先,定义结构体DateEmployee,其中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 Datestruct 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,包含namerollmarks三个成员。
  • struct Student students[5];:声明一个包含 5 个Student的数组。
  • fgets和去除换行符:读取学生姓名并去除末尾的换行符。
  • scanf:读取学生的学号和成绩。
  • getchar();:清除输入缓冲区的换行符,避免影响下一个fgets的读取。
  • totalMarks += students[i].marks;:累加每个学生的成绩。
  • average = totalMarks / 5;:计算平均分。
  • printf:输出平均分。
5. 结构体与函数

题目描述: 编写一个 C 程序,定义一个结构体Point,包含成员xy(均为浮点数)。创建一个函数distance,接受两个Point类型的参数,计算并返回两点之间的距离。在主函数中输入两个点的坐标,调用distance函数并输出结果。

解题思路: 定义结构体Point,包含xy成员。创建函数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,包含xy两个浮点数成员。
  • float distance(struct Point p1, struct Point p2);:声明一个函数distance,接受两个Point参数,返回浮点数。
  • scanf:读取两个点的xy坐标。
  • 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,包含titleauthorprice三个成员。
  • struct Book *ptr = &myBook;:声明一个指向Book结构体的指针ptr,并指向变量myBook
  • ptr->titleptr->author:通过指针访问和修改结构体成员。
  • fgets和去除换行符:读取字符串输入并去除末尾的换行符。
  • scanf:读取和修改价格。
  • printf:输出修改后的书籍信息。
7. 动态内存分配与结构体

题目描述: 编写一个 C 程序,定义一个结构体Student,包含成员name(字符串)和score(浮点数)。动态分配内存以存储一个Student,输入其信息,输出后释放内存。

解题思路: 定义结构体Student,包含namescore成员。在主函数中使用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,包含namescore两个成员。
  • malloc:动态分配内存来存储一个Student结构体。
  • 检查内存分配是否成功:如果malloc返回NULL,则输出错误信息并退出程序。
  • fgets和去除换行符:读取学生姓名并去除末尾的换行符。
  • scanf:读取学生成绩。
  • printf:输出学生信息。
  • free(ptr);:释放动态分配的内存。
8. 结构体比较

题目描述: 编写一个 C 程序,定义一个结构体Point,包含成员xy(均为整数)。输入两个Point,比较它们是否相同(即xy都相等),并输出结果。

解题思路: 定义结构体Point,包含xy两个整数成员。在主函数中声明两个Point变量,读取其坐标值。通过比较两个结构体的xy成员,判断它们是否相同,并输出相应的结果。

详细代码:

#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,包含xy两个整数成员。
  • scanf:读取两个点的xy坐标。
  • if(p1.x == p2.x && p1.y == p2.y):比较两个点的坐标是否相等。
  • printf:输出比较结果。
9. 联合体的定义和使用

题目描述: 编写一个 C 程序,定义一个联合体Data,包含成员i(整数)、f(浮点数)和str(字符串)。输入一个Data类型的变量的类型标识(例如ifstr),然后输入相应类型的值,并输出存储在联合体中的值。

解题思路: 定义联合体Data,包含ifstr三个成员。在主函数中声明一个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(字符串)。输入并设置abc的值,分别展示结构体和联合体的内存占用和成员值的变化。

解题思路: 定义结构体和联合体,包含相同的成员。在主函数中声明结构体和联合体变量,分别为其成员赋值。然后,使用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 ExampleStructunion ExampleUnion:定义结构体和联合体,包含相同的成员abc
  • 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成员覆盖了之前的ab成员的值。
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,包含phoneemail两个字符串成员。
  • struct Employee:定义一个结构体Employee,包含idnamecontact(联合体)和contactType(字符,表示联系方式类型)。
  • getchar();:在读取字符或字符串后,清除输入缓冲区的换行符,避免影响后续的fgets读取。
  • 根据contactType,选择输入电话或邮箱,并存储到联合体的相应成员中。
  • 最后,输出员工的所有信息,包括根据类型选择输出的联系方式。
12. 联合体数组

题目描述: 编写一个 C 程序,定义一个联合体Data,包含成员i(整数)、f(浮点数)和str(字符串)。创建一个包含 5 个Data类型的数组,输入每个元素的类型和相应的值,最后输出所有数组元素的值。

解题思路: 定义联合体Data,包含ifstr三个成员。在主函数中声明一个包含 5 个Data的数组。对于每个数组元素,读取其类型标识(ifstr),然后根据类型输入相应的值。最后,遍历数组并根据类型标识输出存储的值。

详细代码:

#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,包含ifstr三个成员。
  • struct DataWithType:定义一个结构体,用于存储Data和类型标识type
  • struct DataWithType array[5];:声明一个包含 5 个DataWithType的数组。
  • scanf(" %c", &array[idx].type);:读取每个数组元素的类型标识。
  • 根据类型标识,读取相应的值并存储在联合体的对应成员中。
  • fgets和去除换行符:读取字符串输入并去除末尾的换行符。
  • printf:输出数组中的所有元素,根据类型标识选择输出的成员。
13. 结构体中的指针

题目描述: 编写一个 C 程序,定义一个结构体Node,包含成员data(整数)和next(指向Node的指针)。创建一个简单的链表,包含三个节点,输入每个节点的数据,并遍历链表输出每个节点的值。

解题思路: 定义结构体Node,包含datanext成员。动态分配三个节点,链接它们形成链表。读取每个节点的数据,通过遍历链表输出节点的值。最后,释放分配的内存。

详细代码:

#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,包含datanext成员。在主函数中,动态创建链表节点,根据用户输入的值构建链表。输入-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的指针)。
  • headtempcurrent:指向链表的头节点、临时节点和当前节点的指针。
  • while(1):无限循环,直到用户输入-1。
  • malloc:动态分配内存为新节点。
  • if(head == NULL):如果链表为空,设置新节点为头节点。
  • current->next = temp; current = current->next;:将新节点添加到链表末尾,并更新当前节点指针。
  • 遍历链表,输出每个节点的数据。
  • 释放链表中所有节点的内存,防止内存泄漏。
15. 使用动态内存实现双向链表

题目描述: 编写一个 C 程序,定义一个结构体DNode,包含成员data(整数)、prevnext(分别指向前一个和后一个DNode的指针)。动态创建一个双向链表,输入节点的值,建立链表,并遍历链表从头到尾和从尾到头输出节点的值。

解题思路: 定义结构体DNode,包含dataprevnext成员。在主函数中,动态创建节点并链接形成双向链表。输入节点值,直到用户输入-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(整数)、prevnext(指向前后节点的指针)。
  • headtempcurrenttail:分别指向链表的头节点、临时节点、当前节点和尾节点的指针。
  • malloc:动态分配内存为新节点。
  • if(head == NULL):如果链表为空,设置新节点为头节点,并初始化tail
  • current->next = temp; temp->prev = current;:链接新节点到链表末尾,并更新currenttail指针。
  • 遍历链表从头到尾和从尾到头输出节点的数据。
  • 释放链表中所有节点的内存,防止内存泄漏。
16. 使用联合体节省内存

题目描述: 编写一个 C 程序,定义一个联合体Value,包含成员intVal(整数)、floatVal(浮点数)和charVal(字符)。创建一个包含 10 个Value类型的数组,输入每个元素的类型和相应的值,展示联合体如何节省内存。

解题思路: 定义联合体Value,包含intValfloatValcharVal三个成员。声明一个包含 10 个Value的数组。对于每个数组元素,读取类型标识(ifc),并输入相应的值。通过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,包含intValfloatValcharVal三个成员。
  • 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,包含成员lengthwidth(均为浮点数)。创建一个函数calculateArea,接受一个指向Rectangle的指针参数,计算并返回矩形的面积。在主函数中输入矩形的长度和宽度,调用calculateArea函数并输出结果。

解题思路: 定义结构体Rectangle,包含lengthwidth成员。创建函数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,包含lengthwidth两个浮点数成员。
  • float calculateArea(struct Rectangle *rect);:声明一个函数calculateArea,接受一个指向Rectangle的指针参数,返回浮点数。
  • scanf:读取矩形的长度和宽度并存储到结构体变量rect中。
  • calculateArea(&rect);:调用calculateArea函数,传递结构体变量的地址。
  • rect->length * rect->width:通过指针访问结构体成员,计算面积。
19. 比较两个结构体是否相同

题目描述: 编写一个 C 程序,定义一个结构体Point,包含成员xy(均为整数)。输入两个Point,比较它们是否相同(即xy都相等),并输出结果。

解题思路: 定义结构体Point,包含xy两个整数成员。在主函数中声明两个Point变量,读取其坐标值。通过比较两个结构体的xy成员,判断它们是否相同,并输出相应的结果。

详细代码:

#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,包含xy两个整数成员。
  • scanf:读取两个点的xy坐标。
  • if(p1.x == p2.x && p1.y == p2.y):比较两个点的坐标是否相等。
  • printf:输出比较结果。
20. 结构体中的字符串

题目描述: 编写一个 C 程序,定义一个结构体Book,包含成员title(字符串)、author(字符串)和price(浮点数)。输入多个Book的信息,存储在结构体数组中,并输出所有书籍的信息。

解题思路: 定义结构体Book,包含titleauthorprice成员。声明一个包含多个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,包含titleauthorprice三个成员。
  • struct Book library[3];:声明一个包含 3 个Book的数组。
  • fgets和去除换行符:读取书籍的标题和作者,并去除末尾的换行符。
  • scanf:读取书籍的价格。
  • getchar();:清除输入缓冲区的换行符,避免影响下一个fgets的读取。
  • printf:输出所有书籍的信息,包括标题、作者和价格。
Prev: 指针练习 Next: None