C语言函数指针.docx

上传人:b****6 文档编号:15582483 上传时间:2023-07-05 格式:DOCX 页数:16 大小:22.56KB
下载 相关 举报
C语言函数指针.docx_第1页
第1页 / 共16页
C语言函数指针.docx_第2页
第2页 / 共16页
C语言函数指针.docx_第3页
第3页 / 共16页
C语言函数指针.docx_第4页
第4页 / 共16页
C语言函数指针.docx_第5页
第5页 / 共16页
C语言函数指针.docx_第6页
第6页 / 共16页
C语言函数指针.docx_第7页
第7页 / 共16页
C语言函数指针.docx_第8页
第8页 / 共16页
C语言函数指针.docx_第9页
第9页 / 共16页
C语言函数指针.docx_第10页
第10页 / 共16页
C语言函数指针.docx_第11页
第11页 / 共16页
C语言函数指针.docx_第12页
第12页 / 共16页
C语言函数指针.docx_第13页
第13页 / 共16页
C语言函数指针.docx_第14页
第14页 / 共16页
C语言函数指针.docx_第15页
第15页 / 共16页
C语言函数指针.docx_第16页
第16页 / 共16页
亲,该文档总共16页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

C语言函数指针.docx

《C语言函数指针.docx》由会员分享,可在线阅读,更多相关《C语言函数指针.docx(16页珍藏版)》请在冰点文库上搜索。

C语言函数指针.docx

C语言函数指针

函数

函数的定义

<函数类型>函数名(形参1类型形参1,...,形参n类型形参n)

{

函数体

}

(1)函数类型是用来说明调用该函数后返回值的数据类型。

一个函数被调用后都会返回给调用者一个确定的值,称为函数的返回值。

它可以是基本数据类型,也可以是自定义数据类型,若省略该项,则系统默认为int型。

函数也可以没有返回值,这时类型说明应定义为void类型,即空类型。

(2)形参即形式参数,它只能是变量,用于在调用函数和被调用函数之间进行数据传递,通过它接受来自调用者的数据。

因此也必须进行类型说明。

形参表可以是空的,此时应当用void来说明无参数,表示被调用函数不接受来自调用者的任何数据,但函数名后面的()不能省略。

也可以由多个形参组成,之间用逗号隔开,形参的作用范围仅限于本函数内部使用。

(3)若函数的函数体没有任何内容,该函数称为空函数,此时{}也不能省略。

(4)由于形参和内部变量仅限于本函数内部使用,所以可以在同一个程序的不同函数中定义相同的内部变量或形式参数名。

(5)当函数有返回值时,除了要进行函数类型说明外,在函数体中至少要有一条返回函数值的语句。

Return(表达式);

或者是

Return表达式;

其功能是将表达式中的值传递给调用者,并且将程序执行的控制流程转向调用程序,实现函数调用的返回。

其中的表达式值的类型应该与函数定义中的函数类型一致,否则将进行强制类型转换。

若函数没有返回值,则可使用不带表达式return语句实现返回,也可以没有return语句,函数执行到函数体中最后一条语句时自动结束。

(6)c语言规定在一个函数内部不能定义其他函数(即不能嵌套定义),这保证了每个函数的相对独立性,便于实现模块化设计,多个函数定义的顺序是任意的,函数定义的顺序不影响程序运行时的执行顺序。

函数调用与参数传递规则

函数调用的语法格式如下:

函数名(实参表);

如果是调用无参函数,则实参表是空的,但是括号不能省略。

如果实参表中各实参用逗号隔开。

实参可以是常量变量或者表达式。

实参和形参的个数影响等,类型应匹配。

如果实参和形参类型不一致,则会发生自动数据类型转换,将实参类型自动转换为形参类型,有可能损失精度,甚至导致错误。

三中调用方式:

(1)直接调用,以独立形式出现,只要求完成一定的操作,不要求返回值。

通常当函数类型为void类型,使用这样的调用方式。

如:

