C语言程序设计第三章 模块化程序设计
——————————————————————————
——————————
济南大学第三章 模块化程序设计
3.1 模块化程序设计的方法与特点
3.2 函数的定义
3.3 函数参数和函数的值
3.4 函数调用和函数声明
3.5 函数的递归调用
3.6 库函数的使用
3.7 全局变量和局部变量
3.8 指针和指针作为函数参数
——————————————————————————
3.1 模块化程序设计的方法与特点
void stars(int n);
main( )
{
stars(20);
printf(“Han Shu!\n");
stars(20);
}
void stars(int n)
{ int i;
for (i=0; i<n; i++)
printf("*");
printf("\n");
}
main( )
{
int i;
for (i=0; i<20; i++)
printf("*");
printf("\n");
printf("Han Shu!\n");
for (i=0; i<20; i++)
printf("*");
printf("\n");
}
/*函数声明 */
/*函数调用 */
/*函数定义 */
/*函数调用 */
int max(int x,int y);
main( )
{ int a,b,c;
scanf("%d%d",&a,&b);
c=max(a,b);
printf("max=%d\n",c);
}
int max(int x,int y)
{ int z;
if (x>y) z=x;
else z=y;
return(z);
}
/*函数声明 */
/*函数调用 */
/*函数定义 */
1、一个较大的程序常分为若干模块,每个模块实现一个特定的功能 。
2,C语言中用函数来实现模块的功能 。一个C语言源程序文件通常由一个 main函数和若干个其它函数组成。
3、C程序的执行从 main函数开始,由主函数调用其它函数,
其它函数也可以相互调用,程序流程最后回到 main函数,在
main函数中结束整个程序的运行。
4、一个函数 ( 主调函数 ) 可以多次调用多个函数 ( 被调函数 )
。同一个函数也可以被一个或多个函数调用任意多次。但 不能调用 main函数 。 main
a b c
f
d e f g h i d
5、所有函数在定义时都是平行的,相互独立(一个函数并不从属于另一个函数),即函数 不能嵌套定义,但 可以相互调用 。
main( )
{ stars(20);
print_message( );
stars(20);
}
stars(int n)
{ int i;
for (i=0; i<n; i++)
printf("*");
printf("\n");
}
print_message( )
{ printf("How do you do!\n");
}
⑵,函数形式:
有参函数,主调函数与被调函数之间有数据传递
无参函数,主调函数与被调函数之间没有数据传递
int max(int x,int y)
{ int z;
if (x>y) z=x;
else z=y;
return(z);
}
void main( )
{ int a,b,c;
scanf("%d%d",&a,&b);
c=max(a,b);
printf("max=%d\n",c);
}
⑶,任务情况:
带返回值
不带返回值
6、函数分类:
⑴、使用情况:
标准函数,由系统定义,用户不必自己定义,可以直接使用
用户自定义函数
3.2 函数的定义
1、形式:
类型标识符 函数名 (形式参数表列 )
{
变量声明部分语句部分
}
2、说明:
①、函数名,用户给函数起的名字,必须符合标识符命名规则
②、类型标识符,指定函数返回值的类型若函数无返回值,函数定义时应写上 void
int max(int x,int y)
{
……
}
void main( )
{
……
}
③,形式参数表列,说明参数的个数和类型
书写格式,每一个参数都要写上数据类型和参数名 ; 参数之间 以逗号分隔,无参数时一般写上 void 或什么也不写
作用,表示从主调函数中 接收多少数据 以及 每个数据的类型
float average(float a1,float a2,float a3)
{
……
}
形参不能写成:
float a1,a2,a3 ×
④,变量说明:说明函数中用到的除形参以外的其它变量
⑤、语句部分:为了完成特定的功能而设计的一组语句
3、例:
①,打印一行信息,How do you do!”函数的定义:
void print_message( )
{
printf("How do you do!\n");
}
②,求整数 x的 n次幂( n>0) int power(int x,int n){
int i,mul=1;
for (i=1; i<=n; i++)
mul=mul*x;
return(mul);
}; float mul=1;
float
③,将指定的字符打印 n次
void print(char ch,int n)
{ int i;
for (i=0; i<n; i++)
putchar(ch);
putchar('\n');
}
print_message( );
mul=power(5,3);
print(?*?,20);
3.3 函数参数和函数的值
形式参数和实际参数
函数的返回值形式参数和实际参数
1、形式参数,定义函数 时函数名后面括号内的变量实际参数,调用函数 时函数名后面括号内的变量
#include <stdio.h>
int max(int x,int y);
void main( )
{ int a,b,c;
scanf("%d%d",&a,&b);
c=max(a,b);
printf("Max=%d.\n",c);
}
int max(int x,int y)
{ int z;
z=x>y?x:y;
return(z);
}
2、说明:
①、程序在编译时不为形参分配存储空间,只有 当函数被调用时,形参才被分配存储空间,并 在调用结束后释放所占的存储空间 。
②,形参只能是变量;而实参可以是 常量,变量,表达式 或具有返回值的函数调用,但要求它们 有确定的值 。调用时将实参的值赋给形参。
m=max(3,a+b); m=max(a,max(b,c) );
③,实参与形参的个数应相等,类型应一致或赋值兼容。
④,C规定,实参对形参的数据传递是,值传递,,即 单向传递 。 只能由实参传给形参,而不能由形参传回来给实参 。
在内存中,实参与形参占有不同的内存单元。
a 2 b 5
x y2 5 x 45 y 56
a 2 b 5
#include <stdio.h>
void fun(int i,int j)
{ int x=7;
printf("i=%d,j=%d,x=%d\n",i,j,x);
}
void main( )
{ int i=2,x=5,j=7;
fun( j,6 );
printf("i=%d,j=%d,x=%d\n",i,j,x);
}
i=7,j=6,x=7
i=2,j=7,x=5
#include <stdio.h>
void sum(int x,int y,int z)
{
z=x+y;
}
main( )
{ int a=1,b=2,c=0;
sum( a,b,c );
printf("c=%d\n",c);
}
1、函数的返回值是通过 return语句 获得的。
return语句的作用是 终止当前函数的执行 并 将一个确定值带回主调函数中。 return语句的一般形式是:
return(表达式 ); 或,return 表达式 ;
2、函数返回值的类型:在定义函数时指定
int max(int x,int y) double power(int x,int y)
C语言规定,凡不指定类型的函数,自动按 整型 (int)处理。
max(int x,int y) int max(int x,int y)
函数的返回值函数值的类型 与 return语句中 表达式的类型 应一致 ;若不一致,则 以函数类型为准 (自动转换)。
3、一个函数可以有多个 return语句,但每个 return后的表达式类型要相同;当执行到其中任何一个 return语句时会立即返回主调函数。
int isPrime(int m)
{ int i,k;
k=sqrt(m);
for (i=2; i<=k; i++)
if (m%i==0)
return(0);
return(1);
}
4、对于 有返回值的函数,若 return语句后面 没有表达式,或 没有 return语句,此时 带回一个不确定的返回值 。
5、为了明确表示“不带回值”,可以用
void定义,无类型,(或称,空类型,)。
stars(int n)
{ int i;
for (i=1; i<=n; i++)
putchar('*');
putchar('\n');
}
3.4 函数调用和函数声明
函数调用
函数声明
函数嵌套调用函数调用
1 函数调用的一般形式
1、形式:
函数名 (实参表列 );
2、说明
①、实参表列由0到多个 实参名 组成,实参之间用逗号分隔
②、实参与形参的个数应相等,类型应一致,顺序要一一对应
③、调用无参函数时格式为,函数名 ( );括弧不能省略
④,TC中按从右至左的顺序对实参求值
int i=0;
printf("%d,%d\n",++i,++i); 2,1
2 函数调用的方式
①,函数语句,
由函数调用加上分号构成,在主调函数中可作为一个独立的语句;此时不要求函数带回返回值
stars(20); print_message( );
②,函数表达式,
函数调用作为一个运算对象出现在表达式中,此时要求函数带回一个确定的值以参加表达式的运算
c=max(a,b);
③,函数参数,
函数调用作为另一个函数的实参,其值作为一个实际参数传给被调函数的形参进行处理;此时也要求函数带回一个确定值
m=max(a,max(b,c)); printf("%d\n",max(a,b) );
说明:
①、被调用的函数必须已经存在;
②,使用库函数时,应在文件开头用 #include命令将有关头文件包含进来; #include <stdio.h>
#include <math.h>
#include <string.h>
③,若用户自己定义的函数在主调函数之后,则应在主调函数之前对被调用的函数作 声明定义,对函数功能的确定;包括指定函数名、函数类型、形参及类型、函数体等。
声明,将函数的名字、函数类型以及形参的类型、个数和顺序通知编译系统
1、函数声明的格式:
函数类型 函数名 ( 形参表 );
float fun(double a,int b,float c)
{
……
}
如,float fun(double a,int b,float c);
函数声明
(1)、如果被调函数出现 在主调函数之前,可以不必进行声明。
int max(int x,int y)
{ ……
}
void main( )
{ ……
c=max(a,b);
……
}
(2)、如果已在 所有函数定义之前,在函数的外部已作了函数声明,则在各个主调函数中不必对所调用的函数再做声明。
#include "stdio.h"
void stars(int n);
void print_message( );
void main( )
{
stars(20);
print_message( );
stars(20);
}
void stars(int n)
{
……
}
void print_message( )
{
……
}
(3)、除以上三种情况,都应对所调用函数作类型声明,否则编译时出现错误。
2、说明:
在主函数中输入整数 m,编写函数判断是否是素数,在主函数中输出是否素数的信息。
#include <stdio.h>
#include <math.h>
int isPrime(int m)
{ int i,k;
k=sqrt(m);
for (i=2; i<=k; i++)
if (m%i==0)
return(0);
return(1);
}
void main( )
{ int m;
printf("Input int m:");
scanf("%d",&m);
if (isPrime(m)==1)
printf("%d is a prime!\n",m);
else
printf("%d is not a prime!\n",m);
}
函数的嵌套调用
C语言的函数 定义 都是互相平行的、独立的,即不允许嵌套定义函数(即在一个函数内部定义另一个函数);
但是,可以嵌套调用函数,即程序在调用一个函数的过程中,该被调函数又可以调用其它函数。
void main( )
{
:
fun( );
:
}
void fun( void )
{
:
g( );
:
}
main函数
fun函数
g函数调用调用嵌套调用分析下面程序的输出结果:
#include <stdio.h>
void fa(void)
{
putchar('a');
}
void fb(void)
{
fa( );
putchar('t');
}
void main(void)
{
putchar('c');
fb( );
}
cat
3.5 函数的递归调用在调用一个函数的过程中又直接或间接的调用自己,即函数的嵌套调用是函数本身。
int f(int x)
{ int y,z;
……
z=f(y);
……
return(z*z);
}
int f1(int x)
{ int y,z;
……
z=f2(y);
……
return(z);
}
int f2(int t)
{ int b,c;
……
c=f1(a);
……
return(3+c);
}
例:利用递归计算 n!
f(n)= n·f(n-1) (n>1)
1 (n=1)
double f(int n)
{ double y;
if (n==1)
y=1;
else
y=
return(y);
}
n*f(n-1);
void main( )
{ int n;
printf("\ninput n(n>0):");
scanf("%d",&n);
if (n<=0)
printf("Data error!\n");
else
printf("%d! =%.0lf\n",n,f(n));
}
函数调用过程:
main( )
{ ……
n=5;
print(f(5));
}
long f(5)
{ long y;
……
y=5*f(4);
}
long f(4)
{ long y;
……
y=4*f(3);
}
long f(3)
{ long y;
……
y=3*f(2);
}
long f(3)
{ long y;
……
y=3*f(2);
}
long f(2)
{ long y;
……
y=2*f(1);
}
long f(1)
{ long y;
y=1;
……
}
return(1);return(2);return(6);
return(6);return(24);return(120);
递归的条件:
1、须有完成函数任务的语句;
double f(int n)
{ double y;
if (n==1) y=1;
else y=n*f(n-1);
return(y);
}
2、一个确定是否能避免递归调用的测试;
3、一个递归调用语句;
该语句的参数应该逐渐逼近结束条件,以至最后断绝递归。
4、先测试,后递归调用。
在递归函数定义中,必须先测试,后递归调用。也就是说,递归调用是有条件的,
满足了条件后,才可以递归。
double f(int n)
{ double y;
y=n*f(n-1);
if (n==1) y=1;
return(y);
}
3.6 库函数的使用
1、形式:
#include <头文件名 > 或 #include,头文件名”
2、说明
C语言系统提供了大量的库函数,为了方便使用,这些库函数分别包含在不同的头文件中。例如,输入 /输出函数包含在,stdio.h”中、数学函数包含在,math.h”中。为了使用这些系统函数必须将这些头文件加入到程序中。
3.7 全局变量和局部变量
局部变量和全局变量
变量的存储类别
内部函数和外部函数局部变量和全局变量
1 作用域与生存期一,作用域,指变量能够起作用的 程序范围如果一个变量在某源程序文件或某函数范围内有效,则称该文件或函数为该变量的作用域。
局部变量全局变量从作用域角度二,生存期,指变量在内存中存在的 时间范围静态变量动态变量从生存期角度变量在整个程序的运行时间都存在变量只在某个函数的执行过程中才存在
2 局部变量
1、定义:
局部变量,指在一个函数内部定义的变量只在本函数的范围内有效,在此函数之外不能使用
2、例,float f1(int a)
{ int v1,x;
……
}
char f2(void)
{ int v2,x,y;
……
}
main( )
{ int m,y;
……
}
a,v1,x的有效范围
v2,x,y的有效范围
m,y的有效范围
3、说明:
①,main函数中定义的变量是局部变量,它们只能在 main
函数中使用
②、不同函数中可以使用相同名字的变量,它们代表不同的对象,占用不同的内存单元,互相独立
③、形式参数也是局部变量
④、可以在复合语句中定义变量,其作用域只是本复合语句
void main( )
{ int a,b;
……
{ int c;
c=a+b;
……
}
……
}
c在此范围内有效 a,b在此范围内有效
void main( )
{ int i,a=0;
for (i=1; i<=2; i++)
{ int a=1;
a++;
printf("i=%d,a=%d\n",i,a);
}
printf("i=%d,a=%d\n",i,a);
}
i=1,a=2
i=2,a=2
i=3,a=0
3 全局变量
1、定义:
全局变量,指在所有函数外部定义的变量,又称 外部变量可以为本文件中其它函数所共用,其有效范围为,从定义变量的位置开始到本源文件结束
2、例:
#include <stdio.h>
int p=1,q=5 ;
float f1( int a )
{ float r ;
:
}
int s ;
int f2( int b,int c ) ;
{ int sum ;
:
}
float m,n ;
void main( )
{ float x,y ;
:
}
全局变量 p和
q的有效范围全局变量
s的有效范围全局变量 m和
n的有效范围
3、说明:
①、全局变量 增加了函数间的数据联系 ;
由于在同一文件中的所有函数都能使用全局变量,所以可以利用全局变量从函数中 得到一个以上的返回值全局变量名的第一个字母常用 大写字母 表示例 8.15:编写函数计算 10个学生的最高分、最低分和平均分
#include <stdio.h>
float Max=0,Min=100;
float average(int n)
{ int i;
float s,sum=0;
for (i=1;i<=n;i++)
{ scanf(“%f”,&s);
if (s>Max) Max=s;
if (s<Min) Min=s;
sum+=s;
}
return(sum/n);
}
②,建议不要过多的使用全局变量
全局变量在程序的执行过程中一直占用存储单元
它使函数的通用性降低
会降低程序的清晰性 #include <stdio.h>
int k;
void show( )
{
for (k=1; k<=10; k++)
putchar('*');
putchar('\n');
}
void main( )
{
for (k=1; k<=4; k++)
show( );
}
③、若全局变量与局部变量同名,则 在局部变量的作用范围内,全局变量不起作用
int a=3,b=5;
int max(int a,int b)
{ int c;
c=a>b? a,b;
return(c);
}
void main( )
{ int a=8;
printf("%d",max(a,b) );
}
形参 a,b的作用域全局变量 a,b不起作用局部变量 a的作用域全局变量 b的作用域全局变量 a不起作用
④、若全局变量在文件开头定义,则在整个程序中都可以使用;若不在开头定义,其作用域只限于说明处到文件结束。如果想在定义之前的函数中引用该全局变量,则在函数中用关键字,extern”作“外部变量声明”,在函数内部,从声明之处起
,可以使用它们。
#include <stdio.h>
int max(int x,int y)
{ int z;
z=x>y? x,y;
return(z);
}
void main( )
{ extern int a,b;
printf("%d",max(a,b) );
}
int a=13,b=-8;
变量的存储类别
1 两种存储方式一,存储空间的划分,
程序区静态存储区动态存储区
用于存放程序编译后形成的可执行代码(执行时装入)
用于存放程序中的静态数据,如全局变量等
用于存放程序中的动态数据,如函数形参、局部变量、
函数调用时的现场保护和返回地址等二,两种存储方式,
静态存储方式,存放在静态存储区,并在程序执行过程中始终占用该单元,直到程序结束才释放;
动态存储方式,存放在动态存储区,在函数开始执行时分配存储空间,函数结束时释放这些空间。
2 局部变量的存储方式
1、函数中的局部变量,如不专门声明为 static,都是动态分配存储空间的,数据存储在动态存储区中。用关键字 auto作存储类别的声明,称为 自动变量 或 动态变量 。通常 auto被省略。
auto int b,c=3;
auto float f;
int b,c=3;
float f;
自动变量包括,函数内定义的变量,形参 和 复合语句内定义的变量 。
2,局部静态变量 ( static)
函数编译时在静态存储区分配存储单元,函数调用结束后不释放存储单元,直到程序运行结束才释放存储单元,即 在整个程序的运行中不释放存储单元 。
static int i,area;
说明:
①、静态局部变量采用静态存储方式,而自动变量采用动态存储方式
②、若对变量赋初值,对于静态变量,只执行一次,再次调用函数时不再赋初值而 保留上次函数调用结束时的值 ;而对于自动变量,每次调用都要重新分配内存单元并赋初值
void f(int c)
{ int a=0;
static int b=0;
a++; b++;
printf("%d,a=%d,b=%d\n",c,a,b);
}
void main( )
{ int i;
for (i=1; i<=3; i++)
f(i);
}
1,a=1,b=1
2,a=1,b=2
3,a=1,b=3
适用范围:
①、需要保留函数上一次调用结束时的值;(占用永久性的存储空间)
②、对于数组进行初始化,通常定义为静态存储类别
3,寄存器变量 ( register)
一般情况下,变量都是存放在内存中的。为了减少从内存中存取变量值的时间,C语言允许将局部变量的值 放在寄存器中,用关键字 register声明。
int fac(int n)
{ register int i,f;
for (i=1; i<=n; i++)
f=f * i;
return(f);
}
说明:
①、只有局部自动变量和形参可以定义为寄存器变量;
②、不能定义太多的寄存器变量,
因为寄存器数量有限,太多无效(
将 自动按自动变量处理 )。
3 全局变量的存储方式全局变量是 在函数外部定义 的,存放在静态存储区,在程序的整个运行过程中占用存储单元,生存期为整个程序的运行期间。
全局变量有两种存储类别,static和 extern,用来对其作用域进行限制或扩充 。
1、如果想在定义之前的函数中引用全局变量,则在函数中用关键字,extern”作“外部变量声明”,在函数内部,从声明之处起,可以使用它们。 ……
void main( )
{ extern int a,b;
printf("%d",max(a,b) );
}
int a=13,b=-8;
2、如果一个C程序由多个源程序文件组成,那么一个某文件中的函数能否引用另一个文件中的全局变量,有两种情况:
①,在一个文件中要引用另一文件中定义的全局变量,要在引用它的文件中用 extern作声明
file1.c
int Max;
void main( )
{
……
}
file2.c
extern int Max;
int power( )
{
Max=12;
……
}
在文件 file1.c中定义的变量 Max,在文件 file2.c中引用,
引用前加上 extern进行声明。
②、如果要全局变量仅限于被本文件中的函数引用,其它文件不能使用。定义全局变量时用 static进行声明
file1.c
static int Max;
void main( )
{
……
}
file2.c
extern int Max;
int power( )
{
Max=12;
……
}
×
加上 static,限制了 Max的作用域,在 file2.c中引用失败;但不管是否加上 static,Max都按静态存储方式存放
4 关于声明与定义一,函数的声明与定义定义,对函数功能的确定;包括指定函数名、函数类型、
形参及类型、函数体等。
声明,将函数的名字、函数类型以及形参的类型、个数和顺序通知编译系统二,变量的声明与定义定义,定义性声明,为变量建立存储空间声明,引用性声明,不为变量建立存储空间广义的说,声明包括定义,但不是所有的声明都是定义。
int a; 既是声明,又是定义
extern int a; 是声明不是定义内部函数和外部函数一,内部函数,
如果限制一个函数只能被 本文件 中其它函数所调用,称为内部函数(或静态函数)。定义时在函数类型前加 static。
static int fac(int x)
{
……
}
二,外部函数,
定义时在函数类型前加关键字 extern。
extern int fac(int x)
{
……
}
C语言规定,如果在定义函数时省略 extern,则隐含为外部函数。在需要调用此函数的文件中,要用 extern声明所调用函数的原型 。
3.8 指针和指针作为函数参数
指针的概念
指针变量的定义和引用
指针变量作为函数参数指针的概念
1 数据的存取一,内存地址,在计算机中,把内存区划分为一个一个的存储单元,每个单元为一个字节(8位),它们都有一个编号,这个编号就是内存单元的地址。如下图所示:
注意,
1、程序中定义的每个数据在编译后都占有各自的内存区。
2、数据所占有的存储单元个数是由其类型决定的。
3、首地址:第 1个单元的地址
4、表示地址的数与整数的区别二,内存单元的 地址 和内存单元的 内容

低地址高地址
2000
2002
2004
3000
i
j
k
00000011
00000000
0000010100000000
如:
int i,j,k;
i=3;
j=5;
程序编译后已经没有 i,j,k这些变量名了,而是将 变量名 转换为 变量的地址,计算机通过内存地址对变量进行存取。
2 直接访问和间接访问一,直接访问,按变量的地址存取变量的方式
①,i=3; ②,j=i+2;
③,printf("%d",i);
④,scanf("%d",&i);
⑤,k=i+j; 如何执行?

低地址高地址
2000
2002
2004
3000
i
j
k
00000011
00000000
0000010100000000
二,间接访问,将变量 i的地址存放在另一个变量中。先找到存放 i的地址的变量,从中取出 i的地址,然后到这个地址中取出 i的值。
00001000
00000000
2000 ip
ip=&i
三,“指向”的含义变量 ip的值为 2000,即 变量 i的地址,这样就在 ip和 i之间建立了一种联系:
通过变量 ip知道变量 i的地址,从而找到变量 i的内存单元,
因此说 变量 ip指向变量 i,用箭头表示这种,指向,关系。
将数值 10送到变量 i中,两种表示方法:
ip i
3000 2000
2000
i ip i
3000 2000
2000
10 2000 10
3 指针与指针变量通过地址能找到所需的变量单元,可以说:地址,指向,
该变量单元。因此,把一个 变量的地址 称为该变量的,指针,

如果有一个 变量 专门用来存放另一个变量的地址,则称它为,指针变量,。
指针变量就是一个变量,和我们以前所讲的其它变量没有本质区别。不同之处在于这种变量中所存放的内容是 地址 。指针,变量的地址指针变量,存放地址的变量指针变量的定义和引用
1 指针变量的定义一,格式,
类型名 *指针变量名
①,,*”表示定义的是 指针变量 ;
②、,类型名,用来指定该指针变量可以 指向的变量的类型 ;
二,例如,int *p1,*p2;
float i,*ip;
三,说明,
①、,*”只表示定义的变量为指针变量,但指针变量名中并不包含,*”;,*”是指针变量的标志,不可丢掉;
②,指针变量定义时,指定了它所指向的变量的数据类型;
p1 p2
i ip
i的地址? ——&i
ip=&i
p1=&i 错
③,指针变量定义时必须指定其所指向的变量的数据类型,
而且 使用过程中只能指向同一种类型的变量 。
④,指针变量定义后,系统为变量分配一个存储单元,用来存放地址;根据存储单元的长度分为 大存储模式 ( 长指针,4
Byte)和 小存储模式 ( 短指针,2 Byte);
⑤,指针变量定义后,若不赋值,其值是不确定的。
int
float&i
&i
2 指针变量的赋值一,赋值语句,
二,初始化,
int i,j,*p1,*p2;
p1=&i; p2=&j;
char ch,*cp1,*cp2;
cp1=&ch; cp2=&ch;
int x=4 int x;
x=4;
int i,*p=&i; int i,*p;p=&i;
注意,只能用同类型变量的地址进行赋值!
如定义,int *s; float f; 则 s=&f;是非法的。
分析有关指针的程序时,画图是很好的方法
3 指针变量的引用一,两个运算符,&与 *
&:取地址运算符,例如,&a为变量 a的地址
*:指针运算符取内容
*p为指针变量 p所指向的变量的内容二,说明
a,&既可作用于一般变量,也可作用于指针变量
b,* 只能作用于指针变量
c,定义指针变量时的 * 与该处的含义不同例如,int i,*p; p=&i;
i=5; *p=5 *p与 i等价例:
main()
{
int a,b;
int *p1,*p2;
a=100;b=10;
p1=&a;
p2=&b;
printf(“%d,%d\n”,a,b);
printf(“%d,%d\n”,*p1,*p2);
}
p1
p2
a
b
100
10
&a
&b
*p1
*p2
例:
main()
{
int *p1,*p2,*p,a1,a2;
scanf(“%d,%d”,&a1,&a2);
p1=&a1;p2=&a2;
if(a1<a2)
{p=p1;p1=p2;p2=p;}
printf(“\na1=%d,a2=%d\n”,a1,a2);
printf(“max=%d,min=%d\n”,*p1,*p2);
}
p1
p2
a1
a2
5
10
&a1
&a2
*p1
*p2
p
&a1
&a2
&a1
2
1
例:
main()
{
int *p1,*p2,t,a1,a2;
scanf(“%d,%d”,&a1,&a2);
p1=&a1;p2=&a2;
printf(“\na1=%d,a2=%d\n”,a1,a2);
if(a1<a2)
{t=*p1;*p1=*p2;*p2=t;}
printf(“\na1=%d,a2=%d\n”,a1,a2);
}
三,指针变量可以进行的操作赋值,int a,*p1=&a,*p2; p2=p1;
输出,printf(“%x”,p1);
增减,p1++; p2--; p1+=4; (只能和一个整数)
取内容,*p1=5; a=5; printf(“%d”,*p1);
反映了指针变量的引用方法:
①、将变量的地址赋给指针变量 (p1=&a1)
②,将一个指针变量赋给另一个指针变量 (p2=p1)
③,通过指针变量间接访问它所指向的变量 (*p1)
指针变量作为函数参数问题的提出:在子函数中如果要返回 n个值到主函数。除了使用全局变量外还有其他办法吗?(不提倡用全局变量)
指针变量作为函数的参数:
1、形式,只需要形式参数名前加上一个 *即可。
如,void swap(int *pointer,char f,char *s)
2、说明参数的传递是值传递,单向的(从实参到形参)。那么如何理解通过指针作为参数可以改变主调函数中变量的值呢?
形参得到实参的值 (一个地址 ),函数中可以通过形参引用该地址,从而可以 改变该地址对应变量的值 。但如果形参本身改变了,其值不会传给实参。
求三个数的总和和平均值用函数实现:
void mav(int a,int b,int c,int *p1,float *p2)
{*p1=a;
if(*p1<b) *p1=b;
if(*p1<c) *p1=c;
*p2=(a+b+c)/3.0;
}
main()
{int a,b,c,max,*p1;float ave,*p2;
scanf(“%d%d%d”,&a,&b,&c);
p1=&max;p2=&ave;
mav(a,b,c,p1,p2);
printf(“max=%d,ave=%f”,max,ave);
}
主函数的变量:
12 5 7
子函数的变量:
&ave&max
7512
&ave&max
a cb
a
p2p1
cb
p2p1
avemax 12 8.0
#include <stdio.h>
void swap(int *px,int *py)
{ int temp;
temp=*px;
*px=*py;
*py=temp;
}
void main( )
{ int a,b,*p1,*p2;
printf("\nInput a,b,");
scanf("%d%d",&a,&b);
p1=&a;
p2=&b;
if (a<b)
swap(p1,p2);
printf("max=%d,min=%d\n",a,b);
}
5a 8b
&ap1 &bp2
不定px 不定py&a &b
8 5
8a 5b
&ap1 &bp2
#include <stdio.h>
void swap(int *px,int *py)
{ int *p;
p=px;
px=py;
py=p;
}
void main( )
{ int a,b,*p1,*p2;
printf("\nInput a,b,");
scanf("%d%d",&a,&b);
p1=&a;
p2=&b;
if (a<b)
swap(p1,p2);
printf("max=%d,min=%d\n",a,b);
}
5a 8b
&ap1 &bp2
不定px 不定py&a &b&b &a
5a 8b
&ap1 &bp2
如果想通过函数调用得到几个要改变的值,可以:
①,在主调函数中设 n个变量;
②、将 n变量的地址作为实参传给所调用的函数的形参;
③、通过形参指针变量,改变该 n个变量的值;
④、主调函数就可以使用这些改变了的值。
作 业
1、编写函数,计算 a与 b的平方根之和。 a,b在主函数中输入,结果由被调函数返回。
2、编写函数,求和:
ns u m 21
1
321
1
21
11
n在主函数中由键盘输入,被调函数返回 sum的值。
3、以下程序的功能是应用下面的近似公式计算 e的 n次方。函数 f1用来计算每项分子的值,函数 f2用来计算每项分母的值。
请编写函数 f1和 f2。
!20!3!2
1
2032 xxx
xe x
float f2(int n)
{
……
}
float f1(int x,int n)
{
……
}
void main( )
{ float exp=1.0;
int x,n;
scanf("%d",&x);
exp+=x;
for (n=2; n<20; n++)
exp+=f1(x,n)/f2(n);
printf("\nexp(%d)=%.4f\n",x,exp);
}
4、编写递归函数,用于计算?
n
i
i
1
f(n)= n+f(n-1) (n>1)
1 (n=1)
5,判断 101-200之间有多少个素数,并输出所有素数。
6,从 3个红球,5个白球,6个黑球中任意取出 8个作为一组,
要求在每组中可以没有黑球,但必须有红球和白球。输出这样的组合数有多少?并且输出每组中的红、白、黑球数。
T h e E n d