当涉及到C语言结构体的高级玩法时,有很多有趣和强大的技巧可以应用。下面是10个例子代码,每个例子都使用了不同的高级结构体技术,包括位字段、嵌套结构体、联合体、指向结构体的指针等。让我们逐个来讲解这些例子代码。

  • 位字段(Bit Fields)
  1. #include <stdio.h>
  2. struct Flags {
  3.     unsigned int flag1 : 1;
  4.     unsigned int flag2 : 2;
  5.     unsigned int flag3 : 3;
  6. };
  7. int main() {
  8.     struct Flags f;
  9.     f.flag1 = 1;
  10.     f.flag2 = 2;
  11.     f.flag3 = 3;
  12.     printf("Flag 1: %d\n", f.flag1);
  13.     printf("Flag 2: %d\n", f.flag2);
  14.     printf("Flag 3: %d\n", f.flag3);
  15.     return 0;
  16. }
在这个例子中,我们使用了位字段来定义一个结构体,其中每个成员变量都指定了所占用的位数。这样可以有效地使用内存,并在结构体中存储多个布尔标志或其他具有限定范围的值。

  • 嵌套结构体(Nested Structures)
  1. #include <stdio.h>
  2. struct Date {
  3.     int day;
  4.     int month;
  5.     int year;
  6. };
  7. struct Person {
  8.     char name[20];
  9.     struct Date birthdate;
  10. };
  11. int main() {
  12.     struct Person p;
  13.     strcpy(p.name, "John Doe");
  14.     p.birthdate.day = 1;
  15.     p.birthdate.month = 1;
  16.     p.birthdate.year = 1990;
  17.     printf("Name: %s\n", p.name);
  18.     printf("Birthdate: %d/%d/%d\n", p.birthdate.day, p.birthdate.month, p.birthdate.year);
  19.     return 0;
  20. }
在这个例子中,我们定义了一个Date结构体,它包含了日期的日、月和年。然后,我们在Person结构体中嵌套了Date结构体,以表示一个人的姓名和出生日期。

  • 联合体(Unions)
  1. #include <stdio.h>
  2. union Data {
  3.     int i;
  4.     float f;
  5.     char str[20];
  6. };
  7. int main() {
  8.     union Data data;
  9.     data.i = 10;
  10.     printf("Data as integer: %d\n", data.i);
  11.     data.f = 3.14;
  12.     printf("Data as float: %f\n", data.f);
  13.     strcpy(data.str, "Hello");
  14.     printf("Data as string: %s\n", data.str);
  15.     return 0;
  16. }
联合体允许在同一块内存空间中存储不同类型的数据。在这个例子中,我们定义了一个Data联合体,它可以存储整数、浮点数和字符串。通过更改联合体的成员,我们可以以不同的方式解释相同的内存块。

  • 指向结构体的指针(Pointers to Structures)
  1. #include <stdio.h>
  2. struct Point {
  3.     int x;
  4.     int y;
  5. };
  6. void printPoint(struct Point *p) {
  7.     printf("Point coordinates: (%d, %d)\n", p->x, p->y);
  8. }
  9. int main() {
  10.     struct Point p;
  11.     struct Point *ptr;
  12.     p.x = 10;
  13.     p.y = 20;
  14.     ptr = &p;
  15.     printPoint(ptr);
  16.     return 0;
  17. }
在这个例子中,我们定义了一个Point结构体来表示二维平面上的一个点。然后,我们声明一个指向Point结构体的指针ptr,并将其指向结构体变量p。通过指针,我们可以直接访问结构体的成员,并将指针传递给函数以操作结构体。

  • 结构体的自引用(Self-referential Structures)
  1. #include <stdio.h>
  2. struct Node {
  3.     int data;
  4.     struct Node *next;
  5. };
  6. int main() {
  7.     struct Node node1, node2, node3;
  8.     node1.data = 10;
  9.     node2.data = 20;
  10.     node3.data = 30;
  11.     node1.next = &node2;
  12.     node2.next = &node3;
  13.     node3.next = NULL;
  14.     struct Node *current = &node1;
  15.     while (current != NULL) {
  16.         printf("Data: %d\n", current->data);
  17.         current = current->next;
  18.     }
  19.     return 0;
  20. }
这个例子展示了结构体的自引用,其中每个结构体节点包含一个数据成员和一个指向下一个节点的指针。通过链接多个节点,我们可以创建链表的数据结构。

  • 函数指针成员(Function Pointer Members)
  1. #include <stdio.h>
  2. struct MathOperations {
  3.     int (*add)(int, int);
  4.     int (*subtract)(int, int);
  5. };
  6. int add(int a, int b) {
  7.     return a + b;
  8. }
  9. int subtract(int a, int b) {
  10.     return a - b;
  11. }
  12. int main() {
  13.     struct MathOperations math;
  14.     math.add = add;
  15.     math.subtract = subtract;
  16.     int result1 = math.add(5, 3);
  17.     int result2 = math.subtract(10, 4);
  18.     printf("Addition result: %d\n", result1);
  19.     printf("Subtraction result: %d\n", result2);
  20.     return 0;
  21. }
