指针的基本概念
指针即地址
通常意义上声明一个变量,总会存在两个概念,一个是变量的值,另一个是变量的地址。这两个是必须存在!其实更多的情况下,我们只关心变量的值,不并在乎变量的地址是什么。而且不是所有的语言都提供地址运算。
Char *p = &c;
上面声明最的正确解释是,声明了一个指针变量c地址处的指针p,即p的值是变量c的地址。
测试代码:
char c = 'A';
char *p = &c;
if(p != &c){
printf(“Logic is error\n”);
}
回到上面为什么一个变量而言必须存在一个变量的地址呢?
程序在执行的时候,都是在内存里面跑的。计算机为了管理和使用内存的方便,进而对内存进行了编址,相当于给房屋的门牌号码,对于每一个号码其对应该房子的位置都是确定的。每次计算机申请的内存时,都是申请到一个地址对应的编号。申请变量的类型,决定了这块可使用地址的长度。几乎都是起始地址+长度的方式来判定的。这个编号是计算机本身在使用,程序员不太关注。几乎程序员只关系自己是否有可以写的变量,自己的写操作是否正确。如同住户不必每天都关心自己的门牌号一样,只是别人问起的时候或者邮寄的时候才会看看自己门牌号。
通过上面的例子说明了一点,地址是让别人找到自己的位置的一个描述符。
二维指针的使用
二维指针的使用还是比较频繁的,相对于三维以上的指针而言,也是比较好理解的。二维指针即指针的指针。
对于特定的系统指针所占用的字节数都是相同的。对于一个32位的操作系统,无论是一维指针还是二维指针占用的字节数都是4个字节。
Char **p = NULL;
p = (char**)malloc(sizeof(char*)*LENGTH);
申请了存放LENGTH个char*的地址空间,每个char*可以根据自己的需要来申请大小。
此处通过指针运算可以比较方便地操作。
为什么要使用指针
使用指针一是可能带回变量的值,二是指针运算比较方便,三是指针确实是增大的变量的寻址空间。
一使用指针带回变量的值
看一个交换的例子。如果是在一个函数内部对两个变量的值进行交换,那么只要下面的代码就可以了:
int t = a;
a = b;
b = t;
但是如果是通过函数调用的形式来实现这个交换,那么就是要使用下面的代码。
int swap(int *a , int *b){
int t = *a;
*a = *b;
*b = t;
}
为什么会这样?
函数有两种传送参数的方式,一种是传值,另一种是传址(在这里实际上都是通过传值的)。函数在调用执行的过程中,使用栈来传送参数,从而保证每个函数有独立的执行空间。正是由于每次都是通过push操作将参数压入到栈里中,子过程的操作实际上是在操作函数栈里面的变量内容。栈与本地变量所处的位置不一样,所以会导致栈里面的内容修改而本地变量的内容没有被修改。从而失去了交换的真正目的。
那么为什么以使用上述的函数调用形式呢?其实本质上述的函数仍然是采用传值的方式传送参数的,只不过这里传入的值是变量的地址,同时函数体内部通过地址指向操作,即实现了对本地变量内容的修改。
实质上C语言里面是没有引用的概念,引用是在以后的高级语言新引进的概念。这个东西,很像指针,但又不是指针。至少不能如同指针一样运算,那么指针可以做哪些运算?又是怎么运算的?
先看看下面的测试代码
char a = 'A';
char *p = &a;
printf("address of a:%p\n",&a);
printf("address of a:%p\n",p);
p++;
printf("address of p:%p\n",p);
address of a:0xbfa41c2b
address of a:0xbfa41c2b
address of p:0xbfa41c2c
int a = 'A';
int *p = &a;
printf("address of a:%p\n",&a);
printf("address of a:%p\n",p);
p++;
printf("address of p:%p\n",p);
address of a:0xbfd75a38
address of a:0xbfd75a38
address of p:0xbfd75a3c
两希程序执行都是 p++,但是两次增量是不一样的。第一段地址的增量是sizeof(char),第二段地址的增量是sizeof(int).这个正好就是这个指针的类型所占的字节数,指针的加减运算的变量是指针类型。那么遇到空指针时会是什么个情况,下面继续测试:
int a = 'A';
int *p = &a;
void *nil_point = p;
printf("null nil_point:%p\n",nil_point);
nil_point ++;
printf("null nil_point:%p\n",nil_point);
nil_point = p;
(int*)nil_point++;
printf("convert to int* nil_point:%p\n",nil_point);
运行结果是:
null nil_point:0xbf960784
null nil_point:0xbf960785
convert to int* nil_point:0xbf960789
如果没有对指针进行强制转换,那么是以字节的形式变化。