天天看點

C語言結構體的進階玩法,十個樣例代碼賞析并解析

作者:曉亮Albert

當涉及到C語言結構體的進階玩法時,有很多有趣和強大的技巧可以應用。下面是10個例子代碼,每個例子都使用了不同的進階結構體技術,包括位字段、嵌套結構體、聯合體、指向結構體的指針等。讓我們逐個來講解這些例子代碼。

  1. 位字段(Bit Fields)
#include <stdio.h>

struct Flags {
    unsigned int flag1 : 1;
    unsigned int flag2 : 2;
    unsigned int flag3 : 3;
};

int main() {
    struct Flags f;
    f.flag1 = 1;
    f.flag2 = 2;
    f.flag3 = 3;

    printf("Flag 1: %d\n", f.flag1);
    printf("Flag 2: %d\n", f.flag2);
    printf("Flag 3: %d\n", f.flag3);

    return 0;
}
           

在這個例子中,我們使用了位字段來定義一個結構體,其中每個成員變量都指定了所占用的位數。這樣可以有效地使用記憶體,并在結構體中存儲多個布爾标志或其他具有限定範圍的值。

  1. 嵌套結構體(Nested Structures)
#include <stdio.h>

struct Date {
    int day;
    int month;
    int year;
};

struct Person {
    char name[20];
    struct Date birthdate;
};

int main() {
    struct Person p;
    strcpy(p.name, "John Doe");
    p.birthdate.day = 1;
    p.birthdate.month = 1;
    p.birthdate.year = 1990;

    printf("Name: %s\n", p.name);
    printf("Birthdate: %d/%d/%d\n", p.birthdate.day, p.birthdate.month, p.birthdate.year);

    return 0;
}
           

在這個例子中,我們定義了一個Date結構體,它包含了日期的日、月和年。然後,我們在Person結構體中嵌套了Date結構體,以表示一個人的姓名和出生日期。

  1. 聯合體(Unions)
#include <stdio.h>

union Data {
    int i;
    float f;
    char str[20];
};

int main() {
    union Data data;
    data.i = 10;

    printf("Data as integer: %d\n", data.i);

    data.f = 3.14;
    printf("Data as float: %f\n", data.f);

    strcpy(data.str, "Hello");
    printf("Data as string: %s\n", data.str);

    return 0;
}
           

聯合體允許在同一塊記憶體空間中存儲不同類型的資料。在這個例子中,我們定義了一個Data聯合體,它可以存儲整數、浮點數和字元串。通過更改聯合體的成員,我們可以以不同的方式解釋相同的記憶體塊。

  1. 指向結構體的指針(Pointers to Structures)
#include <stdio.h>

struct Point {
    int x;
    int y;
};

void printPoint(struct Point *p) {
    printf("Point coordinates: (%d, %d)\n", p->x, p->y);
}

int main() {
    struct Point p;
    struct Point *ptr;

    p.x = 10;
    p.y = 20;

    ptr = &p;

    printPoint(ptr);

    return 0;
}
           

在這個例子中,我們定義了一個Point結構體來表示二維平面上的一個點。然後,我們聲明一個指向Point結構體的指針ptr,并将其指向結構體變量p。通過指針,我們可以直接通路結構體的成員,并将指針傳遞給函數以操作結構體。

  1. 結構體的自引用(Self-referential Structures)
#include <stdio.h>

struct Node {
    int data;
    struct Node *next;
};

int main() {
    struct Node node1, node2, node3;

    node1.data = 10;
    node2.data = 20;
    node3.data = 30;

    node1.next = &node2;
    node2.next = &node3;
    node3.next = NULL;

    struct Node *current = &node1;

    while (current != NULL) {
        printf("Data: %d\n", current->data);
        current = current->next;
    }

    return 0;
}
           

這個例子展示了結構體的自引用,其中每個結構體節點包含一個資料成員和一個指向下一個節點的指針。通過連結多個節點,我們可以建立連結清單的資料結構。

  1. 函數指針成員(Function Pointer Members)
#include <stdio.h>

struct MathOperations {
    int (*add)(int, int);
    int (*subtract)(int, int);
};

int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

