第十章主要内容10.1地址和指针的概念10.2变量的指针和指向变量的指针变量10.3通过指针引用数组10.4通过指针字符串10.5指向函数的指针10.6返回指针值的函数10.7指针数组和多重指针10.8动态内存分配与指向它的指针变量10.1地址和指针的概念内存区的每一个字节有一个编号,这就是“地址”。如果在程序中定义了一个变量,在对程序进行编译时,系统就会给这个变量分配内存单元。1、按变量地址存取变量值的方式称为“直接访问”方式printf(″%d″,i);scanf(″%d″,&i);k=i+j;2.另一种存取变量值的方式称为“间接访问”的方式。即,将变量i的地址存放在另一个变量中。在C语言中,指针是一种特殊的变量,它是存放地址的。一个变量的地址称为该变量的“指针”。例如,地址2000是变量i的指针。如果有一个变量专门用来存放另一变量的地址(即指针),则它称为“指针变量”。上述的i_pointer就是一个指针变量。指针和指针变量的定义:10.2变量的指针和指向变量的指针变量10.2.1怎样定义指针变量定义指针变量的一般形式为基类型*指针变量名;下面都是合法的定义:float*pointer_3;char*pointer_4;可以用赋值语句使一个指针变量得到另一个变量的地址,从而使它指向一个该变量。例如:pointer_1=&i;pointer_2=&j;在定义指针变量时要注意两点:(1)指针变量前面的“*”,表示该变量的类型为指针型变量。例:float*pointer_1;指针变量名是pointer_1,而不是*pointer_1。(2)在定义指针变量时必须指定基类型。需要特别注意的是,只有整型变量的地址才能放到指向整型变量的指针变量中。下面的赋值是错误的∶floata;int*pointer_1;pointer_1=&a;在对指针变量赋值时需要注意两点:⑴指针变量中只能存放地址(指针),不要将一个整数赋给一个指针变量。例:*pointer_1=100;/*pointer_1是指针变量,100是整数,不合法*/(2)赋给指针变量的变是量地址不能是任意的类型,而只能是与指针变量的基类型具有相同类型的变量的地址。在引用指针变量时,可能有三种情况:⑴给指针变量赋值。如:p=&a;⑵引用指针变量的值。如:printf(“%o”,p);⑶引用指针变量指向的变量。有关的两个运算符:(1)&取地址运算符。&a是变量a的地址。(2)*指针运算符(或称“间接访问”运算符),*p是指针变量p指向的对象的值。10.2.2怎样引用指针变量例10.1通过指针变量访问整型变量#includestdio.hvoidmain(){inta,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\n″,a,b);printf(″%d,%d\n″,*pointer_1,*pointer_2);}例10.2输入a和b两个整数,按先大后小的顺序输出a和b。#includestdio.hvoidmain(){int*p1,*p2,*p,a,b;scanf(″%d,%d″,&a,&b);p1=&a;p2=&b;if(a<b){p=p1;p1=p2;p2=p;}printf(″a=%d,b=%d\n\n″,a,b);printf(″max=%d,min=%d\n″,*p1,*p2);}运行情况如下:5,9↙a=5,b=9max=9,min=5当输入a=5,b=9时,由于a<b,将p1和p2交换。交换前的情况见图(a),交换后见图(b)。10.2.3指针变量作为函数参数例10.3对输入的两个整数按大小顺序输出#includestdio.hvoidmain(){voidswap(int*p1,int*p2);inta,b;int*pointer_1,*pointer_2;scanf(″%d,%d″,&a,&b);pointer_1=&a;pointer_2=&b;if(a<b=swap(pointer_1,pointer_2);printf(″\n%d,%d\n″,a,b);}voidswap(int*p1,int*p2){inttemp;temp=*p1;*p1=*p2;*p2=temp;}例10.4输入3个整数a,b,c,要求按大小顺序将它们输出。用函数实现改变这3个变量的值。#includestdio.hvoidmain(){voidexchange(int*q1,int*q2,int*q3);inta,b,c,*p1,*p2,*p3;scanf(″%d,%d,%d″,&a,&b,&c);p1=&a;p2=&b;p3=&c;exchange(p1,p2,p3);printf(″\n%d,%d,%d\n″,a,b,c);}voidexchange(int*q1,int*q2,int*q3){voidswap(int*pt1,int*pt2);if(*q1<*q2)swap(q1,q2);if(*q1<*q3)swap(q1,q3);if(*q2<*q3=swap(q2,q3);}voidswap(int*pt1,int*pt2){inttemp;temp=*pt1;*pt1=*pt2;*pt2=temp;}10.3通过指针引用数组一个变量有地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量既然可以指向变量,当然也可以指向数组元素(把某一元素的地址放到一个指针变量中)。所谓数组元素的指针就是数组元素的地址。10.3.1数组元素的指针可以用一个指针变量指向一个数组元素。例如:inta[10];(定义a为包含10个整型数据的数组)int*p;(定义p为指向整型变量的指针变量)p=&a[0];(把a[0]元素的地址赋给指针变量p)也就是使p指向a数组的第0号元素。C语言规定在指针指向数组元素时,可以对指针进行以下运算:加一个整数(用+或+=),如p+1减一个整数(用-或-=),如p-1自加运算,如p++,++p自减运算,如p--,--p两个指针相减,如p1-p2(只有p1和p2都指向同一数组中的元素时才有意义)。10.3.2指针的运算分别说明如下:(1)如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素,p-1指向同一数组中的上一个元素。(2)如果p原来指向a[0],执行++p后p的值改变了,在p的原值基础上加d,这样p就指向数组的下一个元素a[1]。(3)如果p的初值为&a[0],则p+i和a+i就是数组元素a[i]的地址,或者说,它们指向a数组的第i个元素。(4)*(p+i)或*(a+i)是p+i或a+i所指向的数组元素,即a[i]。(5)如果指针变量p1和p2都指向同一数组,如执行p2-p1,结果是两个地址之差除以数组元素的长度。10.3.3通过指针引用数组元素引用一个数组元素,可以用:(1)下标法,如a[i]形式;(2)指针法,如*(a+i)或*(p+i)。其中a是数组名,p是指向数组元素的指针变量,其初值p=a。例10.5输出数组中的全部元素假设有一个a数组,整型,有10个元素。要输出各元素的值有三种方法:(1)下标法#includestdio.hvoidmain(){inta[10];inti;for(i=0;i<10;i++)scanf(″%d″,&a[i]);printf(″\n″);for(i=0;i<10;i++)printf(″%d″,a[i]);}(2)通过数组名计算数组元素地址,找出元素的值。#includestdio.hvoidmain(){inta[10];inti;for(i=0;i<10;i++)scanf(″%d″,&a[i]);printf(″\n″);for(i=0;i<10;i++)printf(″%d″,*(a+i));}(3)用指针变量指向数组元素。#includestdio.hvoidmain(){inta[10];int*p,i;for(i=0;i<10;i++)scanf(″%d″,&a[i]);printf(″\n″);for(p=a;p<(a+10);p++)printf(″%d″,*p);}例10.6通过指针变量输出a数组的10个元素。#includestdio.hvoidmain(){int*p,i,a[10];p=a;for(i=0;i<10;i++)scanf(″%d″,p++);printf(″\n″);for(i=0;i<10;i++,p++)printf(″%d″,*p);}程序运行情况:12345671090↙221532340030036252021163110259102372104103显然输出的数值并不是a数组中各元素的值#includestdio.hvoidmain(){int*p,i,a[10];p=a;for(i=0;i<10;i++)scanf(″%d″,p++);printg(″\n″);p=a;for(i=0;i<10;i++,p++)printf(″%d″,*p);}程序运行情况:12345671090↙1234567109010.3.4用数组名作函数参数在第7章中介绍过可以用数组名作函数的参数。如:voidmain(){if(intarr[],intn);intarray[10];┇f(array,10);┇}voidf(intarr[],intn){┇}例10.7将数组a中n个整数按相反顺序存放#includestdio.hvoidmain(){voidinv(intx[],intn);inti,a[10]={3,7,9,11,0,6,7,5,4,2};printf(″Theoriginalarray:\n″);for(i=0;i<10;i++)printf(″%d,″,a[i]);printf(″\n″);inv(a,10);printf(″Thearrayhasbeeninverted:\n″);for(i=0;i<10;i++)printf(″%d,″,a[i]);printf(″\n″);}voidinv(intx[],intn)/*形参x是数组名*/{inttemp,i,j,m=(n-1)/2;for(i=0;i<=m;i++){j=n-1-i;temp=x[i];x[i]=x[j];x[j]=temp;}return;}运行情况如下:Theoriginalarray:3,7,9,11,0,6,7,5,4,2Thearrayhasbeeninverted:2,4,5,7,6,0,11,9,7,3#includestdio.hvoidmain(){voidinv(int*x,intn);inti,a[10]={3,7,9,11,0,6,7,5,4,2};printf(″Theoriginalarray:\n″);for(i=0;i<10;i++)printf(″%d,″,a[i]);printf(″\n″);inv(a,10);printf(″Thearrayhasbeeninverted:\n″);for(i=0;i<10;i++)printf(″%d,″,a[i]);printf(″\n″);}对刚才的程序可以作一些改动。将函数inv中的形参x改成指针变量。voidinv(int*x,intn)/*形参x为指针变量*/{intp,temp,*i,*j,m=(n-1)/2;i=x;j=x+n-1;p=x+m;for(;i<=p;i++,j--){temp=*i;*i=*j;*j=temp;}return;}如果有一个实参数组,想在函数中改变此数组中的元素的值,实参与形参的对应关系有以下4种情况:(1)形参和实参都用数组名,如:voidmain()voidf(in