C语言结构体与指针使用详解及避坑指南

七月
七月
发布时间:2026-10-13| 3人浏览过
原创

掌握C语言结构体及其指针的正确用法是高效编程的基础。本文深入解析结构体的定义与成员访问,阐述为何在函数传参时推荐使用指针以避免数据拷贝开销,并详细介绍基于malloc的动态内存分配全流程,包括空间申请、有效性判断、字符串成员的独立管理及最终的内存释放与指针重置,帮助开发者规避常见的内存泄漏与野指针风险。

结构体的定义与基础操作

结构体(struct)是C语言中用于聚合不同类型数据的复合数据类型。在实际开发中,通常需要定义结构体类型并使用指针进行实例化或成员访问。

以下代码展示了如何定义一个名为 STAFF_T 的结构体,包含姓名、性别、年龄、薪资和日期等成员:

#include <stdio.h>
#include <stdlib.h> // 标准头文件替换了非标准的<malloc.h>

typedef struct Staff_t {
    char* name;
    char sex;
    short age;
    float salary;
    char* date;
} STAFF_T;

函数传参:为什么推荐使用结构体指针?

当将结构体作为函数参数传递时,如果是按值传递(即直接传入结构体变量),系统会创建该结构体的完整副本。对于大型结构体,这种拷贝操作会消耗大量的时间与栈空间,导致性能下降。

最佳实践: 1. 优先使用结构体指针作为函数参数,仅传递地址,大幅降低开销。 2. 若函数仅需读取结构体数据而不修改,建议在指针前添加 const 限定符,防止意外修改原数据。

示例:使用常量指针接收结构体

以下函数演示了如何通过 const STAFF_T * 安全地读取结构体内容:

void print_msg(STAFF_T const *p) {
    if (p == NULL) { 
        printf("print_msg: p is NULL\n");
        return;
    }
    printf("Name:%s, Sex:%c, Age:%d, Salary:%0.2f, Date:%s\n",
           p->name, p->sex, p->age, p->salary, p->date);
}

指针定义、初始化与动态内存管理

指针在使用前必须明确其状态。未初始化的指针指向随机地址,极其危险。同时,涉及内存分配时必须遵循严格的流程。

第1步:指针的定义与初始化

定义指针后应立即赋予确定值,通常为有效地址或 NULL。

// 错误示范:未初始化
int* p; 

// 正确做法1:初始化为NULL
int* p = NULL; 

// 正确做法2:指向现有变量
int i;
p = &i;

第2步:动态内存申请(malloc)

使用 malloc 在堆区申请内存,必须强制转换为目标结构体指针类型。需注意,malloc 失败时返回 NULL。

关键操作: - 申请成功后方可使用。
- 必须进行判空检查,否则会导致程序崩溃。

STAFF_T* staff = NULL; // 定义并初始化为NULL

// 申请内存并转换类型
staff = (STAFF_T*)malloc(sizeof(STAFF_T)); 

// 严格检查是否成功
if (staff == NULL) {
    printf("malloc(STAFF_T) ERROR\n");
    return -1; // 或其他退出逻辑
}

第3步:处理嵌套指针成员

结构体中包含指针成员(如 char*)时,仅分配结构体本身的空间是不够的,还需为这些字符串成员单独分配内存。

// 为name字段分配20字节空间
staff->name = (char*)malloc(20 * sizeof(char));

// 可直接赋值字符串(编译器自动处理静态字符串驻留区引用)
staff->name = "duruofei";

// 或者使用strcpy复制到分配的内存块中
// strcpy(staff->name, "duruofei");

资源释放与防野指针

内存管理的最后一步同样重要。使用完动态分配的内存后,必须手动释放,并将指针置为空。

  • 释放内存:调用 free(p) 归还内存给系统。注意,释放结构体中的子指针(如 staff->name)需根据分配情况单独释放,本例简化展示整体释放场景。
  • 重置指针:free 仅释放内容,不改变指针本身的值。此时指针仍指向原地址(悬空/野指针)。若继续使用,可能导致不可预知的错误。
  • 操作规范:执行 free(staff); 后,务必紧跟 staff = NULL;。

完整运行示例

以下为整合上述要点的完整代码,展示了从定义、申请、赋值、传参到释放的全生命周期管理:

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

typedef struct Staff_t {
    char* name;
    char sex;
    short age;
    float salary;
    char* date;
} STAFF_T;

void print_msg(STAFF_T const *p);

int main() {
    int size;
    STAFF_T* staff = NULL;

    // 1. 申请结构体内存
    staff = (STAFF_T*)malloc(sizeof(STAFF_T)); 
    if (staff == NULL) {
        printf("malloc(STAFF_T) ERROR\n");
        return -1;
    }

    // 2. 打印内存占用大小(辅助调试)
    size = sizeof(STAFF_T);
    printf("STAFF_T size = %d\n", size);
    printf("SIZEOF:\n char*:%lu, char:%lu, short:%lu, float:%lu \n",
           sizeof(char*), sizeof(char), sizeof(short), sizeof(float));

    // 3. 为内部指针成员分配内存并赋值
    staff->name = (char*)malloc(20 * sizeof(char));
    staff->name = "duruofei"; // 简单赋值演示
    staff->sex = 'M';
    staff->age = 29;
    staff->salary = 15000;
    
    staff->date = (char*)malloc(20 * sizeof(char));
    strcpy(staff->date, "2021-12-09");

    // 4. 通过指针传递(只读保护)
    print_msg(staff); 

    // 5. 释放资源并清理指针
    free(staff->name);
    free(staff->date);
    free(staff); 
    staff = NULL; // 防止野指针

    printf("Hello World\n");
    return 0;
}

void print_msg(STAFF_T const *p) {
    if (p == NULL) {
        printf("print_msg: p is NULL\n");
        return;
    }
    printf("Name:%s, Sex:%c, Age:%d, Salary:%0.2f, Date:%s\n",
           p->name, p->sex, p->age, p->salary, p->date);
}

以上就是C语言结构体与指针使用注意事项的详细内容,更多关于C/C++结构体内容的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。