C语言程序设计6-指针C-New_第1页
C语言程序设计6-指针C-New_第2页
C语言程序设计6-指针C-New_第3页
C语言程序设计6-指针C-New_第4页
C语言程序设计6-指针C-New_第5页
已阅读5页,还剩56页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、指针1) 变量与指针2) 数组与指针3) 函数与指针变量与指针指针变量的定义: 数据类型标识符 *变量名;注意: 1) * 是指针型变量,意为:指向的指针 2) 指针变量类型是指它所指向实体的类型注意:变量可以存放数值或字符,也可以存放地址指针变量的理解1、指针变量的地址:指针变量都是有地址的: &指针变量2、指针变量的值:所指向变量的地址:&变量3、指向值:指针(地址)对应的内存空间的值: *指针变量、*内存地址4、取值运算符*与取址运算符&的结合性自右向左, 优先级都处于第2位。&*p=p, *&a=a5、野指针: 定义指针变量,但没有赋给它确定地址 值。它对于系统或程序都是危险的,务必避

2、免!注意区别:*p+ 、(*p)+ 指针变量的赋值 1、指针变量的初始化 int a=10, b=20; int *p=&a, *q=&b; 2、指针变量的赋值 int a=10, b=20; int *p; p=&a; *p=b;1020FFC0FFC2FFC0FFC2FFC4FFC6abpq变量值变量名变量地址sizeof(char *), sizeof(int *), sizeof(float *), sizeof(double *) sizeof(p), sizeof(*p)推广:指向指针的指针二级指针指针变量可以保存普通变量的内存地址还可以保存指针变量的内存地址p是一级地址, *p是

3、p中存放的值q是二级地址, *q是q中存放的值(一级地址),*q是*q中存放的值 int a=10, b=20, c=30; int *p; int *q; p=&a; /把变量a的地址赋值给一级指针p q=&p; /把指针变量p的地址赋值给二级指针pvoid swap1(int a, int b) int t; t=a; a=b; b=t;void swap2(int a, int b) int *t; t=&a; &a=&b; &b=t;辨析函数语法是否正确?功能如何?void swap3(int *a, int *b) int t; t=*a; *a=*b; *b=t;void swap

4、4(int *a, int *b) int *t; *t=*a; *a=*b; *b=*t;void swap5(int *a, int *b) int *t; t=a; a=b; b=t; 对于同类型的一维数组aM和指针*p,若赋值p=a或p=&a0,则: 数组元素ai的地址可以等价用: &ai, a+i, &pi, p+i 数组元素ai的值可以等价用: ai, *(a+i), pi, *(p+i)一维数组与一级指针(1)pn:p向前或后移动nsizeof(Type)字节(2)指向同数组元素的指针允许关系运算与相减运算。 指针引用数组元素不必每次计算数组元素地址,读写 效率比下标法高,但要注

5、意下标是否越界,也要特别 注意指针变量当前值(当前指向地址)。# include int main() static int a5=1, 2, 3, 4; int *p, i; for(p=a, i=0; i5; i+) printf(%3d, *(p+i); printf(n); printf(%3d, *+p); printf(%3d, *p+); printf(%3d, (*p)+); printf(%3dn, +*p); for(p=a, i=0; i5; i+) printf(%3d, *(p+i); printf(n); return 0; 1 2 3 4 0 2 2 3 5 1

6、2 5 4 0理解二维数组aMN为一维数组a0a1aiaM-1 a00 a01 a0j a0N-1 a10 a11 a1j a1N-1 ai0 ai1 aij aiN-1 aM-10 aM-11 aM-1i aM-1N-1a一维数组名表示数组首元素地址a0=&a00, ai=&ai0*a=a0=&a00 (a=&a0=&a00)注意:地址在数值上即使是一样的,但基类型也可能不同对于同类型的二维数组aMN和一级指针*p,若赋值p=&a00、a0、*a ,则: 数组元素aij的地址&aij可以等价用(二维数组元素按行存放): &a00+N*i+j a0+N*i+j p+N*i+j 数组元素aij的

