内容正文:
8.7节:指针应用实例
编程语言基础——C语言
同步精品课堂
高教版(第5版)
掌握国家标准《机械制图》中有关图幅、比例、字体图线等基本规定。
教学目标
一
03
灵活使用指针参数返回多个计算结果,实现通过指针返回奇数之和与偶数之和的功能
理解指针在复杂算法中的应用,能够编写函数为给定偶数寻找两个素数并通过指针返回结果
04
掌握指针作为函数参数传递数组和字符串的方法,能够编写函数完成字符串的查找和插入操作
02
综合运用指针变量、数组指针和字符串指针的知识,通过指针实现数组元素的逆序存放操作
01
教学重难点
二
03
正确使用指针参数实现函数的多返回值功能,掌握通过指针传递地址返回奇数之和与偶数之和的方法
理解素数判断算法的实现原理,能够通过指针参数正确返回满足条件的两个素数
04
灵活运用字符指针处理字符串的查找和插入,注意字符串结束符的处理和指针边界条件
02
熟练掌握指针作为函数参数对数组元素的操作,正确实现数组逆序存放的指针操作逻辑
01
导入新课
三
指针"魔术师"
指针的三大魔法
颠倒魔法:指针让数组元素瞬间倒序
搜索魔法:指针高效查找并插入字符
分解魔法:指针返回多个计算结果
"今天,我们将揭秘指针的三大'魔法',让编程变得神奇又高效!"
新知讲授
四
指针作为C语言的核心特性,能够实现高效的数据访问和灵活的内存操作。本节将通过五个典型实例,展示指针在数组逆序、字符串处理、多值返回和算法实现中的强大功能。从数组元素的倒序存放,到字符串的查找插入,再到素数分解问题,我们将全面体验指针在不同场景下的应用技巧。通过实践这些案例,你将深入理解指针作为函数参数的灵活性和高效性。
概述
新知讲授
四
知识点1:指针应用实例
例8-18:将数组a中的n个整数按相反顺序存放。
【分析】用数组作为参数。设两个变量i和j,i的初始值为0,j的初始值为n-1,a[i]与a[j]交换,然后做“i++,j--;”,再将a[i]与a[j]交换,“i++,j—;”,直到i>=n/2。
①初始状态
②a[i]与a[j]交换,“i++,j--;”
0 1 2 3 4 5
10 11 12 13 14 15
i=0 ↑j=n-1
0 1 2 3 4 5
15 11 12 13 14 10
↑i ↑j
新知讲授
四
知识点1:指针应用实例
例8-18:将数组a中的n个整数按相反顺序存放。
【分析】
③a[i]与a[j]交换,“i++,j--;”
④a[i]与a[j]交换,“i++,j--;”
⑤i>=n/2,结束。
0 1 2 3 4 5
10 14 12 13 11 15
↑i ↑j
0 1 2 3 4 5
15 14 13 12 11 10
↑j ↑i
新知讲授
四
知识点1:指针应用实例
例8-18:将数组a中的n个整数按相反顺序存放。
#include<stdio.h>
void invert(int b[ ],int n)
{ int tmp,i,j,m=n/2;
i=0; j=n-1;
for ( ;i<m;i++,j--)
{ tmp=b[i];
b[i]=b[j];
b[j]=tmp; } }
main ( )
{ int a[100], i, n;
printf ( " 输入数据个数:" );
scanf("%d", &n );
for ( i = 0; i < n; i++ )
scanf ( "%d" , &a[i] );
invert ( a, n );
printf ( "
反序输出:" );
for (i = 0; i < n; i++)
printf ( "%5d " , a[i] ); }
新知讲授
四
知识点1:指针应用实例
例8-19:改写例8-18中的函数invert(),用指针作为函数参数将数组a中的n个整数按相反顺序存放。
#include<stdio.h>
void invert ( int *p, int n )
{ int tmp, *i, *j;
i = p;
j = p + n - 1;
for ( ; i < j; i++, j-- )
{ tmp =*i;
*i =*j; *j =tmp; } }
main ( )
{ int a[100], i, n;
printf ( " 输入数据个数:" );
scanf("%d", &n );
for ( i = 0; i < n; i++ )
scanf ( "%d" , &a[i] );
invert ( a, n );
printf ( "
反序输出:" );
for (i = 0; i < n; i++)
printf ( "%5d " , a[i] ); }
新知讲授
四
知识点1:指针应用实例
编程1:给定程序的功能是判断字符ch是否与串str中某个字符相同:若相同,什么也不做;若不同,则插在串的最后。
【问题分析】
功能需求:判断字符ch是否在字符串str中存在
如果存在,不做任何操作
如果不存在,将ch追加到字符串末尾
注意:字符串以'\0'结尾,需要正确处理字符串操作
【算法设计】
遍历字符串str,检查字符ch是否已存在
如果找到相同字符,直接返回
如果未找到,将ch插入到字符串末尾
更新字符串结束符'\0'
新知讲授
四
知识点1:指针应用实例
编程1:给定程序的功能是判断字符ch是否与串str中某个字符相同:若相同,什么也不做;若不同,则插在串的最后。
#include <stdio.h>
#include <string.h>
void fun(char *str, char ch)
{ int i = 0;
// 检查ch是否已在str中
while (str[i] != '\0')
{ if (str[i] == ch) return;
// 字符已存在,直接返回
i++; }
str[i] = ch; // 插入字符
str[i+1] = '\0'; // 添加结束符
}
main()
{ char str1[100] = "hello";
char str2[100] = "world";
char ch1 = 'o';
char ch2 = 'x';
printf("测试1: str=\"%s\",ch='%c'
",str1,ch1);
fun(str1, ch1);
printf("结果: %s
", str1);
printf("测试2: str=\"%s\",ch='%c'
",str1,ch2);
fun(str1, ch2);
printf("结果: %s
", str1);
printf("测试3: str=\"%s\",ch='%c'
",str2,ch2);
fun(str2, ch2);
printf("结果: %s
", str2); }
新知讲授
四
知识点1:指针应用实例
编程2:试编写一个函数,分别求出数组a中所有奇数之和以及所有偶数之和。形式为:fun(int *a,int n,int *odd,int *even),其中形参n给出数组中数据的个数,利用odd返回奇数之和,利用evev返回偶数之和。
【问题分析】
功能需求:计算数组中奇数和与偶数和
输入:整型数组a,数组长度n
输出:通过指针返回奇数之和odd和偶数之和even
奇偶判断:a[i] % 2 == 0 为偶数,否则为奇数
【算法设计】
初始化odd_sum和even_sum为0
遍历数组a的每个元素
判断当前元素的奇偶性
分别累加到对应的和中
通过指针返回结果
新知讲授
四
知识点1:指针应用实例
编程2:试编写一个函数,分别求出数组a中所有奇数之和以及所有偶数之和。形式为:fun(int *a,int n,int *odd,int *even),其中形参n给出数组中数据的个数,利用odd返回奇数之和,利用evev返回偶数之和。
#include <stdio.h>
void fun(int *a, int n, int *odd, int *even)
{ int odd_sum = 0,i;
int even_sum = 0;
for (i = 0; i < n; i++)
if (a[i] % 2 == 0)
even_sum += a[i]; // 偶数累加
else odd_sum += a[i]; // 奇数累加
*odd = odd_sum; // 返回奇数之和
*even = even_sum; } // 返回偶数之和
main()
{ int arr1[] = {1, 2, 3, 4, 5, 6};
int arr2[] = {10, 21, 32, 43, 54};
int odd_sum, even_sum,n,i;
n = sizeof(arr1) / sizeof(arr1[0]);
printf("数组1: ");
for (i = 0; i < n; i++)
printf("%d ", arr1[i]);
fun(arr1, n, &odd_sum, &even_sum);
printf("
奇数之和: %d
", odd_sum);
printf("偶数之和: %d
", even_sum);
}
新知讲授
四
知识点1:指针应用实例
编程3:试编写函数fun,其功能是:为一个偶数寻找两个素数,这两个素数之和等于该偶数,并将这两个素数通过形参指针传回主函数。
【问题分析】
功能需求:将一个偶数分解为两个素数之和
输入:一个偶数num
输出:通过指针返回两个素数p1和p2
限制:num必须是偶数,需要素数判断函数
【辅助函数】
素数判断函数is_prime(int n)
检查n是否能被2到√n之间的数整除
【算法设计】
判断输入是否为偶数
从2开始遍历到num/2
对每个i,检查i和num-i是否都是素数
找到第一对满足条件的素数
通过指针返回结果
新知讲授
四
知识点1:指针应用实例
编程3:试编写函数fun,其功能是:为一个偶数寻找两个素数,这两个素数之和等于该偶数,并将这两个素数通过形参指针传回主函数。
#include <stdio.h>
int isPrime(int n) // 素数判断
{ int i;
for (i = 2; i * i <= n; i++)
if (n % i == 0) return 0;
return n > 1; }
void fun(int num, int *p1, int *p2) // 寻找素数对
{ int i;
for (i = 2; i <= num / 2; i++)
if (isPrime(i) && isPrime(num - i))
{ *p1 = i;
*p2 = num - i;
return; }
*p1 = *p2 = 0; } // 未找到
main()
{ int p1, p2,i;
int test[] = {8, 10, 20, 28, 100};
for (i = 0; i < 5; i++)
{ fun(test[i], &p1, &p2);
printf("%d = %d + %d
", test[i], p1, p2);
}
}
新知讲授
四
知识点2:指针知识点小结
新知讲授
四
知识点2:指针知识点小结
指针(Pointer)是用于存放内存地址的特殊变量(这里的地址一般是指内存中另一个变量的位置)。“指针指向某个变量”即指针存放的是该变量的地址值。指针变量的命名规则同普通变量。
通常所说的指针类型是指它所指向的变量的数据类型。指针自身的类型其实是整型(但不能将一个整型数据赋给它),因为指针存放的都是内存地址,而内存地址一般都是正整数。内存地址的长度是一定的,不同类型的指针占用的存储空间也是一样的。
求地址运算符“&”返回操作数变量在内存中的地址,与变量的内容无关。
格式为:&变量
新知讲授
四
知识点2:指针知识点小结
运算符“*”返回操作数所指变量的值。
格式为: *指针变量
设指针变量p指向结构体变量dd,而year是dd的一个成员,则下面的3个表达式等价:
指针既可在定义时赋值(即初始化),也可在定义之后赋值。但需遵循“指针变量必须赋值后才能使用”。一个指针变量只准许存放指定类型变量的地址。一个指针变量允许存放哪种类型变量的地址取决于对它的类型说明。
dd.year ←→ (*p).year ←→ p->year
师生互动
五
指针"编程挑战赛"
题目:将数组a中的n个整数按相反顺序存放
函数原型:void reverse(int *a, int n);
要求:使用指针操作数组元素
算法设计思路 挑战规则
关键点:首尾交换,向中间靠拢
步骤:
定义指针p指向数组首元素
定义指针q指向数组末元素
while循环交换p和q
p++,q--,直到p>=q 个人独立完成,10分钟
完成后提交代码到教学平台
随机抽取3位同学讲解
最佳实现将作为班级标准版本
随堂练习
六
1. 执行以下程序的输出是( )
#include<stdio.h>
main()
{
int a=20, *p1=&a, **p2=&p1;
**p2 += 10; *p1 -= 5;
printf("%d",a);
}
答案:25
解析:**p2等价于a,先让a=30;*p1等价于a,再让a=30-5=25,核心考查二级指针解引用与一级指针的关联。
随堂练习
六
2.以下关于指针运算的描述,正确的是( )
A. 不同类型指针可以直接进行减法运算
B. 指针变量可以与任意整数进行加减运算
C. 同类型指针相减,结果是两指针间的元素个数
D. 指针变量可以直接进行大于、小于的比较,与指向类型无关
答案:C
解析:A错误,不同类型指针运算无意义;B错误,指针只能加减整数,且需符合地址逻辑;D错误,只有指向同一数组/连续空间的同类型指针比较才有意义;C为指针运算核心规则。
随堂练习
六
3.若有int a[4]={1,3,5,7}, *p=a+1;,则表达式*(++p) - *(--p)的值是( )
A. 0
B. 2
C. 4
D. 6
答案:A
解析:p初始指向a[1];++p后指向a[2],--p又指向a[1];最终是a[1]-a[1]=0,考查指针自增自减的前置后置与运算顺序。
随堂练习
六
4.以下定义中,p的类型与其他三个完全不同的是( )
A. int *(*p)[3];
B. int (*p)[3][4];
C. int *p[3][4];
D. int (*(*p)[3])[4];
答案:C
解析:A 是指向 “int型指针数组(3 个元素)” 的指针;B 是指向 “3 行 4 列 int 数组” 的指针;C 是 3 行 4 列的 int型指针数组(本质是数组);D 是指向 “指向 3 行 4 列 int 数组的指针数组” 的指针,ABD 均为指向数组的指针,C 是指针数组。
随堂练习
六
5.已知char str[]="test", *p="test";,以下操作不会出现编译 / 运行错误的是( )
A. str[0]='T';
B. p[0]='T';
C. str="TEST";
D. p=strcat(p,"123");
答案:A
解析:B 错误,p 指向常量字符串,不可修改;C 错误,数组名是地址常量,不能赋值;D 错误,常量字符串不可追加内容;A 正确,str 是字符数组,内容可修改。
随堂练习
六
6.已知struct Stu{int id; char name[8];} s[2]={{101,"Tom"},{102,"Jack"}}, *p=s;,则*(p->name + 2)的值是( )
A. 'm'
B. 'c'
C. "m"
D. 不确定
答案:A
解析:p->name等价于 s [0].name,指向 'T';p->name+2指向 'm',解引用为字符 'm',考查结构体指针访问成员与字符数组指针运算结合。
随堂练习
六
7.以下代码片段中,存在逻辑错误且会导致运行异常的是( )
A. int a=5, *p=&a; int *q=p; *q=10;
B. int a[3]={1,2}, *p=a; p+=3; *p=5;
C. int *p; *p=20;
D. int a=10, *p=NULL; p=&a;
答案:C
解析:A 正确,同类型指针赋值后修改有效;B 是越界但不一定立即异常;C 错误,p 是野指针,未指向有效内存就解引用,必然运行异常;D 正确,先赋值 NULL 再指向变量,规范操作。
随堂练习
六
8.若有char *arr[]={"apple", "banana", "orange", "pear"}, **p=arr;,则*(*(p+2)+3)的值是( )
A. 'n'
B. 'g'
C. 'a'
D. 'e'
答案:B
解析:arr 是一级指针数组,p 是二级指针;p+2指向 arr [2]("orange" 的地址);*(p+2)是 "orange" 首地址,+3指向第 4 个字符 'g',解引用即为 'g',考查二级指针操作指针数组。
随堂练习
六
9.以下关于结构体指针的描述,错误的是( )
A. 结构体指针可以指向结构体变量或结构体数组元素
B. 结构体指针通过->访问成员,优先级高于*和&
C. 可以用malloc动态分配结构体内存,返回值需强制转为结构体指针
D. 结构体指针赋值时,只需保证指针类型一致,无需考虑结构体成员是否匹配
答案:D
解析:A、C 为结构体指针基础操作;B 正确,->优先级高于*和&;D 错误,不同结构体类型的指针不可随意赋值,即使成员数量相同,类型不匹配仍非法。
随堂练习
六
10.已知int a[5]={2,4,6,8,10}, *p=a;,以下表达式值为 6的是( )
A. *(p+=2)
B. *p+2
C. *p+2
D. *(p++)+2
答案:A
解析:A:p+=2 指向 a [2],其引用为 6;
课堂小结
七
章节小结
七
谢谢
EV录屏5.4.4软件录制
Lavf58.33.100
本视频由湖南一唯信息科技开发的EV录屏软件录制, www.ieway.cn
EV录屏5.4.4软件录制
Lavf58.33.100
本视频由湖南一唯信息科技开发的EV录屏软件录制, www.ieway.cn
EV录屏5.4.4软件录制
Lavf58.33.100
本视频由湖南一唯信息科技开发的EV录屏软件录制, www.ieway.cn
EV录屏5.4.4软件录制
Lavf58.33.100
本视频由湖南一唯信息科技开发的EV录屏软件录制, www.ieway.cn
EV录屏5.4.4软件录制
Lavf58.33.100
本视频由湖南一唯信息科技开发的EV录屏软件录制, www.ieway.cn
$