(1)int*ptr; (2)char*ptr; (3)int**ptr; (4)int(*ptr)[3]; (5)int*(*ptr)[4]; |
(1)int*ptr; //指针的类型是int* (2)char*ptr; //指针的类型是char* (3)int**ptr; //指针的类型是int** (4)int(*ptr)[3]; //指针的类型是int(*)[3] (5)int*(*ptr)[4]; //指针的类型是int*(*)[4] |
怎么样?找出指针的类型的方法是不是很简单?
2、指针所指向的类型
当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。
从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。例如:
(1)int*ptr; //指针所指向的类型是int (2)char*ptr; //指针所指向的的类型是char (3)int**ptr; //指针所指向的的类型是int* (4)int(*ptr)[3]; //指针所指向的的类型是int()[3] (5)int*(*ptr)[4]; //指针所指向的的类型是int*()[4] |
在指针的算术运算中,指针所指向的类型有很大的作用。指针的类型(即指针本身的类型)和指针所指向的类型是两个概念。当你对C越来越熟悉时,你会发现,把与指针搅和在一起的"类型"这个概念分成"指针的类型"和"指针所指向的类型"两个概念,是精通指针的关键点之一。
3、指针的值,或者叫指针所指向的内存区或地址
指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。在32位程序里,所有类型的指针的值都是一个32位整数,因为32位程序里内存地址全都是32位长。
指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为sizeof(指针所指向的类型)的一片内存区。以后,我们说一个指针的值是XX,就相当于说该指针指向了以XX为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。
指针所指向的内存区和指针所指向的类型是两个完全不同的概念。在例一中,指针所指向的类型已经有了,但由于指针还未初始化,所以它所指向的内存区是不存在的,或者说是无意义的。
以后,每遇到一个指针,都应该问问:这个指针的类型是什么?指针指向的类型是什么?该指针指向了哪里?
4、指针本身所占据的内存区
指针本身占了多大的内存?你只要用函数sizeof(指针的类型)测一下就知道了。在32位平台里,指针本身占据了4个字节的长度。指针本身占据的内存这个概念在判断一个指针表达式是否是左值时很有用。
第二章 指针的算术运算
指针可以加上或减去一个整数。指针的这种运算的意义和通常的数值的加减运算的意义是不一样的。例如:
例二:
1.chara[20]; 2.int*ptr=a; ... ... 3.ptr++; |
intarray[20]; int*ptr=array; ... //此处略去为整型数组赋值的代码。 ... for(i=0;i<20;i++) { (*ptr)++; ptr++; } |
1.chara[20]; 2.int*ptr=a; ... ... 3.ptr+=5; |
在这个例子中,ptr被加上了5,编译器是这样处理的:将指针ptr的值加上5乘sizeof(int),在32位程序中就是加上了5乘4=20.由于地址的单位是字节,故现在的ptr所指向的地址比起加5后的ptr所指向的地址来说,向高地址方向移动了20个字节。
在这个例子中,没加5前的ptr指向数组a的第0号单元开始的四个字节,加5后,ptr已经指向了数组a的合法范围之外了。虽然这种情况在应用上会出问题,但在语法上却是可以的。这也体现出了指针的灵活性。
如果上例中,ptr是被减去5,那么处理过程大同小异,只不过ptr的值是被减去5乘sizeof(int),新的ptr指向的地址将比原来的ptr所指向的地址向低地址方向移动了20个字节。
inta=12; intb; int*p; int**ptr; p=&a; //&a的结果是一个指针, 类型是int*,指向的类型是int,指向的地址是a的地址。 *p=24; //*p的结果,在这里它的类型是int, 它所占用的地址是p所指向的地址,显然,*p就是变量a。 ptr=&p; //&p的结果是个指针,该指针的类型是p的类型加个*, 在这里是int**。该指针所指向的类型是p的类型, 这里是int*。该指针所指向的地址就是指针p自己的地址。 *ptr=&b; //*ptr是个指针,&b的结果也是个指针, 且这两个指针的类型和所指向的类型是一样的, 所以用&b来给*ptr赋值就是毫无问题的了。 **ptr=34; //*ptr的结果是ptr所指向的东西,在这里是一个指针, 对这个指针再做一次*运算,结果就是一个int类型的变量。 |
#p#副标题#e#
第四章 指针表达式
一个表达式的最后结果如果是一个指针,那么这个表达式就叫指针表达式。下面是一些指针表达式的例子:
例六:
inta,b; intarray[10]; int*pa; pa=&a; //&a是一个指针表达式。 int**ptr=&pa; //&pa也是一个指针表达式。 *ptr=&b; //*ptr和&b都是指针表达式。 pa=array; pa++; //这也是指针表达式。 |
char*arr[20]; char**parr=arr; //如果把arr看作指针的话,arr也是指针表达式 char*str; str=*parr; //*parr是指针表达式 str=*(parr+1); //*(parr+1)是指针表达式 str=*(parr+2); //*(parr+2)是指针表达式 |
intarray[10]={0,1,2,3,4,5,6,7,8,9},value; ... ... value=array[0]; //也可写成:value=*array; value=array[3]; //也可写成:value=*(array+3); value=array[4]; //也可写成:value=*(array+4); |
#p#副标题#e#
上例中,一般而言数组名array代表数组本身,类型是int[10],但如果把array看做指针的话,它指向数组的第0个单元,类型是int*,所指向的类型是数组单元的类型即int.因此*array等于0就一点也不奇怪了。同理,array+3是一个指向数组第3个单元的指针,所以*(array+3)等于3.其它依此类推。
例九:
char*str[3]= { "Hello,thisisasample!", "Hi,goodmorning.", "Helloworld" }; chars[80]; strcpy(s,str[0]); //也可写成strcpy(s,*str); strcpy(s,str[1]); //也可写成strcpy(s,*(str+1)); strcpy(s,str[2]); //也可写成strcpy(s,*(str+2)); |
intarray[10]; int(*ptr)[10]; ptr=&array; |
int(*ptr)[10]; 则在32位程序中,有: sizeof(int(*)[10])==4 sizeof(int[10])==40 sizeof(ptr)==4 |