1.指针p,间接访问。p=&a,将a的地址存入p单元中。注意:&p!=&a,p有自己的地址,a与p为两个变量。

2.*:指针运算符(或称间接访问运算符),*P表示指针p中存储的地址中的元素。注意:与定义时的*p区分开。int *p相当于int (*p),(*p)表示p为指针变量,指向的类型为int。可以在定义时直接赋值。int *p=&a,等价于int *p;p=&a;(赋值时并不能*p=a,不合法)

3.难点:指针与数组

int a[10];
int *p;
p=a;//或p=&a[0];

注意:数组名a与&a[0]无条件等价。数组名代表首元素的地址。此时指针变量p与数组名a并不等价。a相当于指针常量,不能进行自增和自减运算。

形象化比喻:定义a[10]一块内存空间,10个元素按顺序排列。首元素地址为0x000000,则a=0x000000,系统在遇到输出例如a[1]时,等价于*(0x000000+1)。由此可知,数组名并不能进行自增和自减运算。而p为指针变量,指向a,p的内容也为0x000000,但是p自己也有地址,且可以进行自增和自减运算。所以&p!=&a。但&a也有自己的含义,为指向整个数组的指针。

int a=10,*p=&a;开辟一块内存空间,并且整个空间叫做a或p,而数组名a是把空间的地址叫做a。两个方面。

再讨论讨论数组。其实数组可以类比为向量,n维数组相当于n维向量。从n维到1维都有不同的指针。int a[3][4];数组名a相当于最大范围的向量也就是行向量,a+1为指向第一行的行向量。a[0]=*a相当于列向量,*(a+1)=a[1]为指向第一列的向量,**a才为取值。作为推广,n维向量a[][][]...[],a+1指向第n维,*(a+1)指向第n-1维,**...*a为取值。&a表示为整个数组的指针,如果定义一个一维数组的地址为0x000000-0x000008,则&(a+1)指向0x000009。相当于整个数组的移动。

注意区分指向数组的指针(*p)[n]和指针数组*p[n]。前者为一个指针变量p包含n个元素,可以通过(*p)[4]读出包含的值。int a[3][4],int (*p)[4];p=a;而int a[4],int (*p)[4],则p=&a;注意指针变量类型的匹配。行指针配行指针,列指针配列指针。

4.字符数组与字符串指针:字符串指针的值为第一个字符的地址,类似于数组名。char *p="asdfg";printf("%d",*p)输出的是第一个字符的首地址,而printf("%s",*p)输出字符串。字符串指针优点在于不必浪费内存空间。字符串指针包含指针的特点,例如可进行左值运算。而字符数组包含数组的特点,例如字符可修改等等。

5.函数指针:int (*p)(int ,int );指向函数的入口地址。int max(int ,int )//函数声明.p=max;此时p指向max的入口,可以通过c=(*p)(a,b)调用。此时不能用*(p+1),无意义。

6.返回值为指针的函数;定义为 int *fun(int ,int );注意与5区分开。

7.指针数组int *p[],包含n个指针变量。由此可以得到指针的指针,int **p,相当于(int *)(*p),定义指针变量p,指向数据类型为int *。使用方法同数组。

 

重点:指针变量作为函数参数进行调用

先打个比方:把函数看作一个个箱子,每个箱子都有n个入口(形参)与0或1个出口(返回值)。普通的变量进行的是值传递,相当于从一个箱子中复制一个球(变量),把球从入口扔进去(调用),在另一个箱子折腾一番后,扔回来一个正方体,此时原来的箱子里球的值和数目不变,多了一个正方体。(函数调用时不改变原来变量的值)数组为传址,相当于不复制球,直接把球扔过去。(改变球的值)指针变量,相当于仍然复制一个球,但是复制的球和原来的球上系着一条线,在把复制好的球扔过去后,复制后的球可以对原来的球产生影响。例如:

int *p1=&a,*p2=&b;
void exchange(int *a,int *b)
{
int temp;
temp=*a;
*a=*b;
*b=temp;}

不改变p1与p2的值(仍指向a和b的地址),但a与b的值互换。其实相当于a与b进行“传址”,地址是不会改变的,改变的只是地址中的值。

数组名作为形参:int fun(int arr[],int n),在fun函数调用时,系统在fun函数中建立一个指针变量arr,用来存放从主调函数中传递过来的实参数组首元素的地址。!!!形参数组名为指针变量,可以进行重新赋值。

void fun (int arr[],int n)
{
printf("%d %d",*arr,*++arr)}

指针数组作main函数的形参:int main(int argc ,char *argv[]),参数个数与参数向量。为命令行参数。通常main函数和其他函数组成一个文件模块。main函数为系统调用,所以实参只能由操作系统给出。通过命令行输入参数。