要讲指针,首先要搞清楚内存。内存只不过是一个存放数据的空间,就好像我的看电影时的电影院中的座位一样。每个座位都要编号,我们的内存要存放各种各样的数据,当然我们要知道我们的这些数据存放在什么位置吧!所以内存也要象座位一样进行编号了,这就是我们所说的内存编址。座位可以是按一个座位一个号码的从一号开始编号,内存则是按一个字节一个字节进行编址,如下图所示。每个字节都有个编号,我们称之为内存地址。
那么对于下面变量申明: int i; char a; 这句代码的含义就是向内存申请了一个整型变量宽度的空间(一般是两个字节)并命名为i,同时申请了一个名为a的字符型变量宽度的空间(一个字节)并命名为a。效果如下图所示:
变量申明之后就是对其赋值: i=10; a='dk'; 这句代码的含义就是将10存入名为i的内存空间,将dk存入名为a的内存空间,效果图如下:
通过上面的讲解可以弄清楚变量、内存、地址的概念,下面就来进行指针的探讨。 首先我们要知道怎么去表达一个变量的地址,这就需要知道&i的含义了,我们可以这样读它:返回变量i的地址编号。对于上述定义&i的值就为6(实际编程中不会是这个数,因为地址不会就是6)。 2、指针 指针就是地址;指针变量是存地址的变量 申明一个整型的指针变量如下: int *p; 其中p就是一个指针变量,实质上它和前面的整型变量和字符型变量没有区别,就是一个变量。上句代码的意思就是向内存申请一个整型指针变量宽度的空间(假设两个字节)并命名为p,效果如下:
和前面变量的区别是p所对应的空间存储的是变量的地址编号,赋值如下: p=&i; 这句代码的含义就是将变量i的地址编号存入名为p的内存空间。如下图,变量i的地址编号为6,
指针变量定义好以后就是使用的问题了,我们就需要搞清楚*p的含义了,我们可以这样读它:p内容所指的地址的内容。此处的*p的值就是地址6所存的内容也就是10。 到此为止就可以搞清楚指针的基本含义和操作,那接下来我们就要探讨指针的用处。 3、指针的使用 (1)访问数组元素 用指针来访问数组元素的时候首先要弄清楚数组名的含义:数组名代表数组的首地址,可以采用如下方法来访问数组元素:
int i,a[]={3,4,5,6,7,3,7,4,4,6};
for (i=0;i<=9;i++)
{
printf ( “%d”, *(a+i) );
} 或者: int i,*pa,a[]={3,4,5,6,7,3,7,4,4,6};
pa =a ;//请注意数组名a直接赋值给指针 pa
for (i=0;i<=9;i++)
{
printf ( “%d”, pa[i] );
} 但是数组名a和pa还是不同的,数组名是一个指针常量,其值不能被更改,pa是一个指针变量其值是可以更改的,下面用一个例子来说明这个问题: int i,a[]={3,4,5,6,7,3,7,4,4,6};
pa =a;
for (i=0;i<=9;i++)
{
printf ( “%d”, *a );
a++ ; //注意这里,指针值被修改
} 上面这段代码运行会出错,因为a是一个指针常量其值不能改变,所以用上面这种方式来访问数组元素是错误的。但是可以采用下面的方式访问: int i,*pa,a[]={3,4,5,6,7,3,7,4,4,6};
pa =a;
for (i=0;i<=9;i++)
{
printf ( “%d”, *pa );
pa++ ; //注意这里,指针值被修改
} 从这两段代码就可以弄清楚指针变量和指针常量的区别。 (2)int const *p和int * const p的区别 const修饰的i不再是一个符号变量,而是一个符号常量,其不能被重新赋值。弄清楚const的含义后就可以来探讨两者的区别了,从语义可以看出int const *p中修饰的是*p,int * const p中修饰的是p即前者*p的值不能修改,后者p的值不能修改。 (3)函数参数的指针传递 在这里首先要搞清楚形参和实参的区别:形参是出现在函数定义中的参数(下文程序中的x,y);实参是出现在函数调用中的参数(下文程序中的a,b)。 下面通过对两个个程序的解读来分析函数参数指针的作用: 题一:程序代码如下: void Exchg1(int x, int y)
{
int tmp;
tmp=x;
x=y;
y=tmp;
printf (“x=%d,y=%dn”,x,y)
}
void main()
{
int a=4,b=6;
Exchg1 (a,b) ;
printf(“a=%d,b=%dn”,a,b)
} 现在来逐条分析程序,从主程序依次执行,首先是对a、b两个变量赋值,然后调用子函数Exchg1,将a、b作为变量代入子函数里面进行执行,这个过程隐含了两条语句:x=a;y=b;(调用函数时是隐含着执行了这两条语句的),然后在子函数里面执行,将x的值和y的值进行交换,而a、b的值是没有发生变化的,所以最后运行的结果是a=4,b=6;x=6,y=4。 题二 代码如下:
Exchg2(int *px, int *py)
{
int tmp=*px;
*px=*py;
*py=tmp;
print(“*px=%d,*py=%dn”,*px,*py);
}
main()
{
int a=4;
int b=6;
Exchg2( &a,&b);
Print (“a=%d,b=%dn”, a, b);
} 同样地从主函数中逐条分析,首先是对a,b进行赋值,然后调用子函数Exchg2,这个函数定义的形参是指针变量,因此调用时的实参是a,b的地址。同样地,隐含着两条代码:px=&a;py=&b;然后在子程序中交换的是指针px所对应的内容和指针py所对应的内容,即a和b的值,最后的运行结果为:a=6,b=4;*px=6,*py=4. (4)**p的含义 **p这是一个指向指针的指针 下面通过一个例子来说明其作用: 设计一个函数:void find1(char array[], char search, char * pi)
要求:这个函数参数中的数组array是以0值为结束的字符串,要求在字符串array中查找字符是参数search里的字符。如果找到,函数通过第三个参数(pa)返回值为array字符串中第一个找到的字符的地址。如果没找到,则为pa为0. void find1(char array[], char search, char * pa)
{
int i;
for (i=0;*(array+i)!=0;i++)
{
if (*(array+i)==search)
{
pa=array+i
break;
}
else if (*(array+i)==0)
{
pa=0;
break;
}
}
} 测试主程序: void main()
{
char str[]={“afsdfsdfdf ”}; //待 查找的字符串
char a=’d’; //设置要查找的字符
char * p=0; //如果 查找到后指针p将指向字符串中查找到的第一个字符的地址。
find1(str,a,p); //调用函数以实 现所要操作。
if (0==p )
{
printf (“没找到!n”);//1.如果没找到则 输出此句
}
else
{
printf(“找到了,p=%d”,p); //如果找到则 输出此句
} 测试的结果是没找到,说明子函数有问题,下面进行逐条分析: 函数调用会隐含三条代码: array[]=str;search=a;pa=p; 从子函数的执行过程可以看出,找到字符后改变的是形参pa的值,实参p的值没有发生改变。 为了得到上述功能,将程序修改如下: void find2(char array[], char search, char ** ppa)
{
int i;
for (i=0;*(array+i)!=0;i++)
{
if (*(array+i)==search)
{
*ppa=array+i
break;
}
else if (*(array+i)==0)
{
*ppa=0;
break;
}
}
} 主程序调用部分修改如下: find2(str,a, &p); 同样的隐含地执行了三条代码: array[]=str;search=a;*ppa=&p; 从中可以看出指针ppa指向的是变量p的地址,在子程序执行过程中改变的ppa所指向的内容即p的地址,那p的值也随之发生改变了。 上面这个例子弄明白后就可以弄清楚指针的含义了。



