关于数组和指针的区别
两者好像可以互换,但又好像在某些地方又不行,求解答 数组是指针的一种表现形式,更加友好罢了 我说下我个人的理解吧,数组就像是一串糖葫芦,一串糖葫芦上面的山楂是一个紧紧挨着另一个,就像数组里面每个元素都是紧紧挨着他旁边的另一个相同类型的元素。而且一般来说一串糖葫芦上面都是同一个口味,这就是
说一个数组里面存放的数据类型都是一样的。指针的话就只是一个签子而已,你想穿什么吃就穿什么在上面,这
也就是说指针可以指向各种不同的内容,但是指针是要和指向的内容类型一致。吃烧烤总不能用木签子,你
说对吧 数组名是个地址常量! 数组按照大小占相应内存,但是实际上,你去获取数组的地址,他返回的是首位的地址,指针如果指向数组第一个地址,相当于指向了整个数组 啊涂涂 发表于 2019-1-11 10:57
我说下我个人的理解吧,数组就像是一串糖葫芦,一串糖葫芦上面的山楂是一个紧紧挨着另一个,就像数组里面
...
可以声明 void 的指针吗??那我不就可以想指向哪个类型的都可以了?? 本帖最后由 行客 于 2019-1-12 13:20 编辑
首先必须纠正一个概念,有些教科书中所说的概念“数组名就是一个指向数组首元素的指针常量”,这是一种错误的说法。
你要记住:数组和指针是两个完全不同的“类型”。这里所说的“类型”,就如同我们常见的基本类型int、char,数组和指针也是两种类型。你必须先看明白我所说的这一段话。
如果上面你看明白了,我们继续来说:
数组既可以表示一种“数据类型”,也可以表示这种类型的“一个对象”(非面向对象之对象,下同)。如果你明白类和对象的关系,这里就能看明白了;如果你不明白类和对象,那我这样给你解释,假设你定义一个int类型的变量n,即int n; ,这里的int就是我们上面说的“类型”,n就是上面说的“对象”。
那么,数组表示为对象时也可以称之为这个数组类型的变量,和其他如int类型的变量n一样,这个数组变量有地址也有值。
数组的地址就是数组所占据内存空间的第一块存储单元的编号,而数组的值是由数组所有元素的值构成。
数组名既不是指针,也不是指针变量,而是数组变量的名字,与数组名相对应的是指针变量的变量名,对应的是 我们上面说的n,都是一个符号。
好,我们来看代码说话:
int a;
int* p = a;
cout << sizeof(a) <<endl; // 40
cout << sizeof(p) <<endl; // 4
作为数组,a拥有可以存放10个int型数据的空间,可以将一个int型的值存储到a中任意一个元素中。但作为一个指针的p,只能存储一个地址。
sizeof 操作符可以获取到一种数据类型所占据的内存大小,指针类型在x32位机器上的大小是4,而数组类型的大小是所有元素大小之和,上例中即为10个int型的大小,是40。
那么,误解从何而来?
我们可以将数组名赋值给一个指针,而赋值后的指针是指向数组首元素的,这让数组名看起来确像一个指针。
直接输出数组名会得到数组首元素的地址,这让人们误觉得“数组名的值就是数组首元素地址“,符合指针的定义。
数组名也可以像指针一样运算,对数组的索引和指针的运算看起来也是相同的。
如例:
#include <stdio.h>
int main(){
int a[] = {1,2,3};
int * p = a;
printf("a:\%#x, p:%#x, &a:%#x\n", a, p, &a);
printf("*a:\%d, *p:%d, a:%d, p:%d\n", *a, *p, a, p);
printf("*(a+1):\%d, *(p+1):%d, a:%d, p:%d\n", *(a+1), *(p+1), a, p);
return 0;
}
输出:
a:0x5fcaf0, p:0x5fcaf0, &a:0x5fcaf0
*a:1, *p:1, a:1, p:1
*(a+1):2, *(p+1):2, a:2, p:2
这些都是让我们觉得数组和指针很相似。
我们下面来解决这个问题:
首先,我们从 &a 与 &a 说起
数组的地址和数组首元素的地址虽然值相同,但意义不同。
值相同是因为,一个变量无论在在内存中占据多大空间,它的地址总是该空间第一个内存单元的地址。而数组的元素依次连续分布在整块数组空间中,数组空间的第一个内存单元被数组首元素占据,必然也同时是数组首元素所占空间的第一块空间单元,所以数组的地址与数组首元素的地址相同。
意义不同是因为,数组地址代表了整块数组所占据的内存空间,而数组首元素的地址只代表了首元素所占据的空间。这句话你一定要好好理解一下。
&a 表示取数组的地址,其结果是一个指向该数组的指针,它可以赋值给另一个同类型的指针。
&a表示取数组首元素的地址,其结果是指向该数组首元素的指针,可以赋值给另一个同类型的指针。
注意:指向数组的指针和指向数组首元素的指针是两种不同类型的指针。
我们通过一个例子来加强理解:
int main(){
int a[]={1,2,3};
int (* pa);
int * pi;
pa = &a;
pi = &a;
printf("&a=%#x, &a=%#x\n",&a, &a);
printf("pa=%#x, sizeof(a)=%d, pa+1=%#x\n", pa, sizeof(a), pa+1);
printf("pi=%#x, sizeof(a)=%d, pi+1=%#x\n", pi, sizeof(a), pi+1);
return 0;
}
编译后运行,输如下:
&a=0x5fcaf0, &a=0x5fcaf0
pa=0x5fcaf0, sizeof(a)=12, pa+1=0x5fcafc
pi=0x5fcaf0, sizeof(a)=4, pi+1=0x5fcaf4
我们发现,取数组地址(&a)得到的指针pa和取数组首元素(&a)得到的指针pi是两种不同类型的指针,pa是一个指向有三个int型元素的数组的指针,pi是一个指向int型对象的指针。虽然pi和pa的值相同,但所指的内存空间不同,pi所指的空间处于pa所指空间的内部,而且是内部最靠前的部分。pi和pa所指内存块的大小显然是不同的,因此我们看到pa+1并不等于pi+1。
由指针运算规则可知,pa+1的值就是pa所指空间的下一个空间的地址,所以pa+1的值就是pa的地址向后偏移一段后的地址,这个偏移量就是pa所指的数组a的大小,即12个内存单元。同样,pi+1的值是pi向后偏移4个单位(int型的大小)后的地址。
这样验证了,我们开始所说的“数组可以表示一种“数据类型””。这里我们可以理解为(&a)就是数组类型。
1809228982 发表于 2019-1-12 08:26
可以声明 void 的指针吗??那我不就可以想指向哪个类型的都可以了??
可以声明的,小甲鱼后面有讲到我记得 行客 发表于 2019-1-12 08:35
首先必须纠正一个概念,有些教科书中所说的概念“数组名就是一个指向数组首元素的指针常量”,这是一种错误 ...
谢谢,大概懂了。 啊涂涂 发表于 2019-1-12 15:05
可以声明的,小甲鱼后面有讲到我记得
好的,谢谢
页:
[1]