第8章 第4节:字符串与指针(课件)-《C语言程序设计》(电子工业出版社)上好课

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

内容正文:

C语言程序设计 电子工业出版社 8.4节:字符串与指针 字符串在内存中的存储方式 使用字符数组和字符指针变量两种方式引用字符串 熟练使用字符指针变量和字符数组编写简单的字符串处理程序 阅读和分析涉及字符串指针的 C 语言代码 培养严谨的逻辑思维和程序调试能力 提升对计算机内存模型的理解和抽象思维能力 知识目标 能力目标 素养目标 01 01 01 学习目标 目录 Part 01 教学导入 Part 02 知识讲授 Part 03 师生互动 Part 04 课堂练习 Part 05 课堂小结 教学导入:一个古老的传说 从前,有一张神秘的藏宝图,上面写着一行奇怪的字符: "X Marks The Spot" 这行字符,就是我们在编程世界里经常打交道的 ——“字符串” 地图的起点,是一个叫做start的地方。你,作为寻宝者,站在起点,手里拿着一个神奇的罗盘。 而这个罗盘,就是我们今天的主角 ——指针 教学导入:寻宝的两种方式 方式一:步步为营 你把地图上的每一个字符都抄在自己的笔记本上,从第一个字符'X'开始,依次查看每一个字符,直到找到最后一个字符't'。 • 你的笔记本就是一个字符数组。 • 你按顺序访问每个字符,就像通过数组下标访问元素。 方式二:直指核心 你使用罗盘,直接定位到地图上第一个字符'X'的位置。然后,罗盘会告诉你下一个字符在哪里,依此类推,直到找到终点。 • 你的罗盘就是一个字符指针。 • 它不存储字符,只存储字符的地址。 今天,我们就来学习这两种寻宝方式:如何通过指针引用字符串! 知识讲授 字符串与指针 字符串的表示形式 字符数组与字符串指针变量比较 第一部分 字符串的表示形式 知识讲授 知识讲授:字符串的本质 核心定义 在C语言中,字符串是由双引号括起来的字符序列,且在内存中会自动以特殊字符'\0'(ASCII码0)作为结束标志。 结束符 '\0' 的关键作用 它是字符串的“终止标记”,决定了程序从哪里停止读取。像strlen、printf等标准库函数都依赖它来判断字符串的实际有效长度。 存储空间计算 字符串在内存中占用的字节数 = 字符个数 + 1。额外的 1 个字节专门用来存放结束符'\0',这一点常被初学者忽略。 知识讲授:使用字符数组 ▍ 定义与初始化 字符数组是存储字符串最基础的方式。它本质上是一个char类型的数组,系统会自动在字符串末尾隐式添加结束符'\0'来标志字符串的终止。 // 方式 1:逐个字符手动赋值 (需自行管理长度) char str1[6];// 需预留空间给结束符 str1[0] = 'H'; str1[1] = 'e'; str1[2] = 'l'; str1[3] = 'l'; str1[4] = 'o'; str1[5] = '\0';// 必须手动添加结束符 // 方式 2:直接用字符串常量初始化 (更推荐) char str2[] = "Hello";// 自动添加'\0',数组长度自动为 6 // 等价于:char str2[6] = {'H','e','l','l','o','\0'}; 知识讲授:如何访问字符数组中的字符串? 01. 使用数组下标访问 #include <stdio.h> main() { char str[] = "Hello"; while (str[i] != '\0') printf("%c", str[i++]); } 💡 核心逻辑: 通过索引循环,逐一打印字符,直到遇到结束符'\0'。 02. 直接输出整个数组 #include <stdio.h> main() { char str[] = "Hello"; // 使用 %s 格式符直接输出字符串 printf("%s ", str); } ⚡ 更优方案: 利用printf("%s", str)自动遍历并输出,代码更简洁。 重要概念:数组名 str 代表了数组首元素的地址。当使用 printf("%s", str) 时,程序会自动从该地址开始逐个输出字符,直到在内存中检测到字符串结束符 '\0' 才停止。 知识讲授:使用字符指针变量 定义与初始化 我们可以定义一个字符指针变量,让它直接指向一个字符串常量的首地址,从而实现对字符串的访问。 /* 将字符串常量 "Hello" 的首字符 'H' 的地址赋给指针变量 p */ char *p ="Hello"; 关键点:变量p本身存储的是一个内存地址,并不存储字符串内容。而 "Hello" 是字符串常量,通常存储在程序的只读数据区。 知识讲授:字符指针访问字符串的方法 方法 01 · 使用指针移动 #include <stdio.h> main() { char *p = "Hello";//循环直到指针指向的内容是'\0' while (*p != '\0') { printf("%c", *p); //输出当前指向的字符 p++; //指针自增,指向下一个字符 } printf(" ");} 输出结果:Hello 核心逻辑:通过 `*p` 取值,通过 `p++` 移动指针 方法 02 · 直接输出字符串 #include <stdio.h> main() {char *p = "Hello"; /*使用%s格式符直接输出, 它会自动从指针指向的地址开始, 逐个输出直到遇到 '\0' 结束 */ printf("%s ", p); } 输出结果:Hello 核心逻辑:利用 %s 格式符自动处理字符串输出 知识讲授:输出字符串的三种方法 程序文本:输出字符串的三种方法 #include<stdio.h> main() { char string[] ="I love China!";// 初始化字符串 char *p1=NULL,*p2=NULL;int i; // 方法1:下标法 | 方法2:数组名法 | 方法3:指针变量法 for(i=0; string[i]!='\0'; i++) printf("%c", string[i]); /* 逐一访问数组元素 */ printf(" "); for(p1=string; p1<string+13; p1++) printf("%c", *p1); /* 数组名隐式转换为指针 */ printf(" "); for(p2="I love China!"; *p2; p2++) printf("%c", *p2);} /* 指针直接指向常量字符串 */ 知识讲授:输出字符串的三种方法 背诵记忆 字符串引用的两种方式 ▍ 字符数组: `char str[] = "Hello";` • 内容直接存储在数组分配的内存中。 • 数组名 `str` 是地址常量,不可改变指向。 ▍ 字符指针: `char *p = "Hello";` • 指针变量 `p` 存储字符串常量的首地址。 • `p` 是变量,可以灵活指向不同的字符。 `'\0'` 的关键作用 它是 C 语言中字符串结束的唯一标志。在内存中它对应 ASCII 码值为 0 的空字符。 直接决定程序行为: 1.`strlen()`:返回从首地址到 `'\0'` 之前的字符个数,不包含它本身。 2.`printf("%s")`:从起始指针开始输出字符,直到遇到 `'\0'` 停止。 `*` 与 `++` 操作符 `*p` : 解引用 访问指针变量 `p` 中存储的地址所指向的内存单元内容,即“透过地址找值”。 `p++` : 指针移动 将指针指向的地址向后移动一个单位。对于 `char*` 类型,即向后移动一个字节,指向内存中的下一个字符。 例题分析:这段代码输出什么? #include <stdio.h> main() { char str[] = "Programming"; char *p = str; p += 3; printf("%s ", p); } 🔍 一步步拆解逻辑 1. 定义字符数组 `str`,存储字符串 "Programming"。 2. 指针变量`p`被赋值为数组首地址,即指向第一个字符`'P'`。 3. `p += 3`:指针向后移动3个`char`长度,指向第4个字符 `'g'`。 4. `printf` 遇到`%s`会从指针当前指向的地址开始输出,直到遇到`\0`。 💡 核心考点回顾 在 C 语言中,字符串本质上是以 `\0` 结尾的字符数组。 当指针指向字符串时,移动指针即改变了字符串输出的起始位置。这是指针操作中非常经典的基础应用场景,需熟练掌握指针的加减运算含义。 正确输出结果 gramming 例题分析 课堂问答 Q1:字符串 "C Language" 在内存中占用多少个字节? A. 10 B. 11 C. 12 D. 不确定 Q2:执行 `char *p = "Hello"; p++` 后,`*p` 的值是什么? A. 'H' B. 'e' C. 地址值 D. 不确定 答案:C. 12 解析:"C Language" 包含11个可见字符,在C语言中字符串是以 `'\0'` 作为结束标志的,这个结束符也占用一个字节,所以总共占用12个字节。 答案:B. 'e' 解析:指针变量 `p` 初始指向字符串常量 `"Hello"` 的第一个字符 `'H'` 的地址。执行 `p++` 后,指针向后移动一个 `char` 类型的长度(即1个字节),指向了第二个字符 `'e'` 的地址。`*p` 是取指针指向的内容,因此结果是 `'e'`。 课堂练习(一):字符串逆序输出 题目要求 请编写一个 C 语言程序,核心要求是: • 必须使用字符指针 (char*)实现 • 处理输入字符串:"Hello World" • 将其完全逆序并打印输出 预期输出 程序运行后,控制台应打印: dlroW olleH 解题思路提示 Step 1. 定位终点 利用指针遍历,直到找到字符串结束标志'\0'。 Step 2. 逆向遍历 回退指针指向最后一个有效字符,然后通过递减指针,从后向前逐个输出字符。 课堂练习(一):字符串逆序输出 程序文本:字符串逆序输出 #include<stdio.h> main() { char str[]="Hello World"; char *p = str; // 步骤1:让指针p指向字符串末尾的'\0' while(*p!='\0') { p++; } // 步骤2:回退一步指向最后一个有效字符 p- -; // 步骤3:从后向前输出直到开头 while(p >= str) { printf("%c", *p); p- -; } } 课堂练习(一):字符串逆序输出 课堂练习(二):统计字符个数 题目要求 不使用strlen函数,使用字符指针编写一个程序,统计以下字符串中包含的字符个数(注意:不包含字符串结束符 '\0'): "Pointer is powerful" 预期输出 The length is:19 解题思路 01. 初始化:定义并初始化一个整型变量 count 为 0,作为字符计数器。 02. 循环遍历:利用 while 循环,让指针不断后移,判断指针指向的内容是否为 '\0'。每访问一个有效字符,计数器加 1。 课堂练习(二):统计字符个数 程序文本:统计字符个数 #include<stdio.h> main() { char str[ ]="Pointer is powerful"; char *p = str; int count = 0; // 遍历字符串,直到遇到结束符 while(*p != '\0') { count++;// 计数器加1 p++;// 指针指向下一个字符 } printf("The length is: %d ", count); } 课堂练习(二):统计字符个数 第二部分 知识讲授 字符数组与字符串指针变量比较 知识讲授 知识讲授:字符指针 vs 字符数组 ? 我们已经学习了两种引用字符串的方式。它们可以互相替代吗?在什么情况下该用哪一种? char str[] = "Hello"; 字符数组 char *p = "Hello"; 字符指针 这节课,我们将深入剖析它们之间的区别。 区别一:存储内容与位置不同 char str[] = "Hello"; 📦 存储内容:数组 `str` 在栈区分配连续内存,直接存储字符内容(含结束符 `'\0'`)。 💡 核心本质:是一个字符集合,本身就是内容的载体。 char *p = "Hello"; 📍 存储内容:指针变量 `p` 存储的是一个地址值,指向存储在只读数据区的字符串常量。 💡 核心本质:是一个地址,它只是指向内容的“路标”。 区别二:赋值操作的灵活性不同 字符数组 初始化可以,但整体赋值不行! // 正确:初始化时赋值 char str[10] = "Hello"; // ❌ 错误:不能用赋值语句给数组整体赋值 str = "Hi"; // 数组名str是地址常量,无法被赋值 字符指针 非常灵活,可以随时改变指向! // 正确:初始化指向字符串常量 char *p = "Hello"; // ✅ 正确:指向另一个字符串常量 p = "Hi"; // 改变指针变量的指向 核心结论:指针本质是一个变量,存储内存地址,所以可以随时重新赋值改变指向;而数组名是一个地址常量,其值不可修改。 区别三:内容的可修改性不同 字符数组:内容通常可修改 char str[] = "Hello"; str[0] = 'h'; // 正确!此时 str 内容变为 "hello" // 数组空间分配在栈上,可读可写 ✅ 原因:字符数组在栈上分配了独立且连续的内存空间,属于程序运行时的“可写”区域,所以可以通过下标自由修改其中的字符。 字符指针:指向常量通常不可修改! char *p = "Hello"; *p = 'h'; // ❌ 严重错误!程序可能崩溃 // "Hello" 是只读内存中的字符串常量 🚫 原因:指针指向的字符串常量存储在程序的“只读数据区”(RODATA)。尝试写入只读内存会触发操作系统的内存保护机制,导致程序异常终止。 重要提醒:在C语言开发中,请务必养成习惯,切勿尝试修改字符指针指向的字符串常量内容! 区别四:初始化细节 字符数组 // 显式指定大小,但字符串过长 char str[5] = "Hello"; ⚠️警告:字符串长于数组大小,导致截断。 str = {'H','e','l','l','o'},缺少 '\0' 结束符! 这会导致后续的字符串操作行为未定义。 字符指针 // 指针指向只读数据区的字符串常量 char *p = "Hello"; ✅ 安全:指针 p 仅存储字符串首字符的地址,不关心字符串的实际长度。系统自动维护了结束符。 核心总结: 使用字符数组时,必须手动保证数组的物理空间足够容纳所有字符和结束符 `\0`;而字符指针无需操心内存分配,直接指向字符串存储位置即可。 知识讲授:字符指针 vs 字符数组 程序文本 #include<stdio.h> main() { char str[] ="I am happy!"; char *p="I am student!"; printf("str = %s ", str); printf("p = %s ", p); str[7] = 'H';// 正确,修改数组内容 //*p = 'H'; // 错误!试图修改字符串常量 printf("str = %s ", str); printf("p = %s ", p); } 思考时刻 如果我们在代码中取消对这一行的注释: *p = 'H'; 再次运行程序,你认为会发生什么现象?为什么? 知识讲授:字符指针 vs 字符数组 背诵记忆 字符数组 `char str[]` 存储内容:存储字符串的内容 存储位置:程序运行时的临时内存区,拥有独立的可写空间 可赋值性:数组名是地址常量,不能被整体赋值或修改指向 灵活性:内容可直接修改,但需注意数组长度限制,防止越界。 字符指针 `char *p` 存储内容:存储字符串的首元素地址 存储位置:指针本身在临时内存区,但它指向的字符串常量通常存放在程序的只读区域 可赋值性:指针变量本身是变量,可随时指向不同的字符串或地址 灵活性:无需担心数组大小限制,指向灵活,但直接修改指向的字符串内容可能引发程序崩溃。 课堂问答 01以下哪种写法可以正确修改字符串的第一个字符为 'x'? A. char str[] = "test"; str[0] = 'x'; B. char *p = "test"; *p = 'x'; C. char *p; *p = 'x'; D. char str[3] = "test"; str[0] = 'x'; ✅ 正确答案:A • B错误,试图修改只读的字符串常量,会导致程序崩溃。 • C错误,指针 p 未初始化,属于“野指针”,直接赋值非法。 • D错误,数组长度为3,无法容纳"test"及末尾的结束符'\0'。 02`char str[] = "abc";` 和 `char *p = "abc";` 中,`str` 和 `p` 的本质区别是什么? A. 没区别,都是字符串 B. str 是数组,p 是指针 C. str 是常量,p是变量 D. B 和 C 都对 ✅ 正确答案:D • 数组名 `str` 是地址常量,它的值不能改变,且指向一块可写的内存。 • 指针变量 `p` 是变量,可以指向任何地方,但它指向的是只读的字符串常量区。 • 两者在使用上有很多相似性,但本质完全不同。 例题分析:这段代码有问题吗? #include <stdio.h> main() { char *p; p[0] = 'H'; p[1] = 'i'; p[2] = '\0'; printf("%s ", p); } 🔍 错误分析 1.野指针风险:定义了指针 `p` 但未初始化,它指向的是随机的、不确定的内存地址。 2.非法写入:直接通过 `p[0]` 向未知地址写入数据,这是非法的内存访问。 3.后果严重:会触发**未定义行为**,最常见的是程序崩溃。 ✅ 正确做法 使用指针前,必须让它指向一块有效的、可写的内存空间。 💡 例如:分配堆内存(malloc) 或 指向内存中已存在的数组/变量。 课堂练习(一):代码纠错 📝 题目要求 下面的代码试图将字符串 "Hello" 改为 "Jello",但运行时会出现错误。请找出逻辑错误并修正它。 #include <stdio.h> main() { char *str ="Hello"; str[0] ='J'; printf("%s ", str); } 🔍 错误分析 指针指向了“只读”的字符串常量 `char *str = "Hello";` 这段代码使得指针 `str` 指向了存储在只读内存段中的字符串常量。 试图修改只读内存导致未定义行为 `str[0] = 'J';` 试图直接修改字符串常量的值,这会导致程序崩溃或出现未定义行为。 课堂练习(一):修正方案 方法一:使用字符数组 #include <stdio.h> main() { // 使用字符数组,内容存储在可写内存区 char str[] = "Hello"; str[0] = 'J';// 正确修改 printf("%s ", str);// 输出 Jello } 课堂练习(一):修正方案 方法二:让指针指向字符数组 #include <stdio.h> main() { char buffer[] = "Hello"; // 字符串存储在数组中 char *str = buffer;// 指针指向数组 *str = 'J';// 通过指针修改数组内容 printf("%s ", str);// 输出 Jello } 课堂练习:概念辨析 题目要求:判断下列说法的正误,并说明理由。 01 `char str[]="abc";`和 `char *p="abc";`完全等价 思考:内存分配方式一样吗? `str` 是数组名,`p` 是指针变量,二者在内存中的存储性质有何不同? 02 字符指针变量只能指向字符串常量 思考:指针的本质是地址。 字符指针是否也可以指向一个字符变量,或者字符数组中的某个元素? 03 数组名可以看作是一个指向数组第一个元素的常量指针。 思考:为什么说它是“常量”指针? 既然是指针,它具备哪些指针的特性?又有哪些不同之处? 课堂练习(二):参考答案 1. 错误 理由:它们在存储方式、可赋值性、内容可变性上都有本质区别。`str`是存储字符的数组,`p`是存储地址的指针。 2. 错误 理由:字符指针非常灵活,它可以指向任何`char`类型的内存地址,包括字符数组的元素、动态分配的内存等。 3. 正确 理由:数组名在大多数表达式中会隐式转换为指向其首元素的指针,且这个指针的值不能被改变(即常量指针)。例如,`str`和`&str[0]`的值是相等的。 课堂小结 字符串的本质 以'\0'结尾的字符序列,是C语言处理文本数据的基础。 两种引用方式 •字符数组:栈区存储,可修改 •字符指针:存地址,灵活,常指向只读区 记住:数组是家,里面住着人(字符);指针是地图,告诉你家在哪里。 指针核心操作 •*p: 解引用,访问指针指向的字符 •p++: 指针移动,遍历整个字符串 课堂小结 课后任务 基础巩固 · 熟练操作 01.字符串大写转小写:编写程序,使用字符指针将字符串 "HELLO WORLD" 中的所有大写字母转换为小写字母并输出。 02.字符串内容复制:编写程序,使用字符数组存储一个字符串,然后使用字符指针将其内容完整复制到另一个字符数组中。 进阶提升 · 深入思考 03.统计特定字符个数:编写程序,使用字符指针统计字符串 "Pointer is powerful" 中字母 'o' 出现的次数。 ★ 04. (挑战)判断回文字符串:编写程序,使用字符指针判断字符串 "abba" 是否为回文字符串(即正读和反读都一样)。如果是,输出 "Yes",否则输出 "No"。 谢谢观看 THANKS $

资源预览图

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