C语言:结构体指针

介绍

在C语言中,结构体指针是一种非常有用的工具,它允许我们通过指针来操作结构体,尤其是在处理动态内存分配或函数参数传递时。以下是关于C语言结构体指针的详细讲解。

定义结构体指针

首先,我们需要定义一个结构体。例如,定义一个表示学生信息的结构体:

#include <stdio.h>

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

然后,我们可以定义一个指向该结构体的指针:

struct Student *studentPtr;

初始化结构体指针

指向现有结构体变量

我们可以让结构体指针指向一个已有的结构体变量:

struct Student student1 = {"Alice", 20, 3.5};
struct Student *studentPtr = &student1;

动态分配内存

我们也可以使用动态内存分配来初始化结构体指针:

struct Student *studentPtr = (struct Student *)malloc(sizeof(struct Student));
if (studentPtr == NULL) {
    printf("Memory allocation failed\n");
    return 1;
}

访问结构体成员

使用结构体指针访问成员

当我们有一个结构体指针时,可以使用箭头操作符 -> 来访问结构体成员:

studentPtr->age = 21;
printf("Name: %s, Age: %d, GPA: %.2f\n", studentPtr->name, studentPtr->age, studentPtr->gpa);

通过指针和解引用

我们也可以使用指针和解引用操作符 * 组合来访问结构体成员:

(*studentPtr).age = 22;
printf("Name: %s, Age: %d, GPA: %.2f\n", (*studentPtr).name, (*studentPtr).age, (*studentPtr).gpa);

不过,使用箭头操作符 -> 更加简洁和常见。

结构体指针作为函数参数

将结构体指针作为函数参数,可以高效地传递结构体数据,避免大结构体的拷贝。以下是一个示例:

void printStudent(struct Student *student) {
    printf("Name: %s, Age: %d, GPA: %.2f\n", student->name, student->age, student->gpa);
}

int main() {
    struct Student student1 = {"Alice", 20, 3.5};
    printStudent(&student1);

    struct Student *studentPtr = (struct Student *)malloc(sizeof(struct Student));
    if (studentPtr == NULL) {
        printf("Memory allocation failed\n");
        return 1;
    }
    strcpy(studentPtr->name, "Bob");
    studentPtr->age = 21;
    studentPtr->gpa = 3.7;
    printStudent(studentPtr);

    free(studentPtr);

    return 0;
}

使用结构体指针构建链表

结构体指针在构建复杂数据结构(如链表)时非常有用。以下是一个简单的单链表示例:

#include <stdio.h>
#include <stdlib.h>

// 定义链表节点
struct Node {
    int data;
    struct Node *next;
};

// 创建新节点
struct Node* createNode(int data) {
    struct Node *newNode = (struct Node *)malloc(sizeof(struct Node));
    if (newNode == NULL) {
        printf("Memory allocation failed\n");
        exit(1);
    }
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}

// 打印链表
void printList(struct Node *head) {
    struct Node *current = head;
    while (current != NULL) {
        printf("%d -> ", current->data);
        current = current->next;
    }
    printf("NULL\n");
}

int main() {
    struct Node *head = createNode(1);
    head->next = createNode(2);
    head->next->next = createNode(3);

    printList(head);

    // 释放内存
    struct Node *current = head;
    struct Node *next;
    while (current != NULL) {
        next = current->next;
        free(current);
        current = next;
    }

    return 0;
}

高级用法

当然,这里有更多关于C语言结构体指针的高级用法和注意事项。

多级指针(指向指针的指针)

有时候,我们可能需要使用指向指针的指针,尤其是在处理动态二维数组或在函数中修改指针变量时。以下是一个简单的示例:

#include <stdio.h>
#include <stdlib.h>

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

void allocateStudent(struct Student **studentPtr) {
    *studentPtr = (struct Student *)malloc(sizeof(struct Student));
    if (*studentPtr == NULL) {
        printf("Memory allocation failed\n");
        exit(1);
    }
}

int main() {
    struct Student *studentPtr = NULL;
    allocateStudent(&studentPtr);

    strcpy(studentPtr->name, "Alice");
    studentPtr->age = 20;
    studentPtr->gpa = 3.5;

    printf("Name: %s, Age: %d, GPA: %.2f\n", studentPtr->name, studentPtr->age, studentPtr->gpa);

    free(studentPtr);
    return 0;
}

在这个例子中,allocateStudent 函数使用了双重指针(struct Student **)来分配内存并修改指针变量。

动态二维数组

使用结构体指针可以创建动态二维数组。例如,一个表示学生成绩的二维数组:

#include <stdio.h>
#include <stdlib.h>

struct Grade {
    int studentId;
    float score;
};