Printf("theresultis:

%ld",r);

(2)在表达式中调用

这时要求返回一个确定的值以参与表达式的运算。

(3)在函数的调用中以实参的形式出现

函数调用作为另一个函数的实参。

总之,只要能使用常量的地方均可以使用函数调用。

函数名:

clrscr  功能:

清除文本模式窗口清屏的意思就是把之前显示出的文字字符去掉跟cmd里面的清屏的功能是一样的实际上是clearscreen的简写  用法:

voidclrscr(void);

函数原型

主调函数调用被调函数之前,必须对被调函数进行函数原型声明。

函数类型函数名(形参1,形参2,...,形参n)

如果被调用函数位于主调函数之前可以不声明,但是最好是声明。

进行函数原型声明主要目的是为了让编译系统知道被调函数有几个参数,各自是什么类型,而参数的名字是无关精要的,可以省略。

如:

函数类型函数名(形参1类型,形参2类型,...,形参n类型);

一般将一个函数需要调用的所有函数原型放在变量定义语句之前。

函数间的信息传递方法

如果形参是数组形式,则实参必须是实际的数组名;如果实参是数组名,则形参可以是同维的数组名或指针。

当数组名作函数参数时,实际上形参与实参之间是地址传递。

实参数组将该数组的起始地址传递给形参数组,两个数组共享一个内存地址,编译系统不再为形参数组分配存储空间。

变量的作用域与生存期

C语言程序中占用的存储空间通常分为三个部分:

程序区,静态存储区和动态存储区。

其中程序存储区是存储可执行程序的机器指令,静态存储区存储的是需要占用固定存储空间的变量,动态存储区存储不需要占用固定存储空间的变量。

在c语言中,变量的定义包含三方面的内容,一是变量的数据类型,二是变量的作用域,变量的作用域是由变量的定义位置决定的。

三是变量的存储方式,不同的存储方式将影响变量值的保存时间,即生存期。

局部变量与全局变量

按作用域划分的。

函数内部定义的变量成为局部变量,函数的形参就是局部变量,其作用域仅限于定义该变量的函数内,离开该函数后再使用是非法的。

注意:

形参变量属于被调函数的局部变量。

允许在不同的函数中使用相同的变量名。

他们代表不同的对象,分配在不同的存储空间中。

注意:

在复合语句中也可以定义变量,其作用范围只在该复合语句内有效。

在函数外部定义的变量称为全局变量。

全局变量的作用域是从定义它的位置开始到本程序文件末为止。

即位于全局变量定义后面的所有函数都可以使用此变量。

在同一源程序中,允许全局变量和局部变量同名,此时在局部变量的作用域内,全局变量不起作用。

建议在第一个函数之前定义全局变量。

全局变量可用于函数之间的数据传递。

静态变量

静态存储通常是指在程序开始执行前就分配存储空间并一直保持到程序运行结束。

全局变量属于此类。

动态存储是指在程序运行过程中,只有在使用它时才分配存储空间,使用完毕立即释放空间。

函数的形参,函数的局部变量等,在函数定义是并没有给他们分配存储空间,只有在函数被调用时才分配存储空间,使用完毕立即释放他们所占用的空间。

使用auto和static对变量存储类型进行说明。

只有局部变量和形参才可能是动态存储类型。

形参只可以是动态存储类型,而局部变量都行。

对动态存储类型的变量可以省略说明关键字auto。

静态存储类型说明格式如下:

Static变量类型静态变量名

静态局部变量

有时希望调用函数结束后任然保持函数中定义的某些局部变量值,以便下次使用时继续使用原来的值,则可以将它定义为静态局部变量。

其他函数不能访问他。

他只在程序开始运行的时候赋一次初值,以后调用时不再赋值,而是保持上一次函数运行结束时的结果。

静态局部变量的默认初值为0。

静态全局变量

静态全局变量和全局变量的区别在于它只能在一个源文件内使用。

外部变量与外部函数

全局变量的作用域是在整个文件,而一个文件的全局变量可以通过外部变量的方式扩展到其他文件,即一个文件中定义的全局变量可以在另外一个文件中作为全局变量使用,该全局变量成为另一个文件的外部变量。

需用extern关键字说明,这种说明一般应放在文件开头且位于所有函数的外面。

Extern变量类型名外部变量名

如果一个文件中的全局变量的定义位于使用它的函数后面,则也用extern在要使用该全局变量的函数中说明是外部的,然后使用。

注意:

extern只能用来说明变量,不能用来定义变量,它只表示声明的变量已经在程序的其他地方定义过。

不能用extern来初始化变量,因为他不能定义变量。

内部函数:

又称静态函数,只能在定义它的文件中被调用,需要在函数前面加static说明。

外部函数:

函数在本质上都具有外部性质,除了内部函数之外,其他的函数都可以被其他文件中的函数调用。

有时为了强调它是一个外部函数,可以再进行函数原型的声明时使用extern说明。

递归函数

C语言中不允许函数嵌套定义,但允许嵌套调用,即在调用一个函数的过程中又可以调用另一个函数,如果在调用一个函数的过程中调用的是自己,则称为函数的递归调用。

定义:

如果出现直接或者间接地调用自己,则称该函数为递归函数。

一个函数的定义中也可以直接调用自己,如a中调用了b,b中又调用a,设计递归函数时应该注意避免出现死循环,一般应根据某一条件是否成立来判断是否继续调用。

求n!

Longfact(intn)

{

Longf;

If(n<=1)f=1;

Elsef=n*fact(n-1);

Returnf;

}

注意这里函数值就是f,重复调用fact(n)实现计算。

递归函数程序设计

两个要素:

(1)递归边界条件,对于问题的最简单情况,它本身不再使用递归的定义,而直接给出运算结果或者结束函数运行。

(2)递归定义要是问题逐步向边界条件转化。

 

指针

指针的概念

内存区中每一个字节有一个编号,这个编号就是内存地址,根据内存地址就可以找到所需的内存单元,通常把这个地址称为内存单元的指针。

指针就是内存单元的地址。

C语言有两种方式来访问内存单元,一是直接访问,直接访问根据变量名跟地址的对应关系,找到变量的地址,在该地址中存取数据。

间接访问是将变量的地址放在另一个变量中,可以定义一个特殊变量用来存放变量的地址。

存取数据时先找到地址变量,从中取出地址,再从地址中取出内存单元中的值。

称地址指向该变量单元,变量的地址称为该变量的指针。

如果有一个变量专门用来存放另一个变量的地址,称为指针变量。

指针变量的值就是另一个变量的内存地址,简称称为指针。

指针的定义及初始化

指针和其他变量一样,使用之前需要定义及初始化。

其定义格式如下:

类型名*指针变量名;如:

int*ap,a;

定义了一个指向整数型变量的指针变量ap和一个整型变量a。

在定义语句中使用*标示所定义的变量是一个指针变量。

注意:

指针变量名前的*表示该变量类型为指针变量,上例中的指针变量名是ap而不是*ap。

在定义指针变量时必须指定指针的类型,一个指针变量只能指向同一类型的变量。

这是由于每一个字节都有一个自己的内存地址编号,只有相同大小的指针变量可以存储相同数量的内存地址编号。

“*”表示“指向”的意思,如*ap表示指向指针变量ap所指向的变量,它是一个变量,跟上面定义的变量a是一回事。

指针变量初始化有两种方式,假设有指针变量p,要把整型变量a的地址赋予p。

(1)在定义时赋值

inta,*ap=&a;(定义了一个指针,并把变量a的地址赋给它。

将变量a的地址存放到指针变量ap中,ap就指向了变量a。

(2)在程序中赋值

Inta,*ap;

ap=&a;

可以把指针初始化为NULL(其宏值为0),表示空指针,即未指向任何变量的指针。

如:

Int*ap=NALL;

注意:

指针变量定义后若不赋值,其值是不确定的,此时不可以使用该指针,强行使用会引起系统崩溃。

指针变量的值为NULL时与未对指针变量赋值意义是不同的。

不能将一个非零的数据赋给一个指针变量,只能将他们的地址赋给指针变量。

如下面的操作是非法的:

int*ap;

ap=2000;

但ap=0是合法的,它表示ap未指向任何变量。

指针运算

*&a等价于a,*和&两个运算符的优先级相同,按自右而左的方向结合。

*&a

和*ap的作用都是等价于变量a。

指针的移动运算:

Int*p,i;

P+i表示的是在指针源地址上加上i个它所指向的变量所占用的内存单元数。

指针变量不能加上一个非整型量。

这里p+i的值为:

若p的值是1000,则这里的p+i的值为1000+2i。

对象距离运算:

两个指针变量可以相减,表示的是两个指针变量之间相差的同类型的变量的个数。

但不能进行加法运算。

指针的赋值运算:

(1)初始化赋值

Int*pa=&a;

或者

Inta,*pa;

Pa=&a;

(2)把一个指针变量的值赋给另外一个指针变量。

Inta,*pa=&a,*pb;

Pb=pa;

只有相同类型的指针才可以相互赋值。

(3)把数组的首地址赋给指向数组的指针变量。

Inta[5],*pa;

Pa=a;/*用数组名表示数组的首地址,因而可以赋给指针变量pa*/

也可以写为:

Pa=&a[0];

(4)把字符串常量的首地址赋予指向字符类型的指针变量。

Char*pc;

Pc="CLanguage";

或者用初始化赋值的方法:

Char*pc="CLanguage";

上面的例子只是把字符串的首地址装入指针变量。

(5)把函数的入口地址赋予指向函数的指针变量。

Int(*pf)();

Pf=f;/*f为函数名*/

指针关系运算:

指向同一类型的两个指针变量可以进行关系运算,比较两个指针值的大小。

(1)p1==p2表示p1和p2指向同一变量。

(2)p1>p2表示p1处于高地址位置。

(3)指针变量还可以与0比较,设p为指针变量,则p==0表明p是空指针。

P!

=0

表示它不是空指针。

指针与数组

数组名可以认为是一个常量指针,它指向数组的起始位置,指针变量可以完成对数组的各种操作。

引用数组元素可以用下标法,a[3],也可以用指针法,通过指向数组元素的指针找到所需的元素。

使用指针法对数组进行操作能使目标程序占内存少,运行速度快。

指针与一维数组:

一个数组是由连续的一块内存单元组成的,数组名就是这块连续内存单元的首地址。

每个数组元素按其类型不同占有几个连续的内存单元。

一个数组包含若干元素,每个数组元素都在内存中占用存储单元,他们都有相应的地址。

指针变量指向数组就是把数组起始地址放到一个指针变量中,指针变量也可以指向数组元素,即把某一元素的地址放到一个指针变量中。

所谓数组的指针是指数组的起始地址,数组元素的指针是指数组元素的地址。

指针指向数组的方法:

Inta[10];

Int*p;

P=&a[0];

它等价于

P=a;

通过指针引用数组元素:

如果指针p已经指向数组中的一个元素,则p+1指向同一数组中的下一个元素。

如果p的初值为&a[0],则:

(1)p+i和a+i都是a[i]的地址,或者说,他们指向数组a的第i个元素。

*(p+i)和*(a+i)是p+i或a+i指向的数组元素。

如:

*(p+5)或者*(a+5)就是a[5],即*(p+5)=*(a+5)=a[5]。

(2)指向数组的指针变量也可以带下标。

如p[i]与*(p+i)等价。

例子:

#include

Voidmain(void)

{

Inta[10];

Int*p,i;

Clrscr();

For(i=0;i<10;i++)a[i]=i;

Printf("%d",a[i]);

For(p=a;p

Getch();

}

注意:

(1)指针变量可以改变本身的值,如P++,但数组名只表示数组的首地址,不能改变,a++是错误的,a的值在程序运行期间是不变的,是常量。

(2)指针变量可以指向数组内存单元以后的地址中的变量,在使用时应当保证指针变量指向数组中的有效的元素。

(3)如果先运行语句p=a;,使p指向数组a,则:

(*p)++与*p++是不同的,p++使p指向下一元素的地址。

指针与二维数组

二维数组中的数据在内存中是连续存放的,并且是按行存放的,可以用指针变量逐一输出数组元素。

例子:

#include

#include

voidmain(void)

{

inta[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};

int*p;

clrscr();

for(p=a[0];p

printf("%4d",*p);

getch();

}

注意这里二维数组的首地址用a[0]来表示,或者用&a[0][0]表示,但不能用a表示,不同于一维数组。

指向数组的行指针变量

二维数组的行指针变量如下:

类型说明符(*指针变量名)[长度];

长度表示的二维数组的列数,第二维的长度。

圆括号不能省略,省略后就表示指针数组了。

例子:

#include

#include

voidmain(void)

{

inta[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};

int(*p)[4];

inti,j;

clrscr();

p=a;

for(i=0;i<3;i++)

{

for(j=0;j<4;j++)

{

printf("%2d",*(*(p+i)+j));

printf("\n");

}

}

getch();

}

语句int(*p)[4]表明一下几点:

P所指对象是每行有四个整型元素的二维数组,称为行指针。

P只指向列数为四的二维数组,p的值就是该数组的首行地址。

P不能指向数组行中间的元素。

P+i表示二维数组第i行的地址,即&a[i][0]。

*(p+i)+j表示该数组第i行j列的元素地址;*(*(p+i)+j)表示的是数组元素a[i][j]。

由于&a[0][0]和a[0]都代表该数组的开始地址,但不能赋给p,因为p表示数组第一行的四个元素的地址的存放地址,也可以用p+i表示第i行地址的首地址。

而a可以代表第一行地址的首地址,所以可以赋给p,还可以用p=&a[0]来赋给p,因为&a[0]表示的是数组首地址所在的行地址的首地址。

注意:

*(p+i)表示的是第i行的存放地址所指向的第一个元素,由于行地址存放的还是地址,所以第一个元素就是第i行第一个元素的地址。

行指针变量又可以称为指针的指针,它是一个地址,又存放了一行中所有元素的地址。

理解为“地址的地址”。

指针与字符数组

字符指针变量的赋值:

(1)char*cp;

cp="Iamastudent.";

(2)char*cp="Iamastudent.";

(3)char*cp,str[10];

cp=str;

scanf("%s",cp);

指针数组

若数组中的所有元素都为指针类型数据,则称该数组为指针数组,即指针数组中的每一个元素都相当于一个指针变量。

一维指针数组定义的语法格式如下:

类型名*数组名[数组长度];

如int*p[5]表示数组p含有5个元素,每个元素都是一个指向整型变量的指针。

C语言中常用指针数组来构造字符串数组,字符串数组中的每一个元素都是一个字符串。

如:

Char*p[4]={"spring","summer","autumn","winter"};

该声明语句中表明p[4]数组有4个元素,char*表明数组p的每一个元素都是指向char类型的指针,放在数组中的四个元素好像是存储在数组p中,但实际上只存储了指针,每一个指针都指向其对应字符串的第一个字符地址。

尽管数组p的大小固定,但它访问的字符串可以是任意长度。

指针与函数

在C语言中引入指针的重要意义还在于函数调用时其参数值可以作双向传递。

例子:

#include

#include

#include

Voidmain(void)

{

Voidswap(intx,inty);

Inti,j;

Clrscr();

Print("Inputtwointegersplease!

\n");

Scanf("%d%d",&i,&j);

Printf("\nmain1:

i=%dj=%d",i,j);

Swap(i,j);

Printf("\nmain3:

i=%dj=%d",i,j);

Getch();

}

Voidswap(intx,inty)

{

Intp;

P=x;

X=y;

Y=p;

Printf("\nswap2:

i=%dj=%d",i,j);

}

程序是为了通过swap函数交换变量i和j的值,但只是在swap函数中交换了,主函数中并未交换。

为了交换就需要用到指针参数。

指针参数

函数传递参数有下面两种方法:

(1)传递参数的值,通过实参将调用函数的值传递给被调函数,用return语句把一个值从被调函数传递给调用函数。

(2)传递变量的地址。

由于被调函数接收到的值是实际变量的地址,所以函数在执行过程中可以修改主调函数中相应变量的值。

指针型函数

当一个函数的返回值是一个指针(地址)时,这种函数称为指针型函数。

类型说明符*参数名(形参表)

{

.../*函数体*/

}

例如,char*strcat()表示strcat()是一个函数,它的返回值是字符型的指针。

函数指针

在c语言中,一个函数占用一片连续的内存区,函数名就是首地址,可以把首地址赋予一个指针变量,使该指针变量指向该函数,然后通过指针变量就可以找到并调用这个函数。

类型说明符(*指针变量名)(参数表)

指针的指针

一个指针中存放的的是另一个指针变量的地址,称为指针的指针。

类型标识符**指针变量名

若定义n级指针,则可以在变量名前面加n个*号。

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2