1、C语言程序设计Soochow University1主要内容F地址和指针的概念地址和指针的概念F变量的指针和指向变量的指针变量变量的指针和指向变量的指针变量F数组的指针和指向数组的指针变量数组的指针和指向数组的指针变量F字符串的指针和指向字符串的指针变量字符串的指针和指向字符串的指针变量F函数的指针和指向函数的指针变量函数的指针和指向函数的指针变量F返回指针值的函数返回指针值的函数F指针数组和指向指针的指针指针数组和指向指针的指针F有关指针的数据类型和指针运算的小结有关指针的数据类型和指针运算的小结F习题习题C语言程序设计Soochow University28.1 指针是什么C语言程序设计S
2、oochow University3地址和指针的概念F变量定义时的内存分配变量定义时的内存分配a如果在程序中定义了一个变量,在编如果在程序中定义了一个变量,在编译时就给这个变量分配内存单元。系译时就给这个变量分配内存单元。系统根据程序中定义的变量类型,分配统根据程序中定义的变量类型,分配一定长度的空间。一定长度的空间。F内存单元的地址和内存单元的内内存单元的地址和内存单元的内容这两个概念的区别容这两个概念的区别a内存区的每一个字节有一个编号,内存区的每一个字节有一个编号,这就是这就是“地址地址”,它相当于旅馆,它相当于旅馆中的房间号。中的房间号。a在地址所标志的内存单元中存放在地址所标志的内存
3、单元中存放数据,这相当于旅馆中各个房间数据,这相当于旅馆中各个房间中居住旅客一样。中居住旅客一样。C语言程序设计Soochow University4地址和指针的概念F变量的变量的“直接访问直接访问”方式通过变量名来访问方式通过变量名来访问a在程序中一般是通过变量名来对内存单元进行存取操作的。其实在程序中一般是通过变量名来对内存单元进行存取操作的。其实程序经过编译以后己经将变量名转换为变量的地址,对变量值的程序经过编译以后己经将变量名转换为变量的地址,对变量值的存取都是通过地址进行的。存取都是通过地址进行的。F变量的变量的“间接访问间接访问”方式方式保存变量地址的变量:保存变量地址的变量:i_
4、pointer=&i;这时,这时,i_pointer的值就是的值就是2000,即变量,即变量i所占用单元的起始地址。所占用单元的起始地址。变量的变量的“间接访问间接访问”过程过程:先找到存放先找到存放“i的地址的地址”的变量,即的变量,即i_pointer,从中取出,从中取出i的地址的地址(2000),然后到,然后到2000、2001字节取出字节取出i的值的值(3)。C语言程序设计Soochow University5地址和指针的概念F“直接访问直接访问”和和“间接访问间接访问”方式下变量的存储过程方式下变量的存储过程为了表示将数值为了表示将数值3送到变量中,可以有两种表达方法送到变量中,可以
5、有两种表达方法:(1)将将3送到变量送到变量i所标志的单元中。所标志的单元中。(2)将将3送到变量送到变量i_pointer所所“指向指向”的单元的单元(即即i所标志的单元所标志的单元)中。见上图。所谓中。见上图。所谓“指向指向”就是通过地址来体现的。就是通过地址来体现的。F“指针指针”和和“指针变量指针变量”一个变量的地址称为该变量的一个变量的地址称为该变量的“指针指针”。如果有一个变量专门用来存放另一变量的地址如果有一个变量专门用来存放另一变量的地址(即指针即指针),则它,则它称为称为“指针变量指针变量”。指针变量的值指针变量的值(即指针变量中存放的值即指针变量中存放的值)是指针是指针(地
6、址地址)。请区分。请区分“指针指针”和和“指针变量指针变量”这两个概念。这两个概念。C语言程序设计Soochow University68.2 指针变量C语言程序设计Soochow University7定义一个指针变量F指针变量也必须指针变量也必须先先定义后定义后使用使用F定义指针变量的一般形式:定义指针变量的一般形式:a基类型基类型*指针变量名指针变量名F指针变量的基类型:指针变量的基类型:a用来指定该指针变量可以指向的变量的类型。用来指定该指针变量可以指向的变量的类型。a指针变量只能用来指向和其基类型指针变量只能用来指向和其基类型的变量,如基类型为的变量,如基类型为int的指针变量只能用
7、来指向整型变量,的指针变量只能用来指向整型变量,。aint*pointer_1,*pointer_2,a;a用赋值语句可使一个指针变量指向另一个变量用赋值语句可使一个指针变量指向另一个变量C语言程序设计Soochow University8在定义指针变量时要注意两点F(1)指针变量前面的指针变量前面的“*”,表示该变量的类型为,表示该变量的类型为指针型变量。指针型变量。a注意:注意:指针变量名是指针变量名是pointer_1、pointer_2,而不是,而不是*pointer_1、*pointer_2。F(2)在定义指针变量时必须指定基类型。例如只在定义指针变量时必须指定基类型。例如只有整型变
8、量的地址才能放到指向整型变量的指针有整型变量的地址才能放到指向整型变量的指针变量中。变量中。C语言程序设计Soochow University9指针变量的引用F指针变量中只能存放地址指针变量中只能存放地址(指针指针),不要随便将一个整型不要随便将一个整型常量常量(或任何其他非地址类型的数据或任何其他非地址类型的数据)赋给一个指针变量赋给一个指针变量。F两个有关的运算符两个有关的运算符a(1)&:取地址运算符。取地址运算符。a(2)*:指针运算符指针运算符(或称或称“间接访问间接访问”运算符运算符)。例如:例如:&a为变量为变量a的地址,的地址,*p为指针变量为指针变量p所指向的存储单元。所指向
9、的存储单元。F注意:指针使用前必须先初始化!注意:指针使用前必须先初始化!apointer_1=&i;注意:注意:规则修改:指针必须先定义并且初始化后,才可以使用规则修改:指针必须先定义并且初始化后,才可以使用C语言程序设计Soochow University10指针变量的引用程序举例例:通过指针变量访问整型变量。例:通过指针变量访问整型变量。main()int a,B,*pointer_1,*pointer_2;/*这里出现这里出现*表示指针定义表示指针定义*/a=100;B=10;/*把变量把变量a的地址赋给的地址赋给pointer_1,不是,不是*pointer_1=&a*/pointe
10、r_1=&a;/*把变量把变量B的地址赋给的地址赋给pointer_2,不是不是*pointer_2=&a*/pointer_2=&B;printf(%d,%dn,a,B);/*这里出现的这里出现的*表示对指针的使用表示对指针的使用*/printf(“%d,%dn”,*pointer_1,*pointer_2);/这里会出现什么结果这里会出现什么结果?prinft(“%d,%dn”,pointer_1,pointer_2);运行结果为:运行结果为:100,10100,10C语言程序设计Soochow University11对“&”和“*”运算符的深入说明F(1)如果已执行了如果已执行了“po
11、inter_1=&a;”语句,若有语句,若有&*pointer_1它的含义是什么?它的含义是什么?a&*pointer_1相当于相当于&aapointer_2=&*pointer_1apointer_2=pointer_1C语言程序设计Soochow University12(2)*&a的含义是什么?与a等价;*&a和*pointer_1的作用是一样的(假设已执行了“pointer_1=&a”),它们等价于变量a。即*&a与a等价,见图(3)(*pointer_1)+相当于a+。注意括号是必要的,如果没有括号,就成为了*pointer_1+,+和*为同一优先级别,相当于先做*pointer_1
12、,然后做pointer_1+对对“&”和和“*”运算符的深入说明运算符的深入说明C语言程序设计Soochow University13例:输入a和B两个整数,按先大后小的顺序输出a和B。main()int*p1,*p2,*p,a,B;scanf(%d,%d,&a,&B);p1=&a;p2=&B;if(aB)p=p1;p1=p2;p2=p;printf(na=%D,B=%Dnn,a,B);printf(max=%D,min=%Dn,*p1,*p2);运行情况如下:运行情况如下:5,9a=5,B=9max=9,min=5 当输入当输入a=5,B=9时,由于时,由于aB,将,将p1和和p2交交换。交
13、换前的情况见图换。交换前的情况见图(a),交换后见图,交换后见图(b)。结论:在使用指针时,结论:在使用指针时,我们要清楚操作的是指我们要清楚操作的是指针本身,还是指针所指针本身,还是指针所指向的变量向的变量C语言程序设计Soochow University14函数的参数回顾F形式参数和实际参数形式参数和实际参数a二者具有各自独立的内存空间二者具有各自独立的内存空间aC语言中函数参数传值是单向的语言中函数参数传值是单向的实际参数实际参数 形式参数形式参数F例如:例如:void swap(int n1,int n2)int temp;if(n1 n2)temp=n1;n1=n2;n2=temp;
14、void main()int a,b;scanf(%d%d,&a,&b);printf(a=%d;b=%d,a,b);swap(a,b);printf(a=%d;b=%d,a,b);输入输入:9 5输出输出:a=9;b=5输出输出:a=9;b=5C语言程序设计Soochow University15函数的参数回顾F函数的调用过程函数的调用过程a首先把首先把a、b的值复制到的值复制到swap函函数的堆栈区间,并赋值给行参数的堆栈区间,并赋值给行参n1、n2.a交换交换n1、n2的值。的值。a返回。返回。95调用函数运行状态返回地址9 /55 /99main()swap()abn1n2temp栈区
15、结果结果被调函数进行的操作被调函数进行的操作结果无法反应在主调函结果无法反应在主调函数中。数中。用传地址的形式用传地址的形式C语言程序设计Soochow University16指针作为函数参数F指针作为函数参数指针作为函数参数a将一个变量的地址传到另一个函数中。将一个变量的地址传到另一个函数中。F例如:例如:void swapp(int*n1,int*n2)int temp;if(*n1*n2)temp=*n1;*n1=*n2;*n2=temp;void main()int a,b;scanf(%d%d,&a,&b);printf(a=%d;b=%d,a,b);swapp(&a,&b);pr
16、intf(a=%d;b=%d,a,b);输入输入:9 5输出输出:a=9;b=5输出输出:a=5;b=9C语言程序设计Soochow University17指针作为函数参数F函数的调用过程函数的调用过程a首先把首先把a、b的地址值复制到的地址值复制到swapp函数的堆栈区间,并赋值给行参函数的堆栈区间,并赋值给行参n1、n2.a交换交换n1、n2所指向内存单元的值。所指向内存单元的值。a返回。返回。结果结果被调函数进行的操作结果反应被调函数进行的操作结果反应在主调函数中。在主调函数中。被调函数实际上是在主调函数被调函数实际上是在主调函数的堆栈区间中进行的操作的堆栈区间中进行的操作实际是一种地
17、址传递方式实际是一种地址传递方式95调用函数运行状态返回地址200820049main()swap()abn1n2temp栈区20042008C语言程序设计Soochow University18指针作为函数参数F指针变量作为函数参数典型错误举例一指针变量作为函数参数典型错误举例一swap(int*n1,int*n2)int*temp;*temp=*n1;*n1=*n2;*n2=*temp;F问题:问题:atemp没有初始化,指向的内存单元是不确定的没有初始化,指向的内存单元是不确定的C语言程序设计Soochow University19指针作为函数参数F指针变量作为函数参数典型错误举例二指针
18、变量作为函数参数典型错误举例二swap(int*n1,int*n2)int*p;p=n1;n1=n2;n2=p;95调用函数运行状态返回地址2008 /20042004 /20082008main()swap()abn1n2 p栈区20042008问题问题交换的只是两个形参所指向的内存单元。交换的只是两个形参所指向的内存单元。C语言程序设计Soochow University20指针变量作为函数参数F C语言中实参变量和形参变量之间的数据传递是语言中实参变量和形参变量之间的数据传递是单向的单向的“值传递值传递”方式。方式。指针变量作函数参数也指针变量作函数参数也要遵循这一规则,这时的值是指针的
19、值,也就是要遵循这一规则,这时的值是指针的值,也就是地址值。地址值。F 调用函数不可能改变实参指针变量的值,但可以调用函数不可能改变实参指针变量的值,但可以改变实参指针变量所指变量的值。改变实参指针变量所指变量的值。F 运用指针变量作参数,可以从函数调用中得到多运用指针变量作参数,可以从函数调用中得到多个变化了的值。如果不用指针变量是难以做到这个变化了的值。如果不用指针变量是难以做到这一点的。参考下例:一点的。参考下例:C语言程序设计Soochow University21指针作函数参数的实例main()int a,B,C,*p1,*p2,*p3;scanf(%d,%d,%d,&a,&B,&C
20、);p1=&a;p2=&B;p3=&C;exchange(p1,p2,p3);printf(n%d,%d,%dn,a,B,C);swap(int*pt1,int*pt2)int temp;temp=*pt1;*pt1=*pt2;*pt2=temp;exchange(int*q1,int*q2,int*q3)if(*q1*q2)swap(q1,q2);if(*q1*q3)swap(q1,q3);if(*q2*q3)swap(q2,q3);运行情况如下:运行情况如下:9,0,10 10,9,0指针举例 编写一个函数,实现将大写字母转换从小写字母,小写字母转换成大写字母。在main函数中测试该函数的
21、正确性。C语言程序设计Soochow University22C语言程序设计Soochow University238.3 通过指针引用数组C语言程序设计Soochow University24数组的指针和指向数组的指针变量F数组的指针数组的指针是指数组的起始地址是指数组的起始地址F数组元素的指针数组元素的指针是数组元素的地址。是数组元素的地址。F指向数组元素的指针指向数组元素的指针a定义一个指向数组元素的指针变量的方法,与以前介绍的指向变定义一个指向数组元素的指针变量的方法,与以前介绍的指向变量的指针变量相同。量的指针变量相同。例如:例如:int a10;int *p;p=&a0;C语言程序
22、设计Soochow University25指向数组元素的指针FC语言规定数组名代表数组的首地址,也就是第语言规定数组名代表数组的首地址,也就是第0号元素的地址。号元素的地址。下面语句等价:下面语句等价:p=&a0;p=a;或者或者int*p=&a0;int *p=a;a注意注意数组名数组名a不代表整个数组,上述不代表整个数组,上述“p=a;”的作用是的作用是“把把a数组的数组的首地址赋给指针变量首地址赋给指针变量p”,而不是,而不是“把数组把数组a各元素的值赋给各元素的值赋给p”。C语言程序设计Soochow University26通过指针引用数组元素F通过指针对数组元素赋通过指针对数组元
23、素赋值,如:值,如:*p=1;p=1;F如果指针变量如果指针变量p已指向已指向数组中的一个元素,则数组中的一个元素,则p+1指向同一数组中的指向同一数组中的下一个元素下一个元素(而不是将而不是将p值简单地加值简单地加1)。C语言程序设计Soochow University27数组元素指针使用的进一步理解如果如果p p的初值为的初值为&a0&a0,则:则:F(1)p+i和和a+i就是就是ai的地址的地址F(2)*(p+i)或或*(a+i)是是p+i或或a+i所指向的数组元素,即所指向的数组元素,即ai。例如,例如,*(p+5)或或*(a+5)就是就是a5。F(3)指向数组的指针变量也可以带下标,
24、如指向数组的指针变量也可以带下标,如pi与与*(p+i)等等价价数组元素引用的两种方法:数组元素引用的两种方法:F(1)下标法,如下标法,如ai或或pi形式,形式,p是指向数组的指针变量,是指向数组的指针变量,其初值其初值p=a。F(2)指针法,如指针法,如*(a+i)或或*(p+i)。其中。其中a是数组名,是数组名,p是指向是指向数组的指针变量,其初值数组的指针变量,其初值p=a。C语言程序设计Soochow University28数组元素指针使用例子例例:输出数组中的全部元素。假设有一个整型数组输出数组中的全部元素。假设有一个整型数组a,有,有10个个元素。要输出各元素的值有三种方法:元
25、素。要输出各元素的值有三种方法:(1)下标法。下标法。main()int a10;inti;for(i=0;i10;i+)scanf(%d,&ai);printf(n);for(i=0;i10;i+)printf(“%d”,ai);(2)数组名方法数组名方法main()int a10;inti;for(i=0;i10;i+)scanf(%d,&ai);printf(n);for(i=0;i10;i+)printf(“%d”,*(a+i);(3)指针方法指针方法main()int a10;inti;int*p;for(i=0;i10;i+)scanf(“%d”,p+i);printf(n);fo
26、r(p=a;p(a+10);p+)printf(%d,*p);C语言程序设计Soochow University29数组元素的指针变量使用过程中的注意事项(1)指针变量可以实现使本身的值改变,数组名是指针变量可以实现使本身的值改变,数组名是否也可以?否也可以?例如,上述第例如,上述第(3)种方法是用指针变量种方法是用指针变量p来指向元素,用来指向元素,用p+使使p的值不断改变,这是合法的。如果不用的值不断改变,这是合法的。如果不用p而使而使a变变化化(例如,用例如,用a+)行不行呢?行不行呢?答案是不行的答案是不行的,因为,因为a是数组首地址,这个地址在编译是数组首地址,这个地址在编译期就定下
27、来了,在程序运行过程中始终会保持不变。程期就定下来了,在程序运行过程中始终会保持不变。程序中如果出现序中如果出现a+,编译器在编译的时候就会报错。,编译器在编译的时候就会报错。(2)要注意指针变量的当前值要注意指针变量的当前值。(3)注意数组下标越界问题注意数组下标越界问题(4)注意指针变量的运算注意指针变量的运算(见见P236)C语言程序设计Soochow University30例例:通过指针变量输出通过指针变量输出a数组的数组的10个元素个元素请检查以下程序的正确性:请检查以下程序的正确性:main()int*p,i,a10;p=a;for(i=0;i10;i+)scanf(%d”,p+
28、);printf(n);for(i=0;i10;i+,p+)printf(“%d”,*p);p=a;数组元素的指针变量使用过程中的注意事项数组元素的指针变量使用过程中的注意事项C语言程序设计Soochow University31用数组名作函数参数 数组名可以用作函数的形参和实参。数组名可以用作函数的形参和实参。如:如:main()f(int arr,int n)int array10;f(array,10);当用数组名作参数时,如果形参数组中各元素的值发生变当用数组名作参数时,如果形参数组中各元素的值发生变化,实参数组元素的值随之变化。化,实参数组元素的值随之变化。实参数组名代表该数组首地址
29、,而形参是用来接收从实实参数组名代表该数组首地址,而形参是用来接收从实参传递过来的数组首地址的。因此,形参应该是一个指参传递过来的数组首地址的。因此,形参应该是一个指针变量。针变量。实际上,实际上,C编译都是将形参数组作为指针变量来处理的。编译都是将形参数组作为指针变量来处理的。f(int arr,int n)实际上相当于实际上相当于f(int*arr,int n)C语言程序设计Soochow University32实参数组名和形参数组名的区别:实参数组名代表一个固定的地址,或者说是指针型实参数组名代表一个固定的地址,或者说是指针型常量,而形参数组并不是一个固定的地址值。如:常量,而形参数组
30、并不是一个固定的地址值。如:f(int arr,int n)printf(%dn,*arr);/*输出输出array0的值,的值,*/arr=arr+3;printf(%dn,*arr);/*输出输出array3的值,的值,*/C语言程序设计Soochow University33用数组名作函数参数举例例例:设计一个函数将:设计一个函数将数组数组a中中n个整数按相反顺序存放,个整数按相反顺序存放,见下图示意。见下图示意。解此题的算法为:将解此题的算法为:将a0与与an-1对换,再将对换,再将a1与与an-2对对,直到将下图中的,直到将下图中的a(n-1)/2与与 an-int(n-1)/2)-
31、1对换对换。程序程序:C语言程序设计Soochow University34重要归纳归纳起来,如果有一个实参数组,想在函数中改变此数组的元素的归纳起来,如果有一个实参数组,想在函数中改变此数组的元素的值,实参与形参的表示形式有以下值,实参与形参的表示形式有以下4 4种情况:种情况:F(1)形参和实参都用数组名,如:形参和实参都用数组名,如:main()f(int x,int n)int a10;f(a,10);可以认为有一形参数组,与实参数组共用一段内存单元。可以认为有一形参数组,与实参数组共用一段内存单元。C语言程序设计Soochow University35重要归纳(2)实参用数组名,形参
32、用指针变量。如:实参用数组名,形参用指针变量。如:main()f(int*x,int n)int a10;f(a,10);实参实参a为数组名,形参为数组名,形参x为指向整型变量的指针变量,为指向整型变量的指针变量,函数开始执行时,函数开始执行时,x指向指向a0,即,即x=&a0。通过。通过x值的改变,可以指向值的改变,可以指向a数组的任一元素。数组的任一元素。C语言程序设计Soochow University36重要归纳(3)实参形参都用指针变量。例如:实参形参都用指针变量。例如:main()f(int*x,int n)int a10,*p;p=a;f(p,10);实参实参p和形参和形参x都是
33、指针变量。先使实参指针变量都是指针变量。先使实参指针变量p指向数组指向数组a,p的值是的值是&a0。然后将。然后将p的值传给形的值传给形参指针变量参指针变量x,x的初始值也是的初始值也是&a0。通过。通过x值的值的改变可以使改变可以使x指向数组指向数组a的任一元素。的任一元素。C语言程序设计Soochow University37重要归纳(4)实参为指针变量,形参为数组名。如:实参为指针变量,形参为数组名。如:main()f(int x,int n)int a10,*p;p=a;f(p,10);实参实参p为指针变量,它使指针变量为指针变量,它使指针变量p指向指向a0,即即p=a或或p=&a0。
34、形参为数组名。形参为数组名x,从前面的介绍已知,实际上将,从前面的介绍已知,实际上将x作为指针变量处理,今将作为指针变量处理,今将a0的地址传给形参的地址传给形参x,使指针变,使指针变量量x指向指向a0。也可以理解为形参数组。也可以理解为形参数组x取得取得a数组的首地址,数组的首地址,x数组和数组和a数组共用同一段内存单元。数组共用同一段内存单元。C语言程序设计Soochow University388.4 通过指针引用字符串C语言程序设计Soochow University39字符串的指针和指向字符串的指针变量 字符串的表示形式 字符数组法:用字符数组存放一个字符串。例如:main()cha
35、r string=IloveChina!;printf(%sn,string);C语言程序设计Soochow University40字符串的指针和指向字符串的指针变量字符串的表示形式字符指针法:用字符指针指向一个字符串。可以不定义字符数组,而定义一个字符指针。用字符指针指向字符串中的字符。例如:main()char*string=I love China!;printf(%sn,string);C语言对字符串常量是按字符数组处理的,在内存开辟了一个字符数组用来存放字符串常量。程序在定义字符指针变量string时把字符串首地址(即存放字符串的字符数组的首地址)赋给string。C语言程序设计S
36、oochow University41字符数组、字符串和字符指针的理解字符数组 存放字符数据的数组,没有字符串结束标志 在定义时可以整体初始化,但不能在非定义时进行整体初始化字符串 存放于字符数组中,必须有字符串结束标志 字符串在内存占有的字节数为长度1 在定义时可以整体初始化,但不能在非定义时进行整体初始化字符指针 可以指向字符数据的指针变量,可以指向字符数组,也可以指向字符串 在定义时可以初始化,也可以在非定义时进行初始化 必须先初始化,才可以使用字符串输出的理解:格式控制符“%s”C语言程序设计Soochow University42字符串指针作函数参数 使用字符指针变量和字符数组的比较
37、(见P263)字符串指针作函数参数与指针变量作函数参数的语法规定完全相同。copy_string函数的几种形式(见P261)目的:深刻体会指针给C程序带来的好处 简化程序的编写工作量,使得程序更简洁。指针给C程序带来的麻烦 需要仔细控制指针的使用 降低了程序的可读性字符指针应用举例 例如:编写一个函数,实现字符串str1与字符串str2的比较。编写一个函数,实现字符串str1与str2的拼接 编写一个函数,求字符串str1的长度C语言程序设计Soochow University43 非静态的局部变量是分配在内存中的动态存储区的,这个存储区是一个称为栈的区域 C语言还允许建立内存动态分配区域,以
38、存放一些临时用的数据,这些数据需要时随时开辟,不需要时随时释放。这些数据是临时存放在一个特别的自由存储区,称为堆区 对内存的动态分配是通过系统提供的库函数来实现的,主要有malloc,calloc,free,realloc这4个函数 以上4个函数的声明在stdlib.h头文件中,在用到这些函数时应当用“#include”指令把stdlib.h头文件包含到程序文件中。malloc函数 其函数原型为 void*malloc(unsigned int size);其作用是在内存的动态存储区中分配一个长度为size的连续空间函数的值(也就是函数的返回值)是所分配区域的第一个字节的地址,或者说,此函数是
39、一个指针型函数,返回的指针指向该分配域的开头位置 malloc(100);开辟100字节的临时分配域,函数值为其第1个字节的地址 注意指针的基类型为void,即不指向任何类型的数据,只提供一个地址 如果此函数未能成功地执行(例如内存空间不足),则返回空指针(NULL)2calloc函数 其函数原型为 void*calloc(unsigned n,unsigned size);其作用是在内存的动态存储区中分配n个长度为size的连续空间,这个空间一般比较大,足以保存一个数组。用calloc函数可以为一维数组开辟动态存储空间,n为数组元素个数,每个元素长度为size。这就是动态数组。函数返回指向所
40、分配域的起始位置的指针;如果分配不成功,返回NULL。如:p=(int*)calloc(50,4);开辟504个字节的临时分配域,把起始地址赋给指针变量p 等价于:p=(int*)malloc(50*4);例如:分配包含20个元素的整型数组:p=(int*)calloc(20,sizeof(int);p=(int*)malloc(20*sizeof(int);sizeof()运算符 计算数据类型在内存在占有的字节数 例如:sizeof(char):1byte sizeof(int):2 or 4bytes sizeof(double):8bytes 使用sizeof运算符可以提高程序的移植性。
41、在动态内存分配中,要求大家使用该运算符计算数据类型在内存占有的字节数。C语言程序设计Soochow University503free函数 其函数原型为 void free(void*p);其作用是释放指针变量所指向的动态空间,使这部分空间能重新被其他变量使用。p应是最近一次调用calloc或malloc函数时得到的函数返回值。free(p);释放指针变量所指向的已分配的动态空间 free函数无返回值4.realloc函数 其函数原型为void*realloc(void*p,unsigned int size);如果已经通过malloc函数或calloc函数获得了动态空间,想改变其大小,可以用
42、recalloc函数重新分配。用realloc函数将p所指向的动态空间的大小改变为size。p的值不变。如果重分配不成功,返回NULL,如:realloc(p,50);将p所指向的已分配的动态空间改为50字节 例8.30 建立动态数组,输入5个学生的成绩,另外用一个函放数检查其中有无低于60分的,输出不合格的成绩。解题思路:用malloc函数开辟一个动态自由区域,用来存5个学生的成绩,会得到这个动态域第一个字节的地址,它的基类型是void型。用一个基类型为int的指针变量p来指向动态数组的各元素,并输出它们的值。但必须先把malloc函数返回的void指针转换为整型指针,然后赋给p1#incl
43、ude#include void check(int*);int main()int*p1,i;p1=(int*)malloc(5*sizeof(int);for(i=0;i5;i+)scanf(%d,p1+i);check(p1);free(p1);return 0;void check(int*p)int i;printf(They are fail:);for(i=0;i5;i+)if(pi60)printf(“%d”,pi);printf(n);C语言程序设计Soochow University56 1.首先要准确地弄清楚指针的含义。指针就是地址,凡是出现“指针”的地方,都可以用“地址
44、”代替,例如,变量的指针就是变量的地址,指针变量就是地址变量 要区别指针和指针变量。指针就是地址本身,而指针变量是用来存放地址的变量。2.什么叫“指向”?地址就意味着指向,因为通过地址能找到具有该地址的对象。对于指针变量来说,把谁的地址存放在指针变量中,就说此指针变量指向谁。但应注意:只有与指针变量的基类型相同的数据的地址才能存放在相应的指针变量中。void*指针是一种特殊的指针,不指向任何类型的数据,如果需要用此地址指向某类型的数据,应先对地址进行类型转换。可以在程序中进行显式的类型转换,也可以由编译系统自动进行隐式转换。无论用哪种转换,读者必须了解要进行类型转换3.要深入掌握在对数组的操作
45、中怎样正确地使用指针,搞清楚指针的指向。一维数组名代表数组首元素的地址 int*p,a10;p=a;p是指向int类型的指针变量,p只能指向数组中的元素,而不是指向整个数组。在进行赋值时一定要先确定赋值号两侧的类型是否相同,是否允许赋值。对“p=a;”,准确地说应该是:p指向a数组的首元素4.有关指针变量的定义形式的归纳比较,见教材中表8.4(P289)。5.指针运算(1)指针变量加(减)一个整数例如:p+,p-,p+i,p-i,p+=i,-=i等均是指针变量加(减)一个整数。将该指针变量的原值(是一个地址)和它指向的变量所占用的存储单元的字节数相加(减)。(2)指针变量赋值 将一个变量地址赋给一个指针变量 不应把一个整数赋给指针变量5.指针运算(3)两个指针变量可以相减 如果两个指针变量都指向同一个数组中的元素,则两个指针变量值之差是两个指针之间的元素个数(4)两个指针变量比较 若两个指针指向同一个数组的元素,则可以进行比较 指向前面的元素的指针变量“小于”指向后面元素的指针变量 如果p1和p2不指向同一数组则比较无意义(5)指针变量可以有空值,即该指针变量不指向任何变量,可以这样表示:p=NULL;