数组名和指针详解
来源:互联网 发布:区间交易软件 编辑:程序博客网 时间:2024/04/28 14:44
首先要说的是,数组名不是指针。
我们来看数组int test[3],这里test[3]是整型,test这个数组名的值是一个指针常量,也就是数组第一个元素的地址。总结一下:
数组名的类型(如int test[3])就是“指向某类型(int型)的常量指针”。
只有当数组名在表达式中使用时,编译器才会为它产生一个指针常量。
但是数组名和指针是不相同的。
我们先来看一个程序
int test[3] = {1, 2, 3};
cout << sizeof(test) << endl;
输出的答案是:12。这个数是3 * sizeof(int) = 3 * 4 = 12得到的。如果test是一个数组的话,输出应该是4才对。这表明,数组名不是指针。
根据《C和指针》这本书的论述的第2条可以解释上面的问题。
指针与数组2(c和指针.P141.)
·1、数组的名的值是一个指针常量,不能试图将一个地址赋值给数组名;
·2、当数组名作为sizeof操作符的操作数时,sizeof(arrayname)返回的是整个数组的长度,而不是指向数组的指针的长度;
·3、当数组名作为单目操作符&的操作数,取一个数组名的地址所产生的是一个指向数组的指针,而不是一个指向某个指针常量值的指针。
其实看这第2条,只是表述了现象,没有上升到抽象理论。
我这里就有这种理论的表述:
(1)数组名的内涵在于其指代实体是一种数据结构,这种数据结构就是数组;
(2)数组名的外延在于其可以转换为指向其指代实体的指针,而且是一个指针常量;
(3)指向数组的指针则是另外一种变量类型(在WIN32平台下,长度为4),仅仅意味着数组的存放地址!
上面第一条说的很透彻,sizeof通过数组名看到了数组的数据结构,因此输出了12。
结合第二条的知识,
int a[5]= {1,2,3,4,5};int *ptr1=(int *)(&a+1);nt *ptr2=(int *)(a+1);printf("%x, %x\n", ptr1[-1], *ptr2);// 输出5,2int *ptr1=(int *)(&a+1);int *ptr2=(int *)(a+1);
ptr1定义时,用的是&a,编译器产生了一个指向数组的指针,通过&数组名反映了数组的数据结构,因此&a + 1就一下子到了数组最后一个元素的后一个元素,以为这里的加1是1 * sizeof(a)。因此用ptr1[-1]才能访问到数组的最后一个元素,这里的加1是1 * sizeof(int)。
与之相比,ptr2定义时,使用的是a + 1,编译器产生了一个常量指针,指向第一个元素,加1后指针指向了第二个元素。
于是,得到了输出5,2。
下面我们接着看《C和指针》第三条,当数组名作为&的操作数时,数组名也不是指针常量了。也就是说,遇到sizeof和&数组名都不是指针常量,而是指向数组的指针。
下面我们要深入一点,来看看数组名作为&的操作数时,数组名为指向数组的指针的情形。
要看这个例子,我们先要明白:“指针数组”和“数组指针”
这两个概念其实不难,
“指针数组”是一个数组!数组的元素是指针。
“数组指针”是一个指针!指向的是数组。
好了知道这个了我们来看例子
int (*ptr)[3]; // 数组指针
int *ptr[3]; // 指针数组
我们要注意:[]下标运算符的优先级高于*解引用操作符,(解引用的英文是dereference,就是取值的意思,深入讨论这个奇怪名字的话可以参见,http://topic.csdn.net/u/20080704/08/93ccd5b3-7dc8-47b9-8574-c31b80954fc9.html)
我们知道优先级了,第一个定义int (*ptr)[3]; 就是先进行解引用,意思就是定义一个指针,指针的类型是int [3]即ptr是一个指针,它指向有3个元素的数组。要习惯int [3]这种表示类型的方式,后面分析时要用到!
第一个定义int *ptr[3]; // 指针数组 意思是先进行ptr[3]操作,声明了一个数组,数组存的变量的类型是int *即数组存放的变量是int型指针。
下面就要开始看数组名作为&的操作数时,数组名为指向数组的指针的情形了。
int (*iPointer)[3]; // 数组指针
int test[3] = {1, 2, 3};
iPointer = &test;
cout << iPointer[0][1] << endl;
输出内容为:2。
我们要讨论的是iPointer = &test;这种定义方式,不是说数组名的类型就是“指向某类型(int型)的常量指针”吗?数组名是一个指针常量,也就是数组第一个元素的地址的吗?
为什么iPointer = test这样不行呢?
我们发现
cout << test << endl;
cout << &test << endl;
cout << &test[0] << endl;
的数值都是一样的,就是数组第一个元素的地址,即数组的首地址。
那么,为什么iPointer = test这样不行呢?从数值上来说,iPointer就是要存储数组的首地址呀。
我们来看,如果是不加&那么报错内容是 cannot convert 'int [3]' to 'int (*)[3]' in assignment。
意思是说,iPointer这个指针的类型是int [3],它指向一个含有3个元素的数组!。而test的类型是一个指向int的常量数组,它只指向一个元素。也就是说,数值对了,iPointer指向了一个数组,test指向了一个元素,类型不匹配。
因此,我们可以得知
iPointer = &test[0];
也是不对的。报错相同。
我们可以这样修改:
强制转换一下就对了:
iPointer = (int (*)[3])test;
这个错误其实没有说穿本质,iPointer需要的右值类型是“指向一个数组”的指针,test这个数组名的值是一个指向数组第一个元素的指针,类型不匹配,而当数组名遇到sizeof和&时,产生的是一个指向数组的指针,不是一个指向指针常量值的指针(指针的类型不是指向第一个元素,而是指向全数组即int (*)[3])
因此,我们可以改成
iPointer = &test;
我们回过头来看:
int *iter;int test[3] = {1, 2, 3};iter = test;cout << iter[2] << endl;
这是正确的,因为test的类型是指向int的常量指针,与iter相符。
指针数组做参数举例
#include <stdio.h>#include <iostream>#include <string.h>#include <stdlib.h>using namespace std;void printMany( char *strings[] )//指针数组,数组的元素是指针,[]优先级高于*{ int i = 0; while( strings[i] != NULL ) { printf("%s, ", strings[i++]); } printf("\n");}void printMany2( char *strings ){ for (int i = 0; i < 7; i++) { printf("%c", strings[i]); }}void strsort(char *s[],int n)// 排序{ int i,j; char *t; for(i=0;i<n-1;i++) for(j=i+1;j<n;j++) { if(strcmp(s[i],s[j])>0) { t=s[i]; s[i]=s[j]; s[j]=t; } }}int main(){ char strings2[] = "abcdef"; char *strings[] = {"C","Basic","Foxpro","Visual Studio", NULL}; // 指针数组,里面存的内容是指针,每个指针指向一个字符串 //strings = strdup(strings2); printMany(strings); printMany2(strings2); cout << sizeof(strings)/4 << endl; // 求指针数组中含有的指针的个数 strsort(strings, sizeof(strings)/4 - 1); printMany(strings); //printf("%X, %X", strings2, &strings2); //free(strings); return 0;}
- 数组名和指针详解
- 数组名和指针详解
- 数组名和指针详解
- 详解数组名和指针的区别
- 数组名 和 指针
- 数组名和指针
- 数组名和指针
- 数组名和指针
- 数组名 和 指针
- 数组名和指针
- 数组名和指针
- 数组名和指针
- 指针和数组名
- 指针和数组名
- 数组名和指针
- 数组名和数组指针
- (转)数组名和指针
- sizeof() && 数组名和指针
- poj -2395-Out of Hay
- NTKO OFFICE文档控件 学习笔记(一)
- 使用JDBC连接sqlserver2008
- 专业前沿
- 【小蒙淘金】亏损是因为不懂资金管理
- 数组名和指针详解
- rcp(插件开发)如何保存并关闭显示在编辑区的单个编辑器
- SIFT算法研究
- jQuery使一组CheckBox全选或取消全选
- Install Oracle ASMLib on Oracle Linux 6
- 阅读json-c库源码的随笔
- strlen和sizeof详解
- Mahout创建一个Web推荐器
- Visual SVN最新2.0以上版本破解 -测试过 可用