作为一位兢兢业业的人民教师,就不得不需要编写教案,借助教案可以让教学工作更科学化。那么什么样的教案才是好的呢?以下是小编收集整理的《c语言第10章教案标准》,供大家参考,更多范文可通过本站顶部搜索您需要的内容。
第一篇:c语言第10章教案标准
C电子教案第7章
泰山职业技术学院电子教案
第7章 函数
7.1 概述
一个C程序是由函数组成的,所以函数是C语言中最重要的概念,本章专门讨论函数的定义、函数的调用及参数传递等问题。 例7.1。 说明:
(1)一个源程序文件是由一个或多个C函数组成的,一个源程序文件是一个编译单位。
(2)一个C程序由一个或多个源程序文件组成,一个源程序文件可以为多个C程序共用。
(3)一个C程序中一定要有一个名为main的主函数,执行时总是从主函数开始,其它函数只有被调用时才会执行,执行完毕返回到调用处继续执行,正常情况下总是在主函数结束执行。
(4)所有的函数是平行的,即在定义时是互相独立的,主函数可以调用其它函数,其它函数之间可以互相调用,但其它函数不能调用主函数。
(5)从用户使用的角度看,函数可分为标准函数(库函数)和用户自定义函数。 (6)从函数的形式看,函数可分为无参函数和有参函数。 7.2 函数定义的一般形式 1. 无参函数的定义形式 格式:函数类型 函数名() { 数据声明部分; 执行语句部分; } 说明:(1)函数名:函数名是函数调用的依据,函数值的返回也是通过函数名实现的,函数名要符合标识符的定义。
(2)函数体:由数据声明和执行语句两部分组成,数据声明是对数据特征的描述,执行语句是对数据处理的描述,函数的功能由它们实现。
(3)函数类型:函数类型规定了函数返回值的类型,int或char可不写,如不要返
C语言程序设计精品课程
第 1 页 共
第二篇:C程序设计教案(第5章 实验5)
实验 5 一维数组和二维数组
一、
二、 实验学时:2课时 实验目标:
1. 熟悉掌握一维数组的定义、赋值和输入输出的方法。 2. 掌握对10个整数排序的方法。
3. 掌握二维数组的定义、赋值和输入输出的方法。
三、 实验要求:
1. 在上实验课之前,每一个同学必须将实验的题目、程序编写完毕,做好充分的准备。
2. 所有实验环节均由每位同学独立完成,严禁抄袭他人实验结果,若发现有结果雷同者,按实验课考核办法处理。
四、 实验步骤和内容
【启动Visual C++】 【新建工程】
选中【C++ Source File】项,【新建源程序文件】 编辑程序 执行程序
【例5.3】用随机函数产生10个0~100之内的整数,按从小到大排列输出。 /* 源文件名:Li5_3.c 功能:产生10个0~100之内的整数,按从小到大排列输出 */ 使数组从小到大排序的规则如下:
⑴设数组为a[0],a[1],…,a[n-1],构造i循环从0,1,…,n-2变化,构造j循环从i+1,i+2,…,n-1变化,即j>i。
⑵对于任何一个a[i],如果a[i]>a[j],表面前面有一个元素a[i]比它后面的元素a[j]大,a[i]应该在后面,a[j]应该在前面,交换a[i]与a[j]。
⑶对于任何一个a[i],都循环一次j,j循环完成后a[i]必不大于a[i+1],…,a[n-1],重复i循环,i循环结束后数组从小到大排序。
#include #include void main() { int a[10],i,j,k ;
/*定义a数组,i、j为循环变量,k为临时变量*/ for(i=0;i<10;i++)
a[i]=rand()%100 ;
/*给a数组随机赋0~100之内的整数*/
printf("排序之前的数据") ; for(i=0;i<10;i++) printf("%d",a[i]) ;
/*输出a数组的值,未排序*/
putchar(‘ ’) ;
for(i=0;i<9;i++)
for(j=i+1;j<50;j++)
if(a[i]>a[j])
{ k=a[i] ; a[i]=a[j] ; a[j]=k ; }
/*数组排序*/ for(i=0;i<10;i++)
printf("%d",a[i]) ;
/*输出a数组的值,已排序*/ putchar(‘ ’) ; }
1) 观查执行结果,是否与教材相同。 2) 重新输入10个不同的数,再查看结果
【例5.5】定义一个a[5][6]的整数数组,用随机函数值填写每个单元,找出最大值的单元,输出其行号及列号。
/* 源文件名:Li5_5.c 功能:找出二维数组中最大值的单元,输出其行号及列号。 */ #include #include void main() { int a[5][6] ;
/*定义a二维数组*/
int i,j,k,l,max ;
/*定义i、j为循环变量,k、l为最大值所在的行和列,
max为最大值*/ for(i=0;i<5;i++)
for(j=0;j<6;j++)
a[i][j]=rand()%100 ;
/*给a二维数组赋值*/
max=a[0][0] ; k=0 ; l=0 ;
/*把a[0][0]假设为最大值*/ for(i=0;i<5;i++) for(j=0;j<6;j++)
if(a[i][j]>max)
{ k=i ; l=j ; max=a[i][j] ;}
/*保存最大值及其行号k及列号l*/ printf("数组是 ") for(i=0;i<5;i++) ;
{
for(j=0;j<6;j++)
printf("%4d",a[i][j]) ;
/*输出a二维数组的值*/ printf(" ") ;
}
printf("最大值是a[%d][%d]=%d ",k,l,max) ; }
1)观查执行结果,是否与教材相同。 2)重新输入不同的数据,再查看结果
五、 思考题
1) 【例5.3】若改为从小到大排序,该如何修改?
2) 【例5.5】一开始为什么要把a[0][0]赋值给max,能把0直接赋值给max吗?
六、
实验小结:
第三篇:C程序设计教案(第7章 实验9)专题
实验9
指针使用和数组的指针
一、
二、 1. 2. 3. 4. 实验学时:2课时 实验目标
掌握指针的概念、指针变量的定义和使用指针变量;
掌握指针变量的运算(取地址运算&、取内容运算*、指针移动的运算等) 学会使用数组的指针和指向数组的指针变量; 掌握指针与数组的关系;
实验要求:
三、
1. 在上实验课之前,每个同学必须预习指针变量的定义、赋值和取地址运算&、取内容运算*、指针移动的运算等操作,数组元素的多种便是方法; 2. 每个同学必须将实验的题目、程序编写完毕,做好充分的准备。 3. 所有实验环节均由每位同学独立完成,严禁抄袭他人实验结果,若发现有结果雷同者,按实验课考核办法处理。
四、 实验步骤和内容
1.分析下列程序的运行结果,并上机验证。 1) void main() {
int i, j, *pi, *pj; pi=&i; pj=&j; i=5; j=7;
printf( "%d %d %d %d", i, j, pi, pj );
printf( " %d %d %d %d ", &i, *&i, &j, *&j ); }
程序的运行结果是:______________________ 2) void main() {
int a[ ]={ 1, 2, 3 }; int *p, i; p=a;
for ( i=0; i<3; i++ )
printf( "%d %d %d %d ", a[i], p[i], *(p+i), *(a+i) ); } 程序的运行结果是:______________________ 3) void main() {
int a[ ]={ 2, 5, 3, 6, 8 }; int *p, i=1, s=0;
for ( p=a; p
1) 用地址法输入输出二维数组各元素。 2) 用指针法输入输出二维数组各元素。
五、 思考题
1. 数组的指针和指向数组的指针变量的区别 2. 分析指针与数组的关系
六、
实验小结:
第四篇:C语言程序设计教案 第十章指针
第十章 指 针
课题:
教学目的: 教学重点: 教学难点: 第十章 指针
§1-§2
1、了解指针与地址的概念
2、掌握指针变量的定义、初始化及指针的运算 指针变量的定义、初始化及指针的运算
指针的运算
步骤一 复习引导
指针是C语言的一个重要概念,也是C语言的一个重要特色。正确而灵活地运用它,可以有效地表示复杂的数据结构;能动态分配内存;能方便地使用字符串;有效而方便地使用数组;在调用函数时能得到多于1个的值;能直接处理内存地址等,这对设计系统软件是很必要的。
指针的概念比较复杂,使用也比较灵活,因此初学者时常会出错,务请在学习本章内容时十分小心。
步骤二 讲授新课
§10.1 地址和指针的概念
计算机的主存储器被分成一个个存储单元,为了区分各存储单元,要为每个存储单元编号,这个编号即地址。
例:i =3;
或 scanf(“%d”, &i);
是将3送给 i所在的空间。
例:将3送到变量I_pointer所“指向”的单元(即I所标志的单元)。
所谓“指向”,是通过地址来体现的,I_pointer中的值为2000,它是变量I 的地址,这样就在I_pointer和变量之间建立起一种联系,即通过I_pointer能知道I的地址,从而找到变量I的内存单元。因而在C语言中,将地址形象化地称为“指针”。
意思是通过它能找到以它为地址的内存单元。一个变量的地址称为该变量的“指针”。
内存单元的地址和内存单元的内容是两个不同的概念。
指针:就是地址,即内存单元的编号。
指针变量:用来存放另一变量的地址(即指针)的变量。
如:地址2000是变量 i的指针;i_pointer是指针变量,其值就是指针2000。
§10.2变量的指针和指向变量的指针变量
变量的指针就是变量的地址。
存放变量地址的变量是指针变量,用来指向另一个变量。
*i_pointer 表示 i_pointer 所指向的变量。
一、定义一个指针变量
指针变量的定义包含三个方面的内容:
⑴ 指针类型说明,即定义变量为一个指针变量 ⑵ 指针变量名
⑶ 变量值(指针)所指向的变量的数据类型。 格式:
存储类型
基类型
*指针变量名; 例:int *pointer_1, *pointer_2;
float *pointer_3;
char *pointer_4;
二、指针的引用
指针变量有两个运算符: & :取地址运算符
功能:取变量地址;单目,右结合。
* :取内容运算符(“间接访问”运算符)
功能:只能跟地址,取变量所指向单元的内容;单目,右结合。
例:&a为变量a的地址,
*p 为指针变量p所指向的存储单元。
例:int a=5, *p=&a;
printf ( “%d”, *p ); main() { int a,b;
int *pointer_1,*pointer_2;
a=100;b=10;
pointer_1=&a;
/*把变量a的地址赋给pointer_1*/
pointer_2=&b;
/*把变量b的地址赋给pointer_2*/
printf(“%d,%d ”,a,b);
printf(“%d,%d ”,*pointer_1, *pointer_2); } 输出结果:100, 10
100, 10
评注:
1、在第3行虽然定义了两个指针变量,只是提供了两个指针变量,但并未指向任何一个整型变量。称为指针“悬空”。
2、最后一行的*pointer_1和pointer_2就是变量a和b。
3、程序中两处出现*pointer_1等,含义不同。程序第3行中的*pointer_1表示定义指针变量pointer_1。它前面的*只是表示该变量是指针变量。程序最后一行中的*pointer_1则代表变量,即pointer_1所指向的变量。
4、第5行中的pointer_1=&a 是将a的地址赋给指针变量pointer_1,而不是*pointer_1。
注意:不应写成:*pointer_1=&a;
5、从上例中可看出,*pointer_1等价于a,*pointer_2等价于b,故凡在程序中出现a的地方均可用 *pointer_1 代替。所以,若有: int x, y, *px=&x ; 则下面的运算均是正确的: y=*px+1;
/*把 x 的内容加1 送变量y*/ printf(“%d ”, px );
/*打印当前x 的内容*/ d=sqrt((double) px);
/*把x的平方根送变量d*/ px=0;
/*把 x 置为0*/ *px+=1;
/*把 x 的值加 1*/ (*px)++;
/*使 x 的值加 1*/ y=(*px)++;
/*即y=x, x++*/
6、假设px和py都被定义为指向int 对象的指针,而且px当前已指向了int 型变量x,则执行:
py=px;
/*把指针px的内容拷贝到指针py中去*/ 即
py和px 这两个不同的指针指向了同一对象x
7、指针不是整数,不能将它与整数混为一谈。 例:
# include main() { int x=100,*p; p=x; printf(“%d”, p ); }
例如:
# include main() { int a, b, *d=&a;
b = d;
printf( “%d ”, b );
……
}——编译不出错,但得不到希望的值
关于&和*运算符的说明:
假设已执行
pointer_1=&a;
1、&*pointer_1含义是什么?
&*pointer_1与&a相同,即变量a的地址。
2、*&a的含义是什么?
先进行&a运算,得a的地址,再进行*运算。
*&a、*pointer_1及变量a等价。
3、(*pointer_1) + + 相当于a + +。
它与*pointer_1 + + 不同。
4、*pointer_1 + + 等价于*(pointer_1 + +),即先进行*运算,得到a的值,然后使pointer_1的值改变,这样pointer_1不再指向a了。
例10.2:输入a和b两个整数,按先大后小的顺序输出a和b。
main() { int *p1,*p2,*p, a, b;
scanf(“%d,%d”,&a,&b);
p1=&a; p2=&b;
if (a
{p=p1; p1=p2; p2=p;}
printf(“ a=%d,b=%d ”,a,b);
printf(“max=%d,min=%d ”,*p1,*p2);
} 运行情况: 5,9 a=5,b=9 max=9,min=5
三、指针变量作为函数参数
例10.3对输入的两个整数按大小顺序输出。 先考察如下程序,看是否能得到预期的结果
swap(int p1, int p2) { int temp; temp = p1; p1 = p2; p2 =temp; } main() { int a, b;
scanf(“%d, %d”, &a, &b);
if(a
printf(“ %d,%d ”,a,b); } 不能得到预期的结果。 改为:
swap(int *p1,int *p2) { int temp;
temp = *p1;
*p1 = *p2;
*p2 =temp; } main() { int a,b;
int *pointer_1,*pointer_2;
scanf(“%d,%d”,&a,&b);
pointer_1=&a;
pointer_2=&b;
if(a
swap(pointer_1,pointer_2);
printf(“ %d,%d ”,a,b); }
注:如果想通过函数调用得到n个改变的值,可以:
1、在主调函数中设n 个变量,用n个指针变量指向它们;
2、然后将指针变量作实参,将这n 个变量的地址传给所调用的函数的形参;
3、通过形参指针变量,改变该n个变量的值;
4、主调函数中就可以使用这些改变了值的变量。
四、指针(变量)的初始化 指针置初始化值的格式:
存储类型
基类型
*指针名=初始化值; 如:main()
{ static int a;
int *p=&a, *p1=p;
…… } 再如: int *p = 0;
或
int *p = NULL;
五、指针的运算
1、指针的算术运算
指针仅能进行加、减算术运算
如:p+n , p-n , p++ , p-- , ++p , --p
p-= n , p+= n , p1-p2 等 其中n是整数,p、p
1、p2均为指针;
施行加法运算时,指针向地址增大的方向移动; 施行减法运算时,指针向地址减小的方向移动; 移动长度取决于指针的基类型,由计算机决定; 如有:int a,b,c, *pt =&a;
则
pt++ 则指针向后移动两个字节; 再如:main()
{ int *p1,a=8,b=3;
p1=&a;
printf(“%d,%d ”, (*p1)++, *p1++);
printf(“%d,%d ”,a, *p1);
} 运行结果:3 , 8
8 , 4 注:p1+k = p1+k*sizeof(p1的基类型);
p1- k = p1- k*sizeof(p1的基类型); 如:
strlen(char *s)
{ char *p=s;
while(*p!=„�‟)p++;
return(p-s);
}
2、指针的关系运算
设指针p1,p2指向同一数组中的元素,则
p1
p1
p1= =p2:
表示p
1、p2指向数组中的同一元素;
同理可推出>、>=、<=、!=比较的意义; 不可将指针与其他类型的对象作比较;
若两指针指向不同数组中的元素,也不可比较;
允许将指针与NULL或数值0进行= =或!=的比较,以便判定一个指针是否为空指针。
步骤三 课堂小结
本课介绍了指针与地址的概念,指针变量的定义、初始化及指针的运算。
指针:就是地址,即内存单元的编号。
指针变量:用来存放另一变量的地址(即指针)的变量。
例如:int a=5, *p=&a;
printf ( “%d”, *p );
注意:运算符*和&的用法,指针变量的自加自减运算。 步骤四 布置作业
课后作业:第十章课后练习 10.1 10.2 课题:
教学目的: 教学重点: 教学难点: 第十章 指针
§3 掌握指针与数组的知识 指向数组的指针变量
指向二维数组的指针
步骤一 复习引导
上节课介绍了指针变量的定义及其赋值。一个变量有地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量既然可以指向变量,当然也可以指向数组和数组元素(把数组起始地址或某一元素的地址放到一个指针变量中)。
步骤二 讲授新课
所谓数组的指针是指数组的起始地址,数组元素的指针是数组元素的地址。
引用数组元素可以用下标法(如a[3]),也可以用指针法,即通过指向数组元素的指针找到所需的元素。使用指针法能使目标程序质量高(占内存少,运行速度快)。
一、指向一维数组的指针
定义形式:
int a[10];
int *p;
p=&a[0];
或
p=a;
含义:把数组的首地址赋给指针变量p。
也即: int *p=&a[0];
或
int *p=a;
二、通过指针引用数组元素
按C的规定:如果指针变量p已指向数组中的一个元素,则p+1指向同一个数组中的下一个元素(而不是简单地加1)。
如果p的初值为&a[0],则:
p+i a+i &a[i],即指向a数组的第i个元素。
*(p+i) *(a+i)
a[i]。
指向数组的指针变量也可以带下标,如p[i]与*(p+i)等价 引用数组元素时,可以用:
1、下标法,如:a[i]
2、指针法,如:*( a+i )
或
*( p+i )
其中,a是数组名,p是指向数组的指针
例10.5:输出数组中的全部元素
假设有一个a数组,整型,有10个元素。用三种方法输出各元素的值:
1、下标法: main() { int a[10], i ;
for( i=0; i<10 ; i++)
scanf(“%d”,&a[i]);
printf(“ ”);
for( i=0 ; i<10; i++)
printf(“%d”,a[i]); }
2、利用数组名计算数组元素地址,找出元素的值。 main() { int a[10], i ;
for( i=0; i<10 ; i++)
scanf(“%d”,&a[i]);
printf(“ ”);
for( i=0 ; i<10; i++)
printf(“%d”,*(a+i)); }
3、用指针变量指向数组元素。 main() { int a[10], *p, i ;
for( i=0; i<10 ; i++)
scanf(“%d”,&a[i]);
printf(“ ”);
for( p=a; p<(a+10); p++)
printf(“%d”,*p ); } 评注:
1、第1和2种方法执行效率是相同的。
2、第3种方法效率高。
3、用下标法比较直观。
在使用指针变量时,有几个问题要注意:
1、指针变量可以实现使本身的值改变。 如:for(p=a; p<(a+10); p++)
2、要注意指针变量的当前值。
如:要通过指针变量输出a数组的10个元素。 main() { int a[10], i , *p=a;
for( i=0; i<10 ; i++)
scanf(“%d”, p++);
printf(“ ”);
for( i=0 ; i<10; i++,p++)
printf(“%d”, *p); } 这个程序输出的并不是a数组中各元素的值。因为第一个 for 循环结束时,p已经指向数组的末尾。再继续下去,p指向的是a数组下面的10个元素,是不可预料的。 可加一句为:p=a;
3、用指针变量p指向数组元素,可以指到数组以后的内存单元。C编译程序不作下标越界检查。
4、注意指针变量的运算。如果p指向数组a, ⑴ p++ (或 p+=1 ),使p指向下一元素a[1]。 ⑵ *p++
等价 *(p++)。作用是先得到p指向的变量的值(即*p),然后再使p+1→p。 ⑶ *(p++)与*(++p) 不同。前者为a[0],后者为a[1] ⑷ (*p)++表示p指向的元素值加1,即(a[0])++ ⑸ 如果p当前指向a数组中第i个元素,则:
*(p- -)相当于a[i- -],先对p进行*运算,再使p自减; *(+ + p)相当于a[+ +i],先使p自加,再作*运算。 *(-) { temp=*i; *i = *j; *j =temp; } return; } main() { int i, a[10],*p=a; printf(“The original array: ”); for( i=0; i<10; i++,p++) scanf(“%d”, p); printf(“ ”); p=a; inv(p,10); printf(“The array is : ”); for( p=a; p
例10.10:用选择法对10个整数排序。 main() {int *p, i, a[10]; p=a; for( i=0; i<10; i++) scanf(“%d”,p++); p=a; sort(p,10); for( p=a, i=0; i<10; i++) { printf(“%d”,*p);p++;} } sort(int x[],int n) { int i, j, k, t; for( i=0; ix[k]) k=j; if( k !=i) { t = x[i]; x[i] = x[k]; x[k] = t; } }
四、指向二维数组的指针和指针变量
1、二维数组的地址如:
int a[3][4] A
a[0]
a[0] [0] a[0] [1] a[0] [2] a[0] [3]
A+1
a[1]
a[1] [0] a[1] [1] a[1] [2] a[1] [3]
A+2
a[2]
a[2] [0] a[2] [1] a[2] [2] a[2] [3] 例:int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
设首地址为2000。
a[k]+p ( 0<=k< i , 0<=p
由此得到: *(a[k]+p) 等价于a[k][p]; a[0]与&a[0][0]等价;
a+k与&a[k][0]等价,而a[0]+k与&a[0][k]等价; *(a+i)可理解为a[i],故有如下等价关系:
a+0
等价于 a[0]、
a[0]+0、
&a[0][0]、
*(a+0)
a+1
等价于 a[1]、
a[1]+0、
&a[1][0]、
*(a+1)
a+(i-1) 等价于 a[i-1]、a[i-1]+0、
&a[i-1][0]、
*(a+i-1)
*(a+k)与*a[k]是不同的,前者相当于a[k],是一个地址值;后者相当于*(a[k]+0)或*&a[k][0],是数组元素a[k][0]中存储的值。 数组元素a[k][p]就是*(a[k]+p),即*(*(a+k)+p)
步骤三 课堂小结
本课介绍了指向数组的指针,主要是指向一维数组的指针。用指针变量p指向数组a,指针变量p可以++、--,表示指向数组的上一元素或下一元素。但C编译程序不作下标越界检查。使用指针既方便有灵活,但初学者容易搞错。
步骤四 布置作业
课后作业:第十章课后练习 10.31 10.5 课题:
教学目的: 教学重点: 教学难点: 第十章 指针
§3-§4 在掌握指针与数组的基础上,掌握字符串的指针与指向字符串的指针变量 指向字符串的指针变量
用指针处理字符串
步骤一 复习引导
上节课介绍了指向一维数组的指针及二维数组的地址,指向一维数组的指针也即指向元素的指针,那么指向二维数组的指针是怎样的呢?它有两种类型。
步骤二 讲授新课
2、指向二维数组的指针变量
——(1)指向数组元素的指针变量
设指针变量p=a[0]
(&a[0][0]、a、a+0、*(a+0) ) 计算a[i][j]在n*m数组中的位置:
例:……
for( i=0; i<3; i++)
{for( j=0; j<4; j++ ) printf (“%4d”, *(p+i*m+j));
printf(“ ”); }
……
例:用指针变量输出数组元素的值。 main() { int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};
int *p;
for( p=a[0]; p
{if((p-a[0])%4 == 0) printf(“ ”);
printf(“%4d”, *p);
} } 计算a[i][j]在n*m数组中的位置:a[0]+i*m+j
——(2)行指针(指向由m个元素组成的一维数组的指针变量)
定义:指针基类型
(*指针名)[m]
其中,m表示二维数组每行有m列;
如: int (*p)[3];
于是,p
指向第0行元素的起始存储地址;
p+1
指向第1行元素的起始存储地址;……
p+I
指向第i 行元素的起始存储地址;
而每一行的元素的表示形式为:
第0行元素的表示为 (*p)[j];
第1行元素的表示为 (*(p+1))[j];……
第i 行元素的表示为 (*(p+ I))[j];
例 :
#include main() { int (*p)[4], j;
int a[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}}; for(p=a; p
for(j=0;j<4; j++)
if( j==3 ) printf(“%4d ”, (*p)[j] );
else printf(“%4d” , (*p)[j] );
} 改写为:
#include main() { int (*p)[4], i, j;
int a[4][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
p=a;
for( i=0; i<4; i++)
for(j=0;j<4; j++)
printf(j==3?“%4d ”: “%4d” , *(*(p+i )+j) );
}
3、多维数组的指针作函数参数
一维数组的地址可以作为函数参数传递,多维数组的地址也可作函数参数传递。在用指针变量作形参以接受实参数组名传递来的地址时,有两种方法:
1、用指向变量的指针变量;
2、用指向一维数组的指针变量。
例;有一个班,3个学生,各学4门课,计算总平均分数,以及第n个学生的成绩。 main() { void average(float *p ,int n);
void search(float (*p)[4], int n);
float score[3][4]={{65,67,70,60},{80,87,90,81}, {90,99,100,98}};
average( *score, 12);
/*求12个分数的平均分*/
search(score , 2);
/*求第2个学生成绩*/ } void average(float *p , int n) {float *p_end;
float sum= 0,aver;
p_end = p+n-1;
for(; p<=p_end; p++) sum =sum+(*p); aver = sum/n; printf(“average=%5.2f ”,aver); } void search(float (*p)[4], int n) { int i; printf(“the score of No %d are: ”,n); for( i=0; i<4; i++) printf(“%5.2f”, *(*(p+n)+i)); }
例10.15 在上题基础上,查找一门以上课程不及格的学生,打印出他们的全部课程的成绩。 main() { void search(float (*p)[4], int n); float score[3][4]={{65,57,70,60},{58,87,90,81),{90,99,100,98}}; search(score, 3); } void search(float (*p)[4], int n) {int i, j, flag; for( j=0; j
§10.4字符串的指针和指向字符串的指针变量
一、字符串的表示形式
1、用字符数组存放一个字符串。 如:main()
{ char string[ ]=“I love China!”;
printf(“%s ”, string); }
2、用字符指针指向一个字符串。
如:main()
{ char *string=“I love China!”;
printf(“%s ”, string); } 例10.18 将字符串a复制为字符串b。 main() { char a[]=“I am a boy.” , b[20];
int i;
for( i=0; *(a+i)!=„�‟; i++) *(b+i) = *(a+i);
*(b+i) = „�‟;
printf(“string a is : %s ”, a);
printf(“string b is :”);
for( i=0; b[i]!=„�‟; i++ )
printf(“%c”, b[i] );
printf(“ ”); }
例10.19 用指针变量来处理上例。 main() { char a[ ]=“I am a boy.” , b[20], *p1, *p2;
int i;
p1= a; p2= b;
for( ; *p1!=„�‟; p1++,p2++ ) *p2 = *p1;
*p2 = „�‟;
printf(“string a is : %s ”, a);
printf(“string b is :”);
for( i=0; b[i]!=„�‟; i++)
printf(“%c”, b[i]);
printf(“ ”); }
二、字符串指针作函数参数
例10.20:用函数调用实现字符串的复制。 ——(1)用字符数组作参数。
void copy_string(char from[],char to[]) { int i=0;
while( from[i]!=„�‟ )
{ to[i] = from[i]; i++;}
to[i]=„�‟;
} main() { char a[]=“I am a teach.”;
char b[]=“you are a student.”;
printf(“string a= %s string b=%s ”,a,b);
copy_string(a,b);
printf(“ string a=%s string b=%s ”,a,b); } ——(2)形参用字符指针变量 void copy_string(char *from,char *to) { for(; * from!=„�‟; from++, to++ )
*to = *from;
*to=„�‟;
} ——(3)对copy_string函数还可以简化。 ① void copy_string(char *from, char *to)
{ while((*to =* from)!=„�‟)
{ to ++; from++;}
} ② void copy_string(char *from, char *to)
{ while((*to ++ =* from++)!=„�‟); }
③void copy_string(char *from, char *to)
{ while(* from!=„�‟)
*to++ = *from ++;
*to = „�‟;
} ④void copy_string(char *from, char *to)
{ while(*to++ = *from ++); }
⑤void copy_string(char *from, char *to)
{ for( ;*to++ = *from ++;); }
⑥void copy_string(char from[], char to[])
{ char *p1,*p2;
p1=from; p2=to;
while((*p2++ = *p1++)!=„�‟);
}
三、字符指针变量和字符数组的讨论
1、 字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址,决不是将字符串放到字符指针变量中。
2、赋值方式。对字符数组只能对各个元素赋值,不能用以下办法对字符数组赋值;
char str[14];
str=“I love China.”;对字符指针变量,可以采用下面方法赋值:
char *a;
a= “I love China.”;
/*赋给a的是串的首地址*/
3、对字符指针变量赋初值:
char *a=“I love China.”;
等价于
char *a;
a=“I love China.”;
而对数组的初始化:
char str[14]={“I love China.”}; 不等价于
char str[14];
str[]=“I love China.”;
即数组可以在变量定义时整体赋初值,但不能在赋值语句中整体赋值。
4、如果定义了一个字符数组,在编译时为它分配内存单元,它有确定的地址。 而定义一个字符指针变量时,给指针变量分配内存单元,在其中可以放一个地址值,也就是说,该指针变量可以指向一个字符型数据,但如果未对它赋一个地址值,则它并未具体指向一个确定的字符数据。这很危险。
如: char str[10];
scanf(“%s”,str); 是可以的
char *a;
scanf(“%s”,a);
能运行,但危险,不提倡,在a单元中是一个不可预料的值。
应当 char *a,str[10]; a=str; scanf(“%s”,a);
5、指针变量的值是可以改变的,数组名虽然代表地址,但它的值是不能改变的。可以下标形式引用所指的字符串中的字符。
如:main()
{char *a=“I love China.”;
a=a+7;
printf(“%s”,a); }
又如:char str[]={“I love China.”}; str=str+7; printf(“%s”,str); 是错的
6、用指针变量指向一个格式字符串,可以用它代替printf函数中的格式字符串。也可以用字符数组实现,但由于不能采用赋值语句对数组整体赋值。
如:char *format; format=“a=%d,b=%f ”; printf(format,a,b);
等价于:printf(“a=%d,b=%f ”,a,b);
也可以:char format[ ]=“a=%d,b=%f ”; printf(format,a,b);
步骤三 课堂小结
本课介绍了指针与二维数组、指针与字符串,指向二维数组的指针有指向元素的指针和行指针,使用时应注意它们的区别。我们既要掌握用数组处理字符串,也要掌握用指针变量处理字符串。要区分这两种方法的不同之处。
步骤四 布置作业
课后作业:第十章课后练习 10.61 10.7 课题: 第十章 指针
§5-§7 教学目的: 了解指针与函数的概念 教学重点:
教学难点: 指针数组,二级指针 掌握指针数组,二级指针等知识 掌握指针数组,二级指针等知识
步骤一 复习引导
前面介绍了指针与维数组、指针与字符串,我们可以用指针变量指向整型变量、字符串、数组,也可以指向一个函数。
步骤二 讲授新课
§10.5函数的指针和指向函数的指针变量
函数的地址:函数存储区域的首地址就是该函数的入口点,其函数名表示了入口地址。
一、函数指针变量的定义:
存储类型
数据类型
(*函数指针名)( );
例:static int (*p)( ); 例10.23 求a和b中的大者。
main()
{ int max(int, int);
int a,b,c;
scanf(“%d,%d”,&a,&b);
c=max(a,b);
printf(“a=%d,b=%d,
max=%d”,a,b,c);
} max(int x, int y) { int z;
if(x>y) z=x;
else z=y;
return(z); } 法2:main()
{
int max(int, int);
int (*p)( );
int a,b,c;
p=max;
/*将地址送入p */
scanf(“%d,%d”,&a,&b);
c=(*p)(a,b);
/*与max(a,b)等价*/
printf(“a=%d,b=%d,max=%d”,a,b,c);
} 注:int (*p)()定义p是一个指向函数的指针变量,此函数带回整型的返回值。
说明:
1、函数的调用可以通过函数名调用,也可以通过函数指针调用。
2、(*p)() 表示定义一个指向函数的指针变量,它不是固定指向哪一个函数的,而只是表示定义了这样一个类型的变量,它是专门用来存放函数的入口地址的。
3、在给函数指针变量赋值时,只需给出函数名而不必给出参数,如:p=max; 。
4、用函数指针变量调用函数时,只需将(*p)代替函数名即可(p为指针变量名),在(*p)之后的括号中根据需要写上实参。如:c=(*p)(a,b);
5、对指向函数的指针变量,像p+n、p++、p--等运算是无意义的。
二、用指向函数的指针作函数参数
函数的参数可以是变量、指向变量的指针变量、数组名、指向数组的指针变量等。现介绍指向函数的指针也可以作为参数,以便实现函数地址的传递,也就是将函数名传给形参。
它的原理可以简述如下:有一个函数(假设函数为sub),它有两个形参(x1和x2),定义x1和x2为指向函数的指针变量。在调用函数sub时,实参用两个函数名f1和f2给形参传递函数地址。这样在函数sub中就可以调用f1和f2函数了。
有人会问,既然在sub函数中要调用f1和f2函数,为什么不直接调用f1和f2而用函数指针变量呢?的确,如果只是用到f1和f2,完全可以直接在sub函数中直接f1和f2,而不必设指针变量x
1、x2。但是,如果在每次调用sub函数时,要调用的函数是不固定的,这次调用f1和f2,而下次要调用f3和f4,第三次要调用的名作为实参即可,sub函数不必作任何修改。这种方法是符合结构化程序设计方法原则的,是程序设计中常使用的。
例10.24 设一个函数process,在调用它的时候,每次实现不同的功能。
main() { int max(int ,int );
int min(int , int);
int add(int , int);
int a, b;
printf(“enter a and b:”);
scanf(“%d,%d”, &a, &b);
printf(“max=”); process(a,b,max);
printf(“min=”); process(a,b, min);
printf(“sum=”); process(a,b, add); }
max(int x, int y)
{ int z;
if(x>y) z = x; else z = y;
return(z);
}
min(int x, int y)
{ int z;
if(x
else z = y;
return(z); } add( int x, int y) { int z;
z = x+y;
return(z); }
process(int x, int y, int (*fun)(int ,int)) {int result;
result = (*fun)(x,y);
printf(“%d ” , result ); }
在函数process定义中,int (*fun)(int,int)表示fun是指向函数的指针,该函数是一个整型函数,有两个整型形参。
在三次调用中,分别将函数名max、 min、 add作为实参将其入口地址送给process函数中的形参fun(fun是指向函数的指针变量)。例:process函数中的(*fun)(x,y)相当于max(x,y)。
注:在使用时,应将函数声明,这样编译系统将它按函数名处理(把函数入口地址作实参值),而不是作为变量名,不致出错。
Process函数无固定功能。如果max、 min、 add换成其它函数,此process函数不需改变,只要修改每函数的函数体。
§10.6 返回指针值的函数
一个函数可以带回一个整型值、字符值、实型值等,也可以带回指针型的数据,即地址。其概念与以前类似,只是带回的值的类型是指针类型而已。 格式: 类型名
*函数名(参数表); 例: int
*a(int x, int y);
a是函数名,调用它以后能得到一个指向整型数据的指针(地址)。
例10.25 有若干个学生的成绩(每个学生有4门课程),要求在用户输入学生序号以后,能输出该学生的全部成绩。用指针函数来实现。 float *search( float (*pointer)[4], int n)
{float *pt;
pt = *(pointer +n);
return( pt );
} main() { float score[][4]={{60,70,80,90},{56,89,67,88),{34,78,90,66}};
float *p;
int i, m;
printf(“enter the number of student:”);
scanf(“%d”,&m);
printf(“The score of No.%d are: ”, m);
p=search(score, m);
for( i=0; i<4; i++)
printf(“%5.2 ”, *(p + i));
}
例10.26 对上例中的学生,找出其中有不及格课程的学生及其学生号。 float *search(float (*pointer)[4]) { int i;
float *pt;
pt = *(pointer+1);
for( i=0; i<4 ; i++)
if(*(*pointer+i)<60) pt = *pointer;
return(pt); } main() { score[][4]={{60,70,80,90},{56,89,67,88),{34,78,90,66}};
float *search(float (*pointer)[4], int n);
float *p;
int i, m;
for( i=0; i<3; i++) { p=search(score+i);
if( p==*(score + i))
{ printf(“ No.%d score:”, i);
for(j=0; j<4; j++)
printf(“%5.2 ”, *(p + i));
printf(“ ”); }
} }
关于函数的返回值是指针的情况,程序设计时应注意:
1、因数组名是地址常量,用于接受这种返值的对象不能是数组名,这与把数组名作为实在参数传递给形式参数的情况不同(作为形式参数的数组名总被视为指针)。
2、不应将局部于被调用函数的指针作为返值返回给调用者,理由是局部于被调用函数的数据对象执行返回语句离开被调用函数后,原来分配的被调用函数的所有局部对象的存储空间立即被收回(释放),虽然调用者已经获得了正确的地址值,但此时它指向的存储区域的内容可能已经发生了变化,或许已经分配给其他函数了。如果调用函数中仍然使用这个指针去存取那个区域中的数据,得到的可能并非原先的数据。对于这种情况的正确做法是应该把所处理的对象定义成全局对象或static型对象。
§10.7 指针数组和指向指针的指针
一、指针数组的概念
一个数组中的元素均为指针类型,称为指针数组。
形式:
存储类型
类型名
*数组名[数组长度]
例如:
static
int
*p[4]
定义指针数组时也可以进行初始化,如:
static char ch[][20]={“Beijing”,“Nanjing”,“Shanghai”,“Guangzhou”};
char *p[ ]={ch[0],ch[1],ch[2],ch[3]}; 该例也可以等价定义为:
char *p[ ]={“Beijing”,“Nanjing”,“Shanghai”,“Guangzhou”};
例如: main( ) { int i, min, j;
char *temp, *p[ ]={“Beging”,“Nanjing”,“Shanghai”, “Guangzhou”};
for( i=0; i<3; i++)
{ min=i;
for( j=i+1; j<4; j++)
if (strcmp(p[j], p[min])<0) min=j;
temp=p[i]; p[i]=p[min]; p[min]=temp;
}
for(i=0; i<4; i++)
printf(“%s ”, p[i]); } 注意:不能把一个二维数组与一个指针数组混淆;
如:int a[10][10]; 与
int *b[10];的异同点 访问形式相同;如a[5][5],b[5][5]; 占用的存储空间数不同;
每一个b[i]必须置初值者能使用; 使用b优越
不需进行复杂的下标计算;
b[i]指向的数组并非一定要10个元素,但a中,每一行上的元素个数必须相同;因指针指向的是一个地址,故对b而言,各个b[i]指向的存储区域之间不必连续;而对a而言,必须存储100个连续的存储int型数据对象的区域。
例10.27 将若干字符串按字母顺序(由小到大)输出。 main() { void sort(char *name[], int n);
void print(char *name[], int n);
char *name[]={“Follow me”, “Basic”, “Great Wall”, “Fortran”, “Computer”};
int n=5;
sort(name, n);
print(name, n);
} void sort(char *name[], int n) { char *temp;
int i, j, k;
for( i=0; i
{ k=i ;
for( j=i+1; j
if( strcmp(name[k], name[j])>0) k=j; if( k!=i )
{temp=name[i];
name[i]=name[k];
name[k]=temp;}
} } void print(char *name[], int n); { int i;
for( i=0; i
}
二、指向指针的指针
在本章开头已提到“间接访问”变量的方式。利用指针变量访问另一个变量就是“间接访问”。
如果在一个指针变量中存放一个目标变量的地址,这就是“单级间址”。指向指针的指针用的是“二级间址”方法。从理论上讲,间址方法可以延伸到更多的级。但实际上在程序中很少有超过二级间址的。级数愈多,愈难理解,容易产生混乱,出错机会也多。
二级指针的定义:
char **p;
含义:表示指针变量p是指向一个字符指针变量(即指向字符型数据的指针变量)的。 main( ) { int i, min, j;
char *temp, *p[ ]={“Beging”,“Nanjing”,“Shanghai”, “Guangzhou”};
char **pp;
pp=p;
for(i=0; i<3; i++)
{ min=i;
for( j=i+1; j<4; j++)
if (strcmp(*(pp+j),*(pp+min))<0) min=j;
temp=*(pp+i);
*(pp+i)=*(pp+min);
*(pp+min)=temp;
}
for (i=0; i<4; i++) printf(“%s ”,*pp++); } 例10.28 使用指向指针的指针。 main() { char *name[]={“Follow me”, “Basic”, “Great Wall”, “Fortran”, “Computer”};
char **p;
int i;
for( i=0; i<5; i++)
{ p=name+i;
printf(“%s ”, *p);
}
} 例 main() { static int a[5]={1,3,5,7,9};
int *num[5]={&a[0],&a[1],&a[2],&a[3],&a[4]};
int **p, i;
p= num;
for( i=0; i<5 ; i++)
{ printf(“%d ”, **p);
p++;
}
} 运行结果:
9 步骤三 课堂小结
本课介绍了指针数组、二级指针、指针与函数。要搞清它们的定义及应用; 注意区分:
char a[5];
与
char (*a)[5];
int
*p(int x);
与
int (*p)( );
步骤四 布置作业
《C语言习题集》同步练习 课题: 第十章 指针
§7-§8 教学目的: 了解指针数组作main函数的形参 教学重点:
教学难点: 指针的应用 掌握指针的应用 掌握指针的应用
步骤一 复习引导
上节课介绍了二级指针、指针数组,而指针数组的一个重要应用是作为main函数的形参。main()函数是我们C语言程序必不可少的,以往使用时main()是不带参数的。实际上是可带参数的,如:main(argc, argv) 。
步骤二 讲授新课
三、指针数组作main函数的形参
带参数的main原型:
main( int argc, char *argv[ ] )
{ ……
}
说明:
第1个参数是指命令行中参数的个数,含文件名本身。
第2个参数是一个指向字符串的指针数组。
main函数是由系统调用的。当处于操作命令状态下,输入main所在的文件名(经过编译、连接后得到的可执行文件名),系统就调用main函数。参数应和命令一起给出。 命令形式:
命令名
参数1
参数2
……参数n 例如:有一个目标文件名file1,今想将两个字符串“China”, “Beijing”作为传送给main函数的参数。可写成:
file1 China Beijing
例:编写一程序echo.c,实现将命令行上除程序名之外的所有给出的其他参数都回显到显示器上。
main(int argc, int *argv[ ]) { while(argc>1) { ++argv;
printf(“%s”, *argv);
-- argc; } }
若将该程序编译、连接、装配成echo.exe,则在命令行上输入:
echo hello, world! 则通过虚实结合后得:argc=3,argv[0]指向echo,argv[1]指向hello,argv[2]指向world! 结果为:hello, world!
§10.8有关指针的数据类型和指针运算的小结
一、有关指针的数据类型的小结
见书中的表
二、指针运算小结
1、指针变量加(减)一个整数 例:p++、p--、p+i、p-=I等
2、指针变量赋值
将一个变量地址赋给一个指针变量。 p=&a; p1=p2;
3、指针变量可以有空值,即该指针变量不指向任何变量。 如 :
p=NULL;
4、两个指向同一数组元素的指针变量可以相减
5、两个指向同一数组的指针变量可作关系运算
习题举例:
习题10.4
有n个整数,使其前面各数顺序向右移m个位置,最后m个数变成最前面m个数。写一函数实现以上功能,在主函数中输入n个整数,并输出调整后的n个数。
main() { int number[20],n,m,I;
printf(“How many number?”);
scanf(“%d”,&n);
printf(“Input %d number: ”,n);
for( i=0; i
scanf(“%d”,&number[i]);
printf(“How many place you want to move?”);
scanf(“%d”,&m);
move(number, n, m);
printf(“Now,they are: ”);
for( i=0; i
printf(“%d”, number[i]); } move(int array[20], int n, int m) { int *p,array_end;
array_end = *(array+n-1);
for(p= array+n-1; p>array; p--)
*p= *(p-1);
*array=array_end;
m--;
if(m>0) move(array, n, m); }
习题10.5 有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。 程序: main() { int i, k, m, n, num[50], *p;
printf(“Input number of person:n=”);
scanf(“%d”,&n);
p=num;
for( i=0; i
*(p+i) = i+1;
i=0; k=0; m=0;
while ( m
{ if( *(p+i)!=0) k++;
if(k==3)
{ *(p+i)=0; k=0; m++; }
i++;
if( i= =n) i=0;
}
while(*p==0) p++;
printf(“The last one is NO.%d ”,*p);
}
习题10.6
写出一个函数,求一个字符串的长度。在main函数中输入字符串,并输出其长度。 main() { int len;
char *str[20];
printf(“Input string:”);
scanf(“%s”, str);
len=length(str);
printf(“The length of string is %d.”,len); }
length(char *p) { int n;
n=0;
while(*p!=„�‟)
{ n++;
p++;
}
return(n); } 习题10.7
有一字符串,包含n个字符。写一个函数,将此字符串中从第m个字符开始的全部字符复制成为另一个字符串。 main() { int m;
char *str1[20],*str2[20];
printf(“Input string:”);
gets(str1);
printf(“Which character that begin to copy?”);
scanf(“%d”,&m);
if (strlen(str1)
printf(“Input error!”);
else { copystr(str1,str2,m);
printf(“result:%s”,str2);
} }
copystr(char *p1, char *p2, int m) { int n;
n=0;
while( n
{n++ ;
p1++ ;
}
while( *p1!=„�‟ )
{ *p2 = *p1 ;
p1++ ; p2++ ;
}
*p2=„�‟; }
习题10.9 写一个函数,将3×3的矩阵转置。 main() { int a[3][3],*p, i;
printf(“Input matrix: ”);
for( i=0; i<3; i++) scanf(“%d %d %d”, &a[i][0], &a[i][1] , &a[i][2]);
p=&a[0][0];
move(p);
printf(“Now,matrix: ”);
for( i=0; i<3; i++)
printf(“%d %d %d”,&a[i][0], &a[i][1], &a[i][2]);
} move(int *pointer) { int i, j, t;
for( i=0; i<3; i++)
for( j=i; j<3; j++)
{ t= *(pointer+ 3*i + j);
*(pointer+ 3*i +j) = *(pointer+ 3*j + i);
*(pointer+3*j + i )=t;
}
} 习题10.16
输入一个字符串,内有数字和非数字字符,如:
a123x456 17960?302tab5876 将其中连续的数字作为一个整数,依次存放到一数组a中。例如123放在a[0]中,456放在a[1]中……统计共有多少个整数,并输出这些数。 #include main() { char str[50], *pstr ;
int i, j, k, m, e10, digit, ndigit, a[10], *pa;
printf(“Input a string: ”);
gets(str);
printf(“ ”);
pstr=&str[0];
pa=&a[0];
ndigit = 0; i = 0; j=0;
while( *(pstr+i)!=„�‟)
{ if( (*( pstr+i )>=„0‟)&&(*( pstr+i )<=„9‟) ) j++;
else { if( j>0 )
{ digit = *(pstr+i-1)-48;
k=1;
while( k
{ e10=1;
for(m=1; m<=k; m++) e10 =e10*10;
digit =digit+(*(pstr+i-k)-48)*e10;
k++;
}
*pa=digit; ndigit++;
pa++;
j=0;
}
}
i++;
}
printf(“There are %d numbers in this line.They are: ”,ndigit );
j=0;
pa=&a[0];
for( j=0; j
printf(“%d”, *(pa+j));
printf(“ ”); } 步骤三 课堂小结
本课主要讲了一些习题,希望通过这些例子加深对指针的了解,看到指针在程序设计中的重要应用。同学们课后需要多看、多想、多练,逐步去体会指针这一重要的概念。 步骤四 布置作业
课后作业:第十章课后练习 10.10、10.11
第五篇:2010C程序教案(第10章)
【教学课题】
预编译处理
(第10章预编译处理,
1、2节) 【目的要求】
了解编译预处理的特点和功能,掌握编译预处理中的宏定义,理解文件包含。 【教学重点】
宏的定义与使用(无参和有参),理解带参的宏和函数的区别。 【教学难点】
宏的定义与使用(无参和有参),理解带参的宏和函数的区别。 【教学方法】
任务驱动法,问题引导法 【教学手段】
讲授+多媒体演示+学生动手 【作业布置】
1、定义一个带参数的宏,使两个参数的值互换,并写出程序,输入两个数作为使用宏时的实参。输出已交换的两个值。
2、分别用函数和带参的宏,从3 个数中找出最大数。
一、提出任务,引入课题 例1:#include main() { int a„„} 例2:#include #define N 100 main() { int a[N];„„ }。
一般C程序的开发执行过程: 编辑 → 编译 → 连接 → 执行 含有预处理命令的C程序:
编辑 → 预处理 → 编译 → 连接 → 执行
二、分析任务,讲授新课
C提供的预处理功能主要有以下三种: 宏定义、文件包含、条件编译。
分别用宏定义命令、文件包含命令、条件编译命令来实现。为了与一般C语句相区别,这些命令以符号“ #” 开头。
(一)宏替换(P172)
宏: 代表一个字符串的标识符。
宏名:被定义为“宏”的标识符。
宏代换(展开):在编译预处理时,对程序中所有出现的 “宏名”,用宏定义中的字符串去代换的过程。
不带参数的宏定义
A、一般形式: #define 标识符 替换文本 例如:#define PI 3.14159 main() { float l,r; printf( “Input a number :”); scanf (“%f”,&r); l=2*PI*r printf(“l=%f ”,l); } 说明:
⑴宏名一般用大写表示,以便与变量名区分。 ⑵使用宏名使程序易读,易修改。 ⑶只作简单的置换,不作正确性检查。 ⑷宏定义不是C语句,不必在行末加分号。 ⑸宏名的作用域一般从自定义命令到本源文件结束。 ⑹可以用# undef命令终止宏定义的作用域。 ⑺宏定义允许嵌套,允许层层置换。
⑻宏名在源程序中用双引号括起来,则TC中预处理不对其作宏代换。
例: printf(“L=%f”, L); 中双引号内L不替换。
⑼宏定义与定义的变量不同,宏只作字符替换,不分配内存空间。 ⑽对“输出格式”进行宏定义,可以减少书写麻烦. 举例:
例
1、不带参数的宏的程序(见P173)
2、带参数的宏定义
格式:#define 宏名(参数表) 替换文本
例:#define s(a,b) a*b {„„
area =s(3,2); „„}
对带参的宏展开后,为area=3*2; 说明:
⑴对带参数的宏展开只是将宏名后括号内的实参字符串代替#define命令行中的形参。 ⑵宏定义时,在宏名与带参数的括号之间不应加空格,否则将空格以后的字符都作为替代字符串的一部分。
⑶有参宏的展开,只是将实参作为字符串,简单地置换形参字符串,而不作任何语法检查。在定义有参宏时,在所有形参和整个字符串外,均加一对圆括号。
带参宏与函数的区别:
1、函数调用时,先求实参表达式值,后代入。而带参的宏只是进行简单的字符替换。
2、函数调用是在程序运行时处理的,分配临时的内存单元。而宏展开则是在编译时进行的,不分配内存单元,不进行值的传递,也无“返回值”。
3、对函数中的实参和形参都要定义类型,类型应一致。而宏不存在类型问题,宏名和参数无类型,只是一个符号代表,展开时代入指定的字符即可。
例
2、带参数宏的使用实例(P174)
二、 “文件包含”处理
“文件包含”处理是指将指定的被包含文件的全部内容插到该控制行的位置处,使其成为源文件的一部分参与编译。因此,被包含的文件应该是源文件。
通常置于源程序文件的首部,故也称为“头文件”。
C编译系统提供的头文件扩展名为“.h”,但设计者可根据实际情况,自行确定包含
文件的后缀、名字及其位置。
一般形式,#include “文件名” 或 #include <文件名> 二者的区别:
用尖括号时称为标准方式,系统到存放C库头文件所在的目录中寻找要包含的文件。
用双引号时,系统先在用户当前目录中寻找要包含的文件,若找不到,再按标准方式查找。
说明:
编译预处理时,预处理程序将查找指定的被包含文件,并将其复制到#include命令出现的位置。
常用在文件头部的被包含文件,称为“标题文件”或“头部文件”,常以“h”作为后缀。
一条包含命令,只能指定一个被包含文件。如果要包含多个文件,则要用多条包含命令。
文件包含可以嵌套,即被包含文件又包含另一个文件。
三、解决任务,学生实践
C语言中如何使用宏替换,如何使用文件包含。
四、针对难点,重点突破
1、带参数宏定义的替换。
2、带参数的宏和函数的区别。
五、拓展任务,学生实践
1、输入两个整数,求它们相除的余数,用带参的宏来实现,编程序。 提示:用一维数组存放所有约数。
六、检查任务,评价学生