7、值可以等价用: *(&a00+N*i+j) *(a0+N*i+j) *(p+N*i+j)二维数组与一级指针# include void main() void select_sort(int *, int); / (int *x, int n); int a10, *p, i,; p=a; printf(Input 10 numbers:n); for(i=0; i10; i+) scanf(%d, p+); select_sort(a,10); / select_sort(p,10) ? printf(The sorted numbers:n); for(p=a, i=0; i10; i+)

8、 /printf(%d , *p), p+;printf(%d , *p+); printf(n);void select_sort(int *x, int n) int i, j, k, temp; for(i=0; in-1; i+) k=i;for(j=i+1; jn; j+)if(*(x+k)*(x+j) k=j;if(k!=i) temp=*(x+i); *(x+i)=*(x+k); *(x+k)=temp; # include int main() void average_grade (float *,int); / (float *p,int n) float score4=6

9、5,57,70,60,58,87,90,81,90,99,100,98; average_grade(*score,12); /注意: 实参与形参基类型匹配 return 0;/计算平均分: 二维数组用一维指针处理void average_grade(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(The average score of all students = %5.2fn,aver); return;理解二维数组a

10、MN为一维数组a0a1aiaM-1 a00 a01 a0j a0N-1 a10 a11 a1j a1N-1 ai0 ai1 aij aiN-1 aM-10 aM-11 aM-1i aM-1N-1a一维数组名表示数组首元素地址ai=&ai0=*(a+i), ai+j=&aij=*(a+i)+j*a=a0=&a00 (a=&a0=&a00) 注意1:地址在数值上即使一样,但基类型可能不同 注意2:i 和 j 移动的数据类型长度单位或基类型不同指向二维数组的数组指针行指针定义格式: 数据类型 (*变量名)每行元素个数 定义了指向二维数组的指针变量,该指针变量可以保存二维数组的行地址。 例如: int

11、 a43; int (*p)3; p=a;054a2765a31032a1981a0210a pFFCC获取二维数组下标i行地址(行指针或行地址)p 二维数组a下标0行地址;p+1 二维数组a下标1行地址;p+2 二维数组a下标2行地址;p+i 二维数组a下标i行地址。获取下标i行0列元素地址(变量指针或变量地址) *p 二维数组a下标0行下标0列元素地址; *(p+1) 二维数组a下标1行下标0列元素地址; *(p+2) 二维数组a下标2行下标0列元素地址; *(p+i) 二维数组a下标i行下标0列元素地址。获取下标i行j列元素地址(变量指针或变量地址) *(p+0)+j 下标0行下标j列元

12、素的地址; *(p+1)+j 下标1行下标j列元素的地址; *(p+i)+j 下标i行下标j列元素的地址。 *(*(p+0)+j) a0j元素值; *(*(p+1)+j) a1j元素值; *(*(p+i)+j) aij元素值。获取第i行第j列元素值(变量值)# include int main() /注意一维数组指针方括号中必须是常量表达式,且不能省略 void search_fail(float (*)4, int); / (float (*p)4, int n) float score4=65,57,70,60,58,87,90,81,90,99,100,98; search_fail(s

13、core, 3); return 0;二维数组的行指针:应用/查询并输出不及格者的成绩: 二维数组用行指针处理void search_fail(float (*p)4, int n) int i, j, flag; for(i=0; in; i+) flag=0; /注意对每一个学生, 标志数重新赋初值0for(j=0; j4; j+) if(*(*(p+i)+j)60) flag=1; break; if(flag) / flag=1 printf(No.%d fails, his scores are:n, i+1); for(j=0; j4; j+) printf(%6.1ft, *(*

14、(p+i)+j); printf(n); /查询并输出不及格者的成绩: 二维数组用行指针处理void search_fail(float (*p)4, int n) int i, j; for(i=0; in; i+) for(j=0; j4; j+) if(*(*(p+i)+j)60) break; if(j4) printf(No.%d fails, his scores are:n, i+1); for(j=0; j4; j+) printf(%6.1ft, *(*(p+i)+j); printf(n); # include # include void main() void sele

15、ct_sort(char (*)20, int); / (char (*p)20, int n) void print(char (*)20, int); / (char (*p)20, int n) char name20=China,England,France,Germany,America; int n=5; printf(The original sequence:n); print(name,n); select_sort(name,n); printf(nThe sorted sequence:n); print(name,n);void print(char (*p)20,in

16、t n) int i; for(i=0; in; i+, p+)/ printf(%sn,*p); puts(*p);选择法排序(行指针)/选择法排序(按照ACSII码值大小排序)void select_sort(char (*p)20,int n)/ char temp20; /等价于下面的两行! char array20; char *temp=array; / char *temp; /可省略array, 直接使用字符指针变量吗? int i, j, k; for(i=0; in-1; i+) k=i; for(j=i+1;j0) k=j; if(k!=i) strcpy(temp,pk

17、); strcpy(pk,pi); strcpy(pi,temp); 指针数组定义格式: 数据类型 *数组名元素个数作用:定义一个数组,数组中每个元素都是指针变量,保存指定数据类型的变量的地址(数组名是二级指针)。int a43;int *q4; /行数q0=a0;q1=a1;q2=a2;q3=a3;054a2765a31032a1981a0210aFFD8q3FFD2q2FFCCq1FFC6q0q 由于数组q中的每个元素保存了数组a中的每行首元素的地址,即,qi保存了a中下标i行首元素的地址,则: qi+j表示a中下标i行j列元素地址, *(qi+j)表示a中下标i行j列元素aij。 又根据

18、一维数组与指针的关系,有:q+i是指针数组下标i个元素的地址,则*(q+i)是指针数组下标i个元素的值,qi与*(q+i)等价。 因此,*(qi+j)可以写成*(*(q+i)+j)。# include int main() static int a=1,3,5,7; int *p3=a+2, a+1, a; int *q=p; printf(%dn,*(p0+1)+*(q+2); return 0;一维指针数组与二级指针变量/ 8 (7+1)pi 作为指针数组的元素,是指针变量。pi+j 中j的移动步长应该是pi所指向变量的单位。考虑p作为一维数组名,p+i 指针数组下标i元素的地址&pi。#

19、 include int main() char *name=China,England,France,Germany,America; char *p; int i; for(p=name, i=0; i5; i+) /*p是指针数组元素值, 即字符串首地址 printf(%s, %cn, *(p+i), *(*(p+i)+i); return 0;一维指针数组与二级指针变量China, CEngland, nFrance, aGermany, mAmerica, i# include # include void main() void select_sort(char *,int); /

20、 (char *name,int n) void print(char * ,int); / (char *name,int n) char *name=China,England,France,Germany,America; int n=5; printf(The original sequence:n); print(name,n); select_sort(name,n); printf(nThe sorted sequence:n); print(name,n);void print(char *name,int n) / 形参是指针数组 int i; for(i=0;in;i+)

21、printf(%sn, namei); / puts(namei);选择法排序(指针数组)/选择法排序(按照ACSII码值大小排序)/注意: 传递指针数组时, 处理的应该是指针数组元素的值。/ 而指针数组的每个元素都是指针变量, 值都是地址。void select_sort(char *name,int n) char *temp; int i,j,k; for(i=0;in-1;i+) k=i; for(j=i+1;j0) k=j; if(k!=i) /是否可以用strcpy, 为什么? /指针变量的互换: 交换地址 temp=namei; namei=namek; namek=temp;

22、格式: 数据类型 *数组名元素个数 作用:定义一个数组,其中每个元素保存指定数据类型的变量地址(指针数组名是二级指针)。指针数组 格式: 数据类型 (*变量名)元素个数 作用:定义了一个指针变量,该变量可以指向一个二维数组或二维数组的一行。指向二维数组的指针 数组(行)指针 注意:运算符的优先级与结合性 圆括号()和数组下标运算符的优先级为第1级,同时使用结合方向自左向右。指针(取值)运算符*、取址运算符&的优先级为第2级,同时使用结合方向自右向左。 区别:(*p)N、*qM (*p)N是二维数组指针或行指针,指向一个包括N个元素的二维数组或二维数组的一行,指针的值是该二维数组或其中某行的行地

23、址,而*qM是一维指针数组,该数组有M个元素,每一个元素都是指针变量,可以存放地址值。 概括1用指针理解和引用二维数组aMN,可按步进行: 1)获得下标i行地址: a+i ; 2)获得下标i行0列元素的地址: *(a+i) ; 3)获得下标i行j列元素的地址: *(a+i)+j ; 4)获得下标i行j列元素的值: *(*(a+i)+j) 。进而,若定义数组行指针(*p)N或指针数组*qM, p=a; 或 for(i=0;iM;i+) qi=ai; 则二维数组a中元素可以用q或p等价引用。注意:地址在数值上即使是一样的,但基类型也可能不同 注意:i 和 j 移动的数据类型长度单位或基类型是不同的

24、!概括2 二维数组、指向一维数组的指针变量(一维数组指针或行指针)、指针数组都可以引用二维数组元素。因此,二维数组元素的引用方法有3种。 int aMN,i;int (*p)N; 列数int *qM; 行数p=a;for(i=0;iM;i+) qi=ai; aij,*(ai+j),*(*(a+i)+j), (*(a+i)jpij,*(pi+j),*(*(p+i)+j), (*(p+i)jqij,*(qi+j),*(*(q+i)+j), (*(q+i)j 对于同类型的二维数组aMN、二维数组行指针(*p)N 、一维指针数组*qM、二级指针*r,注意它们的相互关系: p=a; /正确,二维数组a基

25、类型是行指针(*)N for(i=0;im;i+) qi=ai; /正确,符合指针数组的定义 r=q; /正确,q本质上是二级指针 q=a; /错误,q数组名是常量,且基类型也不一致 r=a; /错误,基类型不一致 注意:理解二维数组a为一维数组,则作为一维数组的值,有ai与*(a+i)等价。 注意:理解q是一维数组,则q+i是数组第i个元素的地址qi,而*(q+i)是数组第i个元素的值qi,故q+i与*(q+i)不同,但qi与*(q+i)等价。 对于同类型的二维数组aMN和二维数组指针(*p)N和一维指针数组*qM,若进行赋值p=a和for(i=0;im;i+)qi=ai,则: 数组行地址(

26、行指针)可以等价用: a+i, p+i 数组行首元素的地址(变量地址)可以等价用:ai, *(a+i), pi, *(p+i), qi, *(q+i) 数组元素aij的地址(变量地址)可以等价用:&aij,ai+j,*(a+i)+j&pij,pi+j,*(p+i)+j &qij,qi+j,*(q+i)+j 数组元素aij的值(变量值)可以等价用:aij,*(ai+j),*(*(a+i)+j),(*(a+i)jpij,*(pi+j),*(*(p+i)+j),(*(p+i)jqij,*(qi+j),*(*(q+i)+j),(*(q+i)j 对于同类型的二维数组aMN和一维指针数组*qM和二级指针*

27、r,若赋值for(i=0;im;i+)qi=ai和r=q,则: 数组行首元素的地址(变量地址)可以等价用: ai, qi, *(q+i), ri, *(r+i) 数组元素aij的地址(变量地址)可以等价用:&qij,qi+j,*(q+i)+j&rij,ri+j,*(r+i)+j 数组元素aij的值(变量值)可以等价用:pij,*(pi+j),*(*(p+i)+j),(*(p+i)jrij,*(ri+j),*(*(r+i)+j),(*(r+i)jchar string =Welcome you !;char string20; /string=Welcome you !; Error ?scan

28、f(%s, string); printf(%sn, string);char *p=Welcome you !; /初始化为字符串首地址char *p; p=“Welcome you !”; /赋值为地址gets(p); puts(p); /区别scanf, printf调用语法和功能char *string3=Welcome, you, !;char *p= string; /指针数组首元素地址&string0指针与字符串示例: 注意字符指针的当前指向# include void main( ) char *str=I love China!;/ char str =I love Chin

29、a!; / OK ? str+=7; puts(str);China!辨别A:字符串复制# include void main( ) char a =I am a teacher.; char b =You are a student.; char *pa=a; / 字符指针指向字符数组 char *pb=b; puts(a), puts(b); puts(pa), puts(pb); for(; *pa; pa+, pb+) / *pa!=0*pb=*pa; *pb=0; / 注意pa, pb当前指向. 注释掉会如何呢? puts(a), puts(b); pa=a, pb=b; / 注释掉

30、会如何呢? puts(pa), puts(pb); 字符指针指向变量或字符数组,相应的地址可写辨别B:字符串复制# include void main( ) /字符指针指向字符串常量 char *pa=I am a teacher.; char *pb= You are a student.; puts(pa), puts(pb); for(; *pa; pa+, pb+)*pb=*pa; *pb=0; puts(pa), puts(pb); 字符指针指向字符串,相应的地址是常量,不可写!/ Error !/ Error !第4节 函数指针与指针函数 函数是一段程序,和数据一起放在内存中的。任

31、何一段程序也有一个首地址。函数的调用,实际上是靠一个转向指令使程序转向被调用函数所在的内存地址而执行的。称一个函数在内存中的首地址(入口地址)为该函数的指针,可以用函数指针变量指向它(函数名)。 函数指针变量的定义格式: 数据类型 (*指针变量名)(函数参数表列) 这里“数据类型”为函数返回值的数据类型。定义了函数指针变量后,可以把函数名直接赋给它,使函数指针变量指向了该函数。而后引用函数指针变量,实际上就是“调用”函数。用函数指针变量调用函数# include int add(int x, int y) return x+y; int sub(int x, int y) return x-y

32、; void main( ) int x,y; int (*fun)(int x,int y); fun=add; x=(*fun)(30,40); fun=sub; y=(*fun)(50,20); printf(x=%d,y=%dn,x,y);定义函数指针变量给指针变量赋值,并引用指针变量函数指针变量指向返回值和参数序列一致的一类函数# include void main()int max(int,int);int min(int,int);void process(int,int,int (*fun)(int,int); /函数声明int a,b;printf(please input

33、two integer: a,bn);scanf(%d,%d,&a,&b);printf(max=); process(a,b,max); /函数调用printf(min=); process(a,b,min); /函数调用int max(int x,int y) return(xy?x:y);int min(int x,int y) return(xy?y:x);void process(int x,int y,int (*fun)(int,int) /函数定义int z=(*fun)(x,y); printf(%dn, z); /函数指针变量指向返回值,参数序列一致的一类函数用指向函数的指

34、针作函数参数 1、函数返回值的类型: 一个函数在被调用之后可以带回一个值返回给主调函数,这个值可以是整型、浮点型、字符型等,当然也可以是指针类型。 2、返回指针值函数声明的语法格式如下: 类型标识符 *函数名(形参列表) 指针型函数返回指针值的函数# include char *string_name(int n) char *string=illegal string,string 1,string 2,string 3; return (n3)?string0:stringn;void main( ) int i; char *string; printf(Input one intege

35、r i (1=i=3):); scanf(%d, &i); string=string_name(i); printf(The string %d is:n, i+1); printf(%sn, string);指针型函数示例# include void main() float *search(float (*pointer)4); float score4=60,70,80,90,56,89,67,88,34,78,90,66; float *p; int i,j; for(i=0;i3;i+) p=search(score+i); /调用函数查看该学生是否有不及格课程if(p=*(sco

36、re+i) /判断地址以否一致 printf(No.%d scores: , i+1); for(j=0;j4;j+)printf(%6.2f, *(p+j); printf(n); /函数返回值是地址float *search(float (*pointer)4) /注意:这里方括号内4不能省略 int i; float *pt; pt=*(pointer+1); /问题:该语句作用是什么? for(i=0;i4;i+) if(*(*pointer+i)60) pt=*pointer; break; /问题:该语句作用和下一行语句等价吗?/ return(pt); return(pt); /

37、问题:这一行语句可以省略吗?函数指针变量 指针型函数函数是一段程序,和数据一起放在内存中的。函数名代表函数的首地址(入口地址)。称一个函数在内存中的首地址为该函数的指针。可以定义函数指针变量,把函数名直接赋给它,使函数指针变量指向该函数。然后引用函数指针变量,实际上就是调用函数。 数据类型 (*指针变量名)(函数参数表列) 返回值为指针变量的函数,称为指针型函数。 类型标识符 *函数名(形参列表) 注意:运算符的优先级与结合性 圆括号()和数组下标运算符的优先级为第1级,同时使用结合方向自左向右。 区别:指针函数*fun()和函数指针(*fun)() *fun()是指针型函数,即函数返回值是指

38、针型数据,而(*fun)()是指向函数的指针,指针的值是函数的入口地址。 函数指针 指针函数命令行参数 分析DOS状态时以下命令: copy c:autoexec.bat d: dir 上面两行都称为命令行,每个命令行由多个参数构成,参数之间用空格分隔。 第1个命令行的参数分别为: copy、c:autoexec.bat、d: 第2个命令行的参数分别为:dir main函数中的命令行参数 main函数也可以定义形式参数,其形参值可以由命令行参数获取。命令行参数由两部分构成:第1个参数为“可执行程序”,第2个以后参数为“行参数”,行参数往往由多个字符串构成。1、main函数的一般形式: 1) m

39、ain(argc, argv) int argc; char *argv; 2) main(int argc, char *argv); 2、main函数参数的来源:命令行 3、main函数的形参的含义: 1) argc表示命令行中字符串的总个数; 2) argvi指向第i+1个字符串; 示例1# include void main(int argc, char *argv) int i; for(i=0;iargc;i+) printf(argv%d: %sn,i,argvi); printf(argc=%dn,i);命令行参数的使用:1 VC+环境下编译建立可执行程序:mytest.exe

40、2 运行cmd,在DOS下执行程序:mytest welcome(回车)# include # include # include void main(int argc, char *argv) int x,s=0,i; if(argc2) printf(input error!n); exit(0); for(i=1;iargc;i+) x=(int)strlen(argvi); s+=x; printf(s=%dn,s); 示例2指针小结:常用指针类型(以整型为例)int * p; p为指向整型数据的指针变量。变量指针int (*p)n; p为指向含n个元素的一维数组的指针变量。数组指针i

41、nt *pn; 定义了指针数组p,含有n个元素,每个元素 都是一个整型指针变量。指针数组int (*p)( ); p为指向函数的指针,函数返回值为整型。函数指针int *p( ); p为返回值是整型指针的函数。指针函数int *p; p为二重指针,它指向一个指向整型数据的指针 变量。指针指针 指向void类型的指针1、定义: 允许使用空类型(void)指针,即不指定该指针指向 一个固定的类型。2、语法格式: void *p;3、作用: void 类型指针不指向一个确定的类型数据,其作用 存放一个地址,但该地址存放数据类型不确定。 注意: 1) 若想将一个变量的地址存放到一个void指针中, 需

42、进行强制类型的转换。 2) 也可以定义一个返回空类型指针的函数。 动态分配内存空间使用malloc函数可以申请动态内存,函数原型是: void * malloc(字节数)由于malloc函数返回void*类型的指针值,因此,在应用时应通过强制类型转换运算符(数据类型*),把函数值转换成指向确定的数据类型,调用格式为: (数据类型*) malloc(字节数)例如: char *q; q=(char *)malloc(100 *sizeof(char); strcpy(q, Welcome you!);可以获得保存30个字符的连续内存空间 。 注意:应该用free函数释放由malloc函数申请的动态内存,函数原型是:void free(void *)。# include # include /# include void main( ) char *string; int m; printf(Input the maximum length of string: ); scanf(%d%*c,&m); string=(char *)malloc(m*sizeof(char);if(!strin

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论