拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

指针与结构体:C 语言进阶核心详解

指针与结构体:C 语言进阶核心详解

1. 引言

在 C 语言的学习过程中,指针与结构体是两个绕不开的核心概念。指针让我们能够直接操作内存地址,而结构体则允许我们将不同类型的数据组合成一个整体。当这两者结合时,便诞生了 C 语言中最强大、也最让初学者头疼的用法——结构体指针。

本文将带你从基础出发,逐步深入理解指针与结构体的关系,掌握结构体指针的定义、初始化、访问方式,以及它在链表、动态内存分配等场景中的典型应用。

2. 结构体基础回顾

在讨论指针之前,我们先快速回顾一下结构体的基本用法。

2.1 结构体的定义

structStudent{charname[50];intage;floatscore;};

2.2 结构体变量的声明与初始化

structStudentstu1={"张三",20,89.5};structStudentstu2;

2.3 通过点运算符访问成员

printf("姓名:%s\n",stu1.name);printf("年龄:%d\n",stu1.age);printf("成绩:%.1f\n",stu1.score);

3. 指针基础回顾

指针是存储变量地址的变量。理解指针,首先要理解地址与取地址运算符。

3.1 指针的声明与赋值

inta=10;int*p=&a;// p 存储变量 a 的地址

3.2 解引用运算符

printf("%d\n",*p);// 输出 10,*p 表示 p 指向的变量的值

4. 结构体指针

结构体指针,就是指向结构体变量的指针。它存储的是结构体变量在内存中的起始地址。

4.1 结构体指针的声明

structStudent*pStu;

4.2 结构体指针的初始化

structStudentstu1={"张三",20,89.5};structStudent*pStu=&stu1;

4.3 通过指针访问结构体成员

访问结构体指针所指向的成员,有两种方式:

方式一:先解引用,再使用点运算符

(*pStu).age=21;printf("年龄:%d\n",(*pStu).age);

方式二:使用箭头运算符(推荐)

pStu->age=21;printf("年龄:%d\n",pStu->age);

注意:pStu->age等价于(*pStu).age。箭头运算符->是 C 语言专门为结构体指针提供的语法糖,书写更简洁,也更不容易出错。

5. 结构体指针作为函数参数

将结构体指针作为函数参数传递,可以避免结构体整体拷贝带来的性能开销,同时允许函数直接修改原结构体的内容。

5.1 传递结构体变量(值传递)

voidprintStudent(structStudentstu){printf("姓名:%s\n",stu.name);}

这种方式会拷贝整个结构体,当结构体很大时效率较低。

5.2 传递结构体指针(引用传递)

voidupdateStudent(structStudent*pStu){pStu->age+=1;// 直接修改原结构体}intmain(){structStudentstu1={"张三",20,89.5};updateStudent(&stu1);printf("年龄:%d\n",stu1.age);// 输出 21return0;}

5.3 传递 const 指针保护数据

如果函数只需要读取结构体内容而不需要修改,可以加上const修饰,防止意外修改:

voidprintStudent(conststructStudent*pStu){printf("姓名:%s\n",pStu->name);}

6. 结构体指针与动态内存分配

结构体指针最常见的应用之一,就是配合malloc在堆上动态分配结构体内存。

#include<stdio.h>#include<stdlib.h>#include<string.h>structStudent{charname[50];intage;};intmain(){structStudent*pStu=(structStudent*)malloc(sizeof(structStudent));if(pStu==NULL){printf("内存分配失败\n");return1;}strcpy(pStu->name,"李四");pStu->age=22;printf("姓名:%s,年龄:%d\n",pStu->name,pStu->age);free(pStu);// 释放内存return0;}

注意:使用malloc分配的内存必须用free释放,否则会造成内存泄漏。

7. 结构体指针数组

结构体指针数组,即数组的每个元素都是一个指向结构体的指针。这在管理多个动态分配的结构体时非常有用。

structStudent*students[3];students[0]=(structStudent*)malloc(sizeof(structStudent));students[1]=(structStudent*)malloc(sizeof(structStudent));students[2]=(structStudent*)malloc(sizeof(structStudent));// 使用students[0]->age=20;students[1]->age=21;students[2]->age=22;// 释放for(inti=0;i<3;i++){free(students[i]);}

8. 结构体指针与链表

链表是结构体指针最经典的应用场景。每个节点是一个结构体,其中包含一个指向下一个节点的指针。

structNode{intdata;structNode*next;};

8.1 创建链表节点

structNode*createNode(intdata){structNode*newNode=(structNode*)malloc(sizeof(structNode));if(newNode==NULL){returnNULL;}newNode->data=data;newNode->next=NULL;returnnewNode;}

8.2 在链表头部插入节点

voidinsertAtHead(structNode**head,intdata){structNode*newNode=createNode(data);if(newNode==NULL)return;newNode->next=*head;*head=newNode;}

注意:这里使用了二级指针struct Node **head,因为我们需要修改头指针本身的值。

8.3 遍历链表

voidprintList(structNode*head){structNode*current=head;while(current!=NULL){printf("%d -> ",current->data);current=current->next;}printf("NULL\n");}

9. 常见错误与注意事项

9.1 未初始化指针就使用

structStudent*pStu;// 未初始化,指向未知地址pStu->age=20;// 错误!野指针

正确做法:要么指向一个已存在的结构体变量,要么用malloc分配内存。

9.2 忘记释放内存

structStudent*pStu=(structStudent*)malloc(sizeof(structStudent));// 使用完后忘记 free(pStu);

这会导致内存泄漏。务必在不再使用时调用free。

9.3 释放后继续使用(悬空指针)

free(pStu);pStu->age=20;// 错误!pStu 已成为悬空指针

释放后应将指针置为NULL:

free(pStu);pStu=NULL;

9.4 混淆->与.

  • 结构体变量用.访问成员:stu.age
  • 结构体指针用->访问成员:pStu->age

10. 总结

指针与结构体的结合是 C 语言进阶的重要里程碑。通过本文的学习,我们掌握了:

  • 结构体指针的声明、初始化与成员访问(->运算符)
  • 结构体指针作为函数参数的高效传参方式
  • 结构体指针配合malloc进行动态内存分配
  • 结构体指针数组与链表的典型应用
  • 常见错误与规避方法

掌握这些内容后,你就能更自如地编写高效、灵活的 C 程序,为后续学习数据结构与算法打下坚实基础。

返回列表