1809228982 发表于 2019-1-11 09:54:20

关于数组和指针的区别

两者好像可以互换,但又好像在某些地方又不行,求解答

BngThea 发表于 2019-1-11 10:11:12

数组是指针的一种表现形式,更加友好罢了

啊涂涂 发表于 2019-1-11 10:57:36

我说下我个人的理解吧,数组就像是一串糖葫芦,一串糖葫芦上面的山楂是一个紧紧挨着另一个,就像数组里面

每个元素都是紧紧挨着他旁边的另一个相同类型的元素。而且一般来说一串糖葫芦上面都是同一个口味,这就是

说一个数组里面存放的数据类型都是一样的。指针的话就只是一个签子而已,你想穿什么吃就穿什么在上面,这

也就是说指针可以指向各种不同的内容,但是指针是要和指向的内容类型一致。吃烧烤总不能用木签子,你

说对吧

mqcake 发表于 2019-1-11 14:59:44

数组名是个地址常量!

qpwoow 发表于 2019-1-11 15:19:25

数组按照大小占相应内存,但是实际上,你去获取数组的地址,他返回的是首位的地址,指针如果指向数组第一个地址,相当于指向了整个数组

1809228982 发表于 2019-1-12 08:26:53

啊涂涂 发表于 2019-1-11 10:57
我说下我个人的理解吧,数组就像是一串糖葫芦,一串糖葫芦上面的山楂是一个紧紧挨着另一个,就像数组里面
...

可以声明 void 的指针吗??那我不就可以想指向哪个类型的都可以了??

行客 发表于 2019-1-12 08:35:21

本帖最后由 行客 于 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)就是数组类型。

啊涂涂 发表于 2019-1-12 15:05:29

1809228982 发表于 2019-1-12 08:26
可以声明 void 的指针吗??那我不就可以想指向哪个类型的都可以了??

可以声明的,小甲鱼后面有讲到我记得

1809228982 发表于 2019-1-14 09:45:36

行客 发表于 2019-1-12 08:35
首先必须纠正一个概念,有些教科书中所说的概念“数组名就是一个指向数组首元素的指针常量”,这是一种错误 ...

谢谢,大概懂了。

1809228982 发表于 2019-1-14 09:46:22

啊涂涂 发表于 2019-1-12 15:05
可以声明的,小甲鱼后面有讲到我记得

好的,谢谢
页: [1]
查看完整版本: 关于数组和指针的区别