int main() {
    struct MathOperations math;

    math.add = add;
    math.subtract = subtract;

    int result1 = math.add(5, 3);
    int result2 = math.subtract(10, 4);

    printf("Addition result: %d\n", result1);
    printf("Subtraction result: %d\n", result2);

    return 0;
}
           

在這個例子中,我們定義了一個MathOperations結構體,其中包含兩個函數指針成員,分别用于執行加法和減法操作。我們将這些函數指針與相應的函數進行關聯,并使用結構體中的函數指針調用函數。

  1. 動态配置設定結構體(Dynamic Allocation of Structures)
#include <stdio.h>
#include <stdlib.h>

struct Person {
    char name[20];
    int age;
};

int main() {
    struct Person *person = (struct Person*) malloc(sizeof(struct Person));

    if (person == NULL) {
        printf("Memory allocation failed.\n");
        return 1;
    }

    strcpy(person->name, "John Doe");
    person->age = 25;
		printf("Name: %s\n", person->name);
		printf("Age: %d\n", person->age);

		free(person);

		return 0;
}           

在這個例子中,我們使用`malloc`函數動态地配置設定了一個`Person`結構體的記憶體空間。通過`sizeof`運算符确定所需的記憶體大小。然後,我們可以像使用普通結構體一樣,通路和操作這個動态配置設定的結構體。最後,記得使用`free`函數釋放動态配置設定的記憶體空間,以避免記憶體洩漏。

  1. 結構體數組(Array of Structures)
#include <stdio.h>

struct Student {
    char name[20];
    int age;
    float gpa;
};

int main() {
    struct Student students[3];

    for (int i = 0; i < 3; i++) {
        printf("Enter name for student %d: ", i+1);
        scanf("%s", students[i].name);

        printf("Enter age for student %d: ", i+1);
        scanf("%d", &students[i].age);

        printf("Enter GPA for student %d: ", i+1);
        scanf("%f", &students[i].gpa);
    }

    printf("\nStudent Details:\n");

    for (int i = 0; i < 3; i++) {
        printf("Name: %s\n", students[i].name);
        printf("Age: %d\n", students[i].age);
        printf("GPA: %.2f\n", students[i].gpa);
        printf("\n");
    }

    return 0;
}
           

在這個例子中,我們定義了一個Student結構體,包含學生的姓名、年齡和GPA。然後,我們建立一個包含3個Student結構體的數組,并使用循環依次擷取每個學生的資訊。最後,我們周遊結構體數組,并列印每個學生的詳細資訊。

  1. 結構體的對齊(Structure Padding)
#include <stdio.h>

#pragma pack(1)

struct Person {
    char name[20];
    int age;
};

int main() {
    struct Person p;

    printf("Size of struct Person: %d\n", sizeof(p));

    return 0;
}
           

在這個例子中,我們使用#pragma pack(1)預處理指令告訴編譯器以位元組對齊方式為1來定義結構體。預設情況下,編譯器會進行結構體成員的對齊,以優化通路速度。通過指定對齊方式為1,我們可以減少記憶體浪費,但可能會導緻通路效率稍微降低。我們可以使用sizeof運算符來檢視對齊後的結構體大小。

  1. 結構體作為函數的傳回值(Structure as Return Type)
#include <stdio.h>

struct Point {
    int x;
    int y;
};

struct Point getPoint() {
    struct Point p;
    p.x = 10;
    p.y = 20;
    return p;
}

int main() {
    struct Point result = getPoint(); 
    printf("Point coordinates: (%d, %d)\n", result.x, result.y);
		return 0;
  }           

在這個例子中,我們定義了一個傳回`Point`結構體的函數`getPoint()`。在函數内部,我們建立一個`Point`結構體并設定其坐标值。然後,我們将該結構體作為函數的傳回值傳回,并在`main()`函數中接收并列印傳回的結構體的坐标值。

這些例子展示了C語言結構體的一些進階玩法,包括位字段、嵌套結構體、聯合體、指向結構體的指針、自引用、函數指針成員、動态配置設定、結構體數組、結構體的對齊以及結構體作為函數的傳回值。這些技巧可以幫助你更靈活和高效地使用結構體來組織和操作資料。