在这个例子中,我们定义了一个MathOperations结构体,其中包含两个函数指针成员,分别用于执行加法和减法操作。我们将这些函数指针与相应的函数进行关联,并使用结构体中的函数指针调用函数。

  • 动态分配结构体(Dynamic Allocation of Structures)
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. struct Person {
  4.     char name[20];
  5.     int age;
  6. };
  7. int main() {
  8.     struct Person *person = (struct Person*) malloc(sizeof(struct Person));
  9.     if (person == NULL) {
  10.         printf("Memory allocation failed.\n");
  11.         return 1;
  12.     }
  13.     strcpy(person->name, "John Doe");
  14.     person->age = 25;
  15.                 printf("Name: %s\n", person->name);
  16.                 printf("Age: %d\n", person->age);
  17.                 free(person);
  18.                 return 0;
  19. }
在这个例子中,我们使用`malloc`函数动态地分配了一个`Person`结构体的内存空间。通过`sizeof`运算符确定所需的内存大小。然后,我们可以像使用普通结构体一样,访问和操作这个动态分配的结构体。最后,记得使用`free`函数释放动态分配的内存空间,以避免内存泄漏。

  • 结构体数组(Array of Structures)
  1. #include <stdio.h>
  2. struct Student {
  3.     char name[20];
  4.     int age;
  5.     float gpa;
  6. };
  7. int main() {
  8.     struct Student students[3];
  9.     for (int i = 0; i < 3; i++) {
  10.         printf("Enter name for student %d: ", i+1);
  11.         scanf("%s", students[i].name);
  12.         printf("Enter age for student %d: ", i+1);
  13.         scanf("%d", &students[i].age);
  14.         printf("Enter GPA for student %d: ", i+1);
  15.         scanf("%f", &students[i].gpa);
  16.     }
  17.     printf("\nStudent Details:\n");
  18.     for (int i = 0; i < 3; i++) {
  19.         printf("Name: %s\n", students[i].name);
  20.         printf("Age: %d\n", students[i].age);
  21.         printf("GPA: %.2f\n", students[i].gpa);
  22.         printf("\n");
  23.     }
  24.     return 0;
  25. }
在这个例子中,我们定义了一个Student结构体,包含学生的姓名、年龄和GPA。然后,我们创建一个包含3个Student结构体的数组,并使用循环依次获取每个学生的信息。最后,我们遍历结构体数组,并打印每个学生的详细信息。

  • 结构体的对齐(Structure Padding)
  1. #include <stdio.h>
  2. #pragma pack(1)
  3. struct Person {
  4.     char name[20];
  5.     int age;
  6. };
  7. int main() {
  8.     struct Person p;
  9.     printf("Size of struct Person: %d\n", sizeof(p));
  10.     return 0;
  11. }
在这个例子中,我们使用#pragma pack(1)预处理指令告诉编译器以字节对齐方式为1来定义结构体。默认情况下,编译器会进行结构体成员的对齐,以优化访问速度。通过指定对齐方式为1,我们可以减少内存浪费,但可能会导致访问效率稍微降低。我们可以使用sizeof运算符来查看对齐后的结构体大小。

  • 结构体作为函数的返回值(Structure as Return Type)
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. struct Point {
  4.     int x;
  5.     int y;
  6. };
  7. struct Point* getPoint() {
  8.     struct Point* p = malloc(sizeof(struct Point));
  9.     p->x = 10;
  10.     p->y = 20;
  11.     return p;
  12. }
  13. int main() {
  14.     struct Point* result = getPoint();
  15.     printf("Point coordinates: (%d, %d)\n", result->x, result->y);
  16.     free(result);
  17.     return 0;
  18. }
在这个例子中,我们定义了一个返回`Point`结构体的函数`getPoint()`。在函数内部,我们创建一个`Point`结构体并设置其坐标值。然后,我们将该结构体作为函数的返回值返回,并在`main()`函数中接收并打印返回的结构体的坐标值。我们将getPoint()函数的返回类型改为指向Point结构体的指针。在函数内部,我们使用malloc()动态分配了一个Point结构体的内存,并设置其坐标值。然后,我们返回指向动态分配内存的指针。在main()函数中,我们接收返回的指针,并使用箭头运算符访问结构体的成员。最后,记得使用free()函数释放动态分配的内存空间,以避免内存泄漏。
这些例子展示了C语言结构体的一些高级玩法,包括位字段、嵌套结构体、联合体、指向结构体的指针、自引用、函数指针成员、动态分配、结构体数组、结构体的对齐以及结构体作为函数的返回值。这些技巧可以帮助你更灵活和高效地使用结构体来组织和操作数据。