C++ 数组名与元素指针的区别

393 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情

数组名与指针的共同点

在C++中,数组名可以当作数组第一个元素的指针来用。例如:

short x[] = {1,2,3};
short* y = x;
cout << x[0] << " " << y[1] << " " << *(x+1) << " " << *(y+2) << endl;

输出: 1 2 2 3

如上例,无论是数组名x还是指针y,都可以使用下标的方式或解引用的方式来访问数组中的某个元素。那么,数组名和元素指针真的完全一样,没有区别吗?

其实,这二者还是有区别的。

与数组名与指针的区别

  1. 数组名是常量,不可修改

    首先数组名只能指向这个数组,不能指向其他地址。

    x = x+1; // error
    y = y+1;
    

    x = x+1会报编译错误,而指针y指向的地址则可以修改。

  2. 数组名和元素指针的sizeof大小不同

    cout << sizeof(x) << " " << sizeof(y) << endl;
    

    输出: 6 8

    这里面,6代表x这个数组的大小,因为是short类型2字节,3个元素,所以一共6个字节。而y的大小为8则是64位指针的大小。

  3. 取地址操作表现不同

    数组名x进行取地址&x,得到的是整个数组的地址;而对指针y进行取地址得到的则是指针的地址。它们有什么区别呢?看看代码:

    cout << "x:" << x << " &x:" << &x << " x+1:" << x+1 << " &x+1:" << &x+1
        << " &y:" << &y << " &y+1:" << &y+1 << " " << endl;
        
    输出:x:0x7ffee8c3fada &x:0x7ffee8c3fada x+1:0x7ffee8c3fadc 
        &x+1:0x7ffee8c3fae0 &y:0x7ffee8c3fad0 &y+1:0x7ffee8c3fad8
    

    可以看到,数组的地址(&x:0x7ffee8c3fada)与第一个元素地址(x:0x7ffee8c3fada)在数字上相同,但数组的地址表示的是整个数组的大小,因此&x+1操作实际上偏移了6个字节(即sizeof x),而x+1只偏移了2个字节(short的长度)。

    而指针y的地址(&y:0x7ffee8c3fad0)则与第一个元素地址没有联系,&y+1偏移了8个字节(即sizeof y)。

  4. 初始化方式不同

    用数组名的方式实际上直接分配了数组的内存空间,所以可以直接用初始化列表进行初始化,数组声明后也可以直接对某个元素赋值。

    而指针在声明时只分配了指针本身的内存空间,因此需要用new或者其他已经分配好的空间进行赋值,才能使其指向有效的内存地址。 我们不能这样初始化:

    short* z = {1,2,3};
    

    但对于字符串,却可以用下面两种方式初始化:

    char st1[] = "string";
    char* st2 = "string";
    

    对于第一种,为字符串分配了内存空间,没有问题。但第二种,有些编译器可能不会为st2单独分配内存空间,而是对于相同的字符串字面量,共享同一个内存空间。因此,我们最好不要修改st2,有些IDE也会给出提示 image.png 改进方法很简单,只需声明为const类型即可:

    const char* st2 = "string";