int main() {
    int rows = 3;
    int cols = 2;

    // 分配行指针数组
    struct Grade **grades = (struct Grade **)malloc(rows * sizeof(struct Grade *));
    if (grades == NULL) {
        printf("Memory allocation failed\n");
        return 1;
    }

    // 分配每行的列
    for (int i = 0; i < rows; i++) {
        grades[i] = (struct Grade *)malloc(cols * sizeof(struct Grade));
        if (grades[i] == NULL) {
            printf("Memory allocation failed\n");
            return 1;
        }
    }

    // 初始化数据
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            grades[i][j].studentId = i * cols + j;
            grades[i][j].score = (i + 1) * (j + 1) * 10.0;
        }
    }

    // 输出数据
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("Student ID: %d, Score: %.2f\n", grades[i][j].studentId, grades[i][j].score);
        }
    }

    // 释放内存
    for (int i = 0; i < rows; i++) {
        free(grades[i]);
    }
    free(grades);

    return 0;
}

结构体指针与链表操作

链表是一种常见的数据结构,使用结构体指针实现链表操作是一个非常好的练习。以下是一些基本的链表操作示例,包括插入和删除节点:

插入节点

void insertAtBeginning(struct Node **head, int data) {
    struct Node *newNode = createNode(data);
    newNode->next = *head;
    *head = newNode;
}

void insertAtEnd(struct Node **head, int data) {
    struct Node *newNode = createNode(data);
    if (*head == NULL) {
        *head = newNode;
        return;
    }

    struct Node *current = *head;
    while (current->next != NULL) {
        current = current->next;
    }
    current->next = newNode;
}

删除节点

void deleteNode(struct Node **head, int key) {
    struct Node *temp = *head, *prev = NULL;

    // 如果头节点持有要删除的值
    if (temp != NULL && temp->data == key) {
        *head = temp->next;
        free(temp);
        return;
    }

    // 搜索要删除的节点
    while (temp != NULL && temp->data != key) {
        prev = temp;
        temp = temp->next;
    }

    // 如果没有找到该值
    if (temp == NULL) return;

    // 解除链接并释放内存
    prev->next = temp->next;
    free(temp);
}

高级链表操作

链表反转

反转链表是一个常见的操作,以下是反转单链表的代码示例:

#include <stdio.h>
#include <stdlib.h>

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

struct Node* createNode(int data) {
    struct Node *newNode = (struct Node *)malloc(sizeof(struct Node));
    if (newNode == NULL) {
        printf("Memory allocation failed\n");
        exit(1);
    }
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}

void reverseList(struct Node **head) {
    struct Node *prev = NULL;
    struct Node *current = *head;
    struct Node *next = NULL;
    while (current != NULL) {
        next = current->next;
        current->next = prev;
        prev = current;
        current = next;
    }
    *head = prev;
}

void printList(struct Node *head) {
    struct Node *current = head;
    while (current != NULL) {
        printf("%d -> ", current->data);
        current = current->next;
    }
    printf("NULL\n");
}

int main() {
    struct Node *head = createNode(1);
    head->next = createNode(2);
    head->next->next = createNode(3);

    printf("Original List:\n");
    printList(head);

    reverseList(&head);

    printf("Reversed List:\n");
    printList(head);

    // 释放内存
    struct Node *current = head;
    struct Node *next;
    while (current != NULL) {
        next = current->next;
        free(current);
        current = next;
    }

    return 0;
}

链表合并

合并两个有序链表是一个常见操作,以下是合并两个有序链表的代码示例:

struct Node* mergeLists(struct Node *l1, struct Node *l2) {
    if (l1 == NULL) return l2;
    if (l2 == NULL) return l1;

    struct Node *head = NULL;

    if (l1->data < l2->data) {
        head = l1;
        l1 = l1->next;
    } else {
        head = l2;
        l2 = l2->next;
    }

    struct Node *current = head;

    while (l1 != NULL && l2 != NULL) {
        if (l1->data < l2->data) {
            current->next = l1;
            l1 = l1->next;
        } else {
            current->next = l2;
            l2 = l2->next;
        }
        current = current->next;
    }

    if (l1 != NULL) {
        current->next = l1;
    } else {
        current->next = l2;
    }

    return head;
}

深拷贝结构体

有时候我们需要对结构体进行深拷贝,即复制结构体及其所有嵌套的内容。以下是一个深拷贝简单结构体的示例:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct Address {
    char street[100];
    char city[50];
    char state[50];
    int zip;
};

struct Student {
    char name[50];
    int age;
    float gpa;
    struct Address *address;
};

struct Student* deepCopyStudent(const struct Student *original) {
    struct Student *copy = (struct Student *)malloc(sizeof(struct Student));
    if (copy == NULL) {
        printf("Memory allocation failed\n");
        exit(1);
    }

    strcpy(copy->name, original->name);
    copy->age = original->age;
    copy->gpa = original->gpa;

    copy->address = (struct Address *)malloc(sizeof(struct Address));
    if (copy->address == NULL) {
        printf("Memory allocation failed\n");
        free(copy);
        exit(1);
    }
    memcpy(copy->address, original->address, sizeof(struct Address));

    return copy;
}

int main() {
    struct Address address = {"123 Maple St", "Springfield", "IL", 62701};
    struct Student student1 = {"Alice", 20, 3.5, &address};

    struct Student *studentCopy = deepCopyStudent(&student1);

    // 修改原始数据以验证深拷贝
    strcpy(student1.address->city, "Changed City");

    printf("Original Student: %s, %s\n", student1
  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值