本文最后更新于 2026-03-06,文章内容可能已经过时。

C语言结构体是一种自定义复合数据类型,用于组合不同类型的数据成员;结构体指针通过箭头运算符(->)高效访问成员,避免复制大型结构体的开销,广泛应用于函数参数传递、动态内存分配(如malloc)和链表/树等数据结构实现中,但需注意指针初始化、越界访问及内存泄漏等常见陷阱。

一、结构体基础

1. 结构体定义

结构体是C语言中一种用户自定义的复合数据类型,允许将不同类型的数据组合成一个逻辑整体。

定义结构体的三种方式:

  1. 先声明结构体类型再定义变量(推荐,利于复用与模块化)

    struct Student {
        char name[50];
        int age;
        float score;
    };
    struct Student student1, student2;
    
  2. 在声明类型的同时定义变量

    struct Student {
        char name[50];
        int age;
        float score;
    } student1, student2;
    
  3. 直接定义匿名结构体变量

    struct {
        char name[50];
        int age;
        float score;
    } student1, student2;
    

2. 结构体变量的初始化

struct Student student1;
strcpy(student1.name, "张三");
student1.age = 20;
student1.score = 90.5;

二、结构体指针

1. 结构体指针的定义

结构体指针是指向结构体变量的指针,用于存储结构体变量的地址。

定义格式:

struct 结构体名 *指针变量名;

示例:

struct Student student1;
struct Student *ptr = &student1;  // ptr指向student1

2. 访问结构体成员的两种方式

  1. 通过解引用和点运算符(*ptr).member

    printf("%s", (*ptr).name);
    
  2. 通过箭头运算符ptr->member,更常用)

    printf("%s", ptr->name);
    

注意(*ptr).nameptr->name 是等价的,但箭头运算符更简洁直观。

3. 结构体指针的实例

示例1:基本结构体指针使用

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

struct Book {
    char title[20];
    long id;
    int price;
};

int main() {
    struct Book book1;
    struct Book *ptr;
    
    ptr = &book1;  // 指向book1
    
    // 初始化
    strcpy(book1.title, "C语言入门教程");
    book1.id = 1;
    book1.price = 49;
    
    // 通过结构体变量访问
    printf("书名:%s 编号:%ld 价格:%d\n", book1.title, book1.id, book1.price);
    
    // 通过结构体指针访问
    printf("书名:%s 编号:%ld 价格:%d\n", (*ptr).title, (*ptr).id, (*ptr).price);
    printf("书名:%s 编号:%ld 价格:%d\n", ptr->title, ptr->id, ptr->price);
    
    return 0;
}

示例2:结构体数组与指针

#include <stdio.h>
#define STU_NUM 2

struct Student {
    char *name;
    int num;
    int age;
    float score;
} students[STU_NUM] = {
    {"张三", 1, 18, 97.0},
    {"李四", 2, 19, 96.0}
}, *ptr;

int main() {
    printf("Name\tNum\tAge\tScore\n");
    for(ptr = students; ptr <= students + (STU_NUM - 1); ptr++) {
        printf("%s\t%d\t%d\t%.1f\n", ptr->name, ptr->num, ptr->age, ptr->score);
    }
    return 0;
}

三、结构体指针在函数中的应用

1. 作为函数参数传递

结构体指针作为函数参数可以避免复制整个结构体,提高效率。

示例:

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

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

// 通过结构体指针修改结构体内容
void set_student(struct Student *s, char *name, int age, float score) {
    strcpy(s->name, name);
    s->age = age;
    s->score = score;
}

// 通过结构体指针打印结构体内容
void print_student(struct Student *s) {
    printf("Name: %s, Age: %d, Score: %.1f\n", s->name, s->age, s->score);
}

int main() {
    struct Student student;
    
    set_student(&student, "张三", 20, 95.5);
    print_student(&student);
    
    return 0;
}

四、结构体指针的内存管理

1. 动态分配结构体内存

使用malloc在堆上分配结构体内存:

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

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

int main() {
    struct Student *p = (struct Student *)malloc(sizeof(struct Student));
    if (p == NULL) {
        printf("内存分配失败\n");
        return 1;
    }
    
    strcpy(p->name, "张三");
    p->age = 20;
    p->score = 95.5;
    
    printf("Name: %s, Age: %d, Score: %.1f\n", p->name, p->age, p->score);
    
    free(p);  // 释放内存
    return 0;
}

五、结构体指针的常见陷阱

  1. 未初始化指针:使用未初始化的指针会导致未定义行为。
  2. 指针越界:在操作结构体数组时,确保指针不会超出数组范围。
  3. 内存泄漏:使用malloc分配的内存,记得用free释放。

六、结构体指针的实用场景

  1. 链表:结构体指针是实现链表的核心,每个节点包含数据和指向下一个节点的指针。
  2. 树结构:二叉树、AVL树等数据结构中,节点通常包含指向子节点的指针。
  3. 哈希表:桶数组中的元素通常是结构体指针。
  4. 函数参数传递:传递大型结构体时,使用指针避免复制开销。

七、总结

  • 结构体是C语言中组织异构数据的基本工具。
  • 结构体指针是访问和操作结构体的高效方式。
  • 箭头运算符(->)是访问结构体指针成员的首选方式。
  • 结构体指针在数据结构、动态内存管理、函数参数传递等方面有广泛应用。

掌握结构体和指针是学习C语言高级特性和数据结构的基础,也是成为合格C语言程序员的必经之路。