第9章 第4节:结构体指针(课件)-《C语言程序设计》(电子工业出版社)上好课

2026-06-29
| 45页
| 40人阅读
| 0人下载
精品

内容正文:

C语言程序设计 电子工业出版社 9.4节:结构体指针 理解结构体指针的概念,掌握其定义与使用方 熟练运用->运算符访问结构体成员 能够运用结构体指针编写程序,实现对结构体的高效操作 能够分析和调试包含结构体指针的C语言程序 培养严谨的逻辑思维和程序设计能力 养成良好的编程习惯和代码规范意识 知识目标 能力目标 素养目标 01 02 03 学习目标 目录 Part 01 教学导入 Part 02 知识讲授 Part 03 师生互动 Part 04 课堂练习 Part 05 课堂小结 教学导入:温故知新 回顾:指针的本质 指针是一个特殊的变量,它的值存储的不是普通数据,而是**另一个变量的内存地址**。 在之前的课程中,我们已经掌握了指向基础数据类型(如int,float,char)的指针用法。 🤔 思考题: 如果一个变量的结构本身非常复杂(例如一个包含姓名、学号、成绩的学生信息),也就是一个“结构体”,我们该如何定义指针去指向它? 回顾:结构体的本质 结构体是一种**用户自定义的复合数据类型**,它打破了单一类型的限制,允许将多个不同类型的数据“打包”在一起,形成一个整体。 struct Student { long num; // 学号 char name[20]; // 姓名 char sex; // 性别 float score; // 成绩 }; 💡 关键提示:结构体变量在内存中占据一块连续的存储空间。 教学导入:问题引入 📝 场景模拟 假设处理一个包含1000个学生信息的数组,传统做法是传递整个结构体: void printStudent(struct Student s) { printf("%ld,%s,%c, %f ",s.num,s.name,s.sex,s.score);} 这样做有什么缺点? 每次调用函数,都需要复制整个结构体的数据到新的内存空间。 当结构体很大(如包含多个数组、字符串),或者要处理的数组元素数量很多时,会产生巨大的内存开销,并浪费大量CPU时间在数据拷贝上,导致程序效率低下。 解决方案 只需要将结构体变量的地址传递给函数。 函数直接通过地址访问和操作原数据,避免了任何不必要的数据复制,节省内存且效率极高。 今天的主角: 结构体指针 教学导入:课程导航 本节课我们将深入学习结构体与指针的结合应用,掌握两大核心场景: 01指向结构体变量的指针 • 如何定义一个指向结构体变量的指针? • 如何通过指针访问结构体的成员? • 核心运算符`->`的使用与优先级解析 02指向结构体数组的指针 • 如何使用指针高效遍历结构体数组? • 指针在结构体数组中移动的步长逻辑 • 开发中的常见易错点与调试注意事项 知识讲授 结构体指针 指向结构体变量的指针 指向结构体数组的指针 第一部分 指向结构体变量的指针 知识讲授 知识讲授:结构体指针的定义 什么是结构体指针? 它是一个指向结构体变量的指针,其核心作用是存储结构体变量在计算机内存中的**起始地址**,通过它可以间接访问结构体变量中的数据。 标准语法格式 在定义指针变量时,必须明确指出它指向的结构体类型: struct 结构体名 *指针变量名; 💻 代码示例 // 1. 先定义结构体类型 struct Student { long num; char name[20]; float score; }; // 2. 再定义结构体变量 struct Student stu_1; // 3. 最后定义指向该类型的指针 struct Student *p; ⚠️ 核心要点 指针变量的类型,必须与它要指向的**结构体变量类型**完全一致,就像一把钥匙只能开一把锁,不能混用。 知识讲授:让指针指向结构体变量 核心操作 使用 C 语言的取地址运算符 &,将结构体变量在内存中的起始地址,直接赋值给同类型的结构体指针变量。 内存逻辑 指针变量p中存储了stu_1的起始地址。建立联系后,我们就能通过指针p间接访问并操作stu_1的所有成员数据。 程序文本【9.10】指向结构体变量的指针 struct student { int num; char ename[20]; char sex; int age; float score; char addr[30]; } ; struct student stu_1= {1,"cui lin",'M',19,86.4,"shanghai"}; struct student *p=&stu_1; 知识讲授:访问结构体成员的三种方式 前置假设:struct Student stu_1 = {10101, "Li Lin", 'M', 89.5}; struct Student *p = &stu_1; 方式一:直接访问 (使用 . 运算符) 💡 语法规则: 结构体变量名 . 成员名 📝 代码示例: printf("Name: %s ", stu_1.name); 方式二:间接访问 (使用 (*指针).成员名) 语法:(*指针变量名).成员名 解释:p 表示指针 p 指向的变量 stu_1,再用“.”访问成员。 ⚠️ 注意: p 两侧的括号不可省略!因为“.”的优先级高于“*”。 示例:printf("Name: %s ", (*p).name); 知识讲授:访问结构体成员的第三种方式(重点) 方式三:间接访问 (使用 -> 运算符) 核心语法:指针变量名 -> 成员名 这是C语言为指针访问结构体成员提供的“专用语法糖”。它同时结合了取值运算 (*)和直接成员访问 (.)的双重功能,简化书写。 p->name ≡ (*p).name printf("Name: %s ", p->name); 为什么推荐使用 ->? 代码更简洁,可读性更高 相比需要频繁使用括号的 (*p).name,p->name 的书写更顺手,一眼就能看出是通过指针访问成员,语义清晰。 避免复杂嵌套的括号混乱 在处理“指向结构体的指针的指针”(二级指针)等复杂场景时,-> 能极大减少括号数量,降低代码出错率。 知识讲授:变量成员形式用以下三种形式表示等价 程序文本【9.10】指向结构体变量的指针 struct student { int num; char ename[20]; char sex; int age; float score; char addr[30]; } ; struct student stu_1= {1,"cui lin",'M',19,86.4,"shanghai"……}; struct student *p=&stu_1; 知识讲授:三种方式的等价性总结 假设有定义:struct Student stu_1; struct Student *p = &stu_1;,以下三种访问结构体成员的方式完全等价: stu_1.num 直接通过结构体变量名访问 (*p).num 先对指针解引用,再用点号访问 (注意:圆括号不可省略!) p -> num 通过指针直接访问(最推荐写法) 可读性高,书写更简洁 💡 核心记忆口诀 1.变量用点(.),指针用箭头(->)—— 分清“变量”与“指针”身份。 2. 如果想用指针配合点号,一定要记得加星号和括号((*p).) —— 养成良好的代码习惯。 背诵记忆 01. 定义 struct 结构体名 *指针名; 声明一个指向结构体类型的指针变量,用于存储结构体变量的地址。 02. 赋值 指针名 = &结构体变量名; 使用取地址运算符 `&` 获取结构体变量的地址,并赋值给对应的指针变量。 03. 访问 • 结构体变量访问成员: . (点运算符) • 结构体指针访问成员: -> (箭头运算符) 💡 等价关系: 指针->成员 ≡ (*指针).成员 程序文本:指向结构体指针变量的定义、输入和输出 #include <stdio.h> struct student { char xh[3], xm[10]; int cj; }s ={"10","王强",85 }; main( ) { struct student *p; p= &s; printf(" 学号 姓名 成绩 "); printf("%7s%7s%7d ",s.xh,s.xm,s.cj ); printf("%7s%7s%7d ",(*p).xh,(*p).xm,(*p).cj ); printf("%7s%7s%7d ",p->xh,p->xm,p->cj ); } 例题分析 1 例题分析 1:指向结构体指针变量的定义、输入和输出 例题分析 2 程序文本:通过指向结构体变量的指针变量输出结构体变量中成员的信息 #include <stdio.h> #include <string.h> int main() {struct student { long num; char name[20]; char sex; float score; }; struct student stu_1; // 定义struct student类型的变量stu_1 struct student * p; // 定义指向struct student 类型数据的指针变量p p=&stu_1; // p指向stu_1 stu_1.num=10101; // 对结构体变量的成员赋值 strcpy(stu_1.name,"Li Lin"); stu_1.sex='M'; stu_1.score=89.5; printf("No.:%ld name:%s sex:%c score:%5.1f ",stu_1.num,stu_1.name,stu_1.sex,stu_1.score); printf(" No.:%ld name:%s sex:%c score:%5.1f ",(*p).num,(*p).name,(*p).sex, (*p).score); } 例题分析 2 课堂问答 Q1. 指针访问结构体成员 struct Person { int age; char name[10];} person1, *p = &person1; 请问以下哪个语句可以正确地将 person1 的年龄设置为 20? A. p.age = 20; B. *p.age = 20; C. (*p).age = 20; D. p->age = 20; 正确答案:C、D Q2. 语法对比与推荐 `(*p).name` 和 `p->name` 是否完全等价? 为什么推荐在代码中使用后者? 是完全等价的。 推荐使用->的原因: 1.代码更简洁:少了一对括号,视觉干扰更少。 2.可读性更高:一眼就能识别是指针访问,尤其在多层嵌套的复杂结构体指针中优势极其明显。 课堂练习 1 📝 练习题目 定义一个结构体Point,包含两个整型成员x和y。编写程序,定义一个 `Point` 类型的变量 `p1` 并初始化其坐标为 (3, 4)。 然后定义一个指向 `Point` 的指针 `pp`,使其指向 `p1`。最后,通过指针 `pp` 将 `p1` 的坐标修改为 (5, 6),并分别使用`.`、`(*pp).` 和 `pp->`三种方式输出修改后的坐标。 💡 提示: 理解坐标点在内存中的表示,以及如何通过不同的语法访问结构体成员。 课堂练习 1 程序文本 #include<stdio.h> struct Point{ int x, y; }; int main() { struct Point p1 = {3, 4}; struct Point *pp = &p1; // 指向结构体变量 pp->x = 5; pp->y = 6; // 修改值 printf("Using . : (%d, %d) ", p1.x, p1.y); printf("Using (*pp).:(%d, %d) ",(*pp).x,(*pp).y); printf("Using -> : (%d, %d) ", pp->x, pp->y); return 0; } 课堂练习 1 课堂练习 2 📝 编程任务 任务要求: 1. 定义一个结构体Book,包含三个成员:书名 `title`、作者 `author`、价格 `price`。 2. 声明一个 `Book` 类型的变量 `book1`,并定义一个指向它的指针变量。 3.仅通过指针为 `book1` 赋值:书名 "C Programming",作者 "K&R",价格 58.5。 4.仅通过指针将书籍的完整信息打印输出。 课堂练习 2 程序文本 #include<stdio.h> #include<string.h> struct Book { char title[50]; char author[30]; float price; }; int main() { struct Book book1; struct Book *p = &book1; // 指针赋值: 注意字符串用 strcpy strcpy(p->title,"C Programming"); strcpy(p->author,"K&R"); p->price =58.5; printf("Title: %s Price: %.2f ", p->title, p->price); return 0; } 课堂练习 2 第二部分 知识讲授 指向结构体数组的指针 知识讲授:指向结构体数组的指针 01 / 定义与赋值 struct Student stu[3] = { ... }; struct Student *p; p = stu; // 将数组首元素地址赋给指针 p // 等价于:p = &stu[0]; 💡 核心原理: 数组名 `stu` 是一个指向数组第一个元素的**常量指针**。因此,直接将 `stu` 赋值给指针变量 `p`,就实现了指针与数组的关联,这是C语言中最常用的写法。 02 / 内存映射示意图 📍 映射逻辑: • `p` ➔ 指向数组第 1 个元素 `stu[0]`|• `p+1` ➔ 指向数组第 2 个元素 `stu[1]` • `p+i` ➔ 指向数组第 i+1 个元素 `stu[i]` 知识讲授:指针的移动 `p++` 的含义 当指针 `p` 指向一个结构体数组的元素时,执行 `p++` 操作,指针的值并不会简单地加 1,而是会增加一个结构体的整体长度。 举个例子:假设一个 `struct Student` 类型的元素占用 32 字节,那么执行 `p++` 后,指针 `p` 的值会直接增加 32,从而精准地指向数组中的下一个元素。 遍历数组的实现 for(p = stu; p < stu + 3; p++) { // 访问指针指向的当前元素 printf("%s ", p->name); } 利用指针移动的特性,我们可以在循环中直接通过指针的自增操作,轻松地遍历整个结构体数组,比使用数组下标访问更高效、更简洁。 知识讲授:易错点讲解 典型误区 · 错误用法 p = stu[0].name;// 错误!类型不匹配 ❓ 为什么会报错? •stu[0].name是一个char *类型,指向字符串的第一个字符。 •指针 p被定义为struct Student *类型,用于指向结构体。 不同类型的指针不能直接赋值,这是初学者最容易混淆的地方。 核心概念 · 正确理解 结构体指针p的核心职责是指向一个完整的结构体对象,而非对象中的某一个成员变量。 💡 如果强行赋值,必须进行强制类型转换,但这通常会破坏程序逻辑,且无法通过指针访问结构体的其他成员。 例题分析:指向结构体数组的指针 程序文本【9.11】指向结构体数组的指针 #include<stdio.h> #include<string.h> struct student { int num; char ename[20]; char sex; int age; float score; char addr[30]; }; struct student stu[3]={{1,"Cui Lin",'M',19,86.4,"Shanghai"}, {2,"Zhou Li",'F',19,76.6,"Nanjing"},{3,"Chengyan",'F',18,92.5,"Nanchang"}}; main() { struct student *p; //定义指向结构体数组的指针 p=stu; //指针p指向结构体数组首地址 for(p=stu;p<stu+3;p++) printf("%d,%s,%c,%d,%.2f,%s ",p->num,p->ename,p->sex,p->age,p->score,p->addr); } 例题分析:指向结构体数组的指针 例题分析:指向结构体数组的指针 课堂问答 Q1:循环边界辨析 在例9.11中,如果将for循环的条件改为p <= stu + 2,程序还能正确运行吗?为什么? 答案:能。因为stu + 2正好是最后一个元素stu[2]的地址。条件p <= stu + 2和原来的p < stu + 3的效果是完全一致的,都能遍历数组所有元素。 Q2:指针与数组的等价写法 假设有代码片段: struct Student stu[5], *p = stu; 请问:表达式(p+2)等价于什么?(p+2)->num等价于什么? 答案:根据指针运算规则: 1.(p+2)等价于stu[2](指向数组的第3个元素) 2.(p+2)->num等价于stu[2].num(访问该元素的 num 成员) 背诵记忆 01 数组名即地址 结构体数组名代表数组首元素的地址,本质是一个指向结构体类型的指针常量。 02 指针赋值 执行`p = stu;`操作,即可使指针变量 `p` 指向结构体数组 `stu` 的第一个元素。 03 指针移动 执行`p++`时,指针将向后移动一个结构体长度,指向数组的下一个完整元素。 04 访问元素成员 使用`p->member`或`(*p).member`两种方式,访问指针当前指向元素的指定成员。 05 核心禁忌 严禁将结构体成员的地址直接赋值给结构体类型指针,类型不匹配会导致逻辑错误。 课堂练习:寻找高薪员工 📝 编程挑战:寻找高薪员工 1. 定义一个结构体Employee,包含id (工号)、name (姓名)、salary (工资)三个字段。 2. 创建并初始化一个包含 4 个员工信息的结构体数组。 3. 使用结构体指针遍历数组,找出薪资最高的员工。 4. 打印出该员工的完整个人信息。 课堂练习:寻找高薪员工 程序文本 #include<stdio.h> struct Employee { int id; char name[20]; float salary; }; int main() { struct Employee emp[4] = {{101,"Alice",8500}, {102,"Bob",9200},{103,"Job",9000},{104,"Kelly",19200}}; struct Employee *p, *max_emp = emp; // 初始化指针 for(p = emp; p < emp+4; p++) if(p->salary > max_emp->salary) max_emp = p; printf("最高薪员工: %s (ID: %d), 薪资: %.2f ",max_emp->name,max_emp->id,max_emp->salary); } 课堂练习:寻找高薪员工 课堂练习:冒泡排序 📝 题目要求 使用结构体指针,将一个结构体数组中的元素,按照结构体内部的 `num`(学号)字段,从小到大进行排序。 课堂练习:冒泡排序 程序文本 #include<stdio.h> struct Student { int num; char name[20]; }; int main() { struct Student stu[3] = {{103, "Tom"}, {101, "Jerry"}, {102, "Mike"}}; struct Student *p, *q, temp; printf("排序前: "); // 输出:排序前的结构体数组 for (p = stu; p < stu + 3; p++) printf("学号:%d\t姓名:%s ", p->num, p->name); for(p = stu; p < stu + 2; p++) // 核心:指针操作结构体进行冒泡排序与交换 for(q = p+1; q < stu+3; q++) if(p->num > q->num) { temp = *p; *p = *q; *q = temp; } printf(" 排序后: ");// 输出:排序后的结构体数组 for (p = stu; p < stu + 3; p++) printf("学号:%d\t姓名:%s ", p->num, p->name); } 课堂练习:冒泡排序 课堂小结 指向结构体变量的指针 掌握结构体指针的定义与赋值方法,重点理解并区分通过 `->` 和 `(*p).` 两种方式来访问结构体的成员变量。 指向结构体数组的指针 学会利用指针遍历结构体数组,深入理解指针 `p++` 的移动逻辑,即移动一个“结构体元素”所占的字节数,实现高效的数据遍历。 💡 核心思想 指针本质是一种“间接访问”内存的手段。对于复杂的结构体类型,直接传递指针比复制整个结构体更节省内存开销,同时让程序逻辑更灵活、执行效率更高。 🚩 核心原则 “变量用点,指针用箭头” 区分访问方式:结构体变量名使用 `.`,指针变量使用 `->` 课堂小结 课后任务 01 基础题 编写一个程序,定义一个表示矩形的结构体Rectangle,包含width和height。 定义一个结构体变量,并使用指针计算并输出该矩形的周长和面积。 02 进阶题 定义结构体Car,包含品牌(brand)、型号(model)和价格(price)。 创建含5个汽车信息的结构体数组并初始化。 用结构体指针遍历数组,找出价格最低的汽车并打印信息。 03 综合题 定义结构体Student,包含学号(num)、姓名(name)和两门课程成绩(score[2])。 创建含3个学生信息的结构体数组并初始化。 用结构体指针完成: 1. 计算并输出每个学生的平均分; 2. 按平均分对数组降序排序; 3. 输出排序后的完整信息。 谢谢观看 THANKS $

资源预览图

第9章 第4节:结构体指针(课件)-《C语言程序设计》(电子工业出版社)上好课
1
第9章 第4节:结构体指针(课件)-《C语言程序设计》(电子工业出版社)上好课
2
第9章 第4节:结构体指针(课件)-《C语言程序设计》(电子工业出版社)上好课
3
第9章 第4节:结构体指针(课件)-《C语言程序设计》(电子工业出版社)上好课
4
第9章 第4节:结构体指针(课件)-《C语言程序设计》(电子工业出版社)上好课
5
第9章 第4节:结构体指针(课件)-《C语言程序设计》(电子工业出版社)上好课
6
所属专辑
由于学科网是一个信息分享及获取的平台,不确保部分用户上传资料的 来源及知识产权归属。如您发现相关资料侵犯您的合法权益,请联系学科网,我们核实后将及时进行处理。