如果这篇博客帮助到你,可以请我喝一杯咖啡~
CC BY 4.0 (除特别声明或转载文章外)
问题是这样的,今天在我想输出一个字符数组的地址时:
char* buffer = new char[256];
cout << "&buffer = " << (void*)buffer << " " <<&buffer << endl;
我本想用 &buffer
来打印 buffer
的地址(因为如果写 buffer 的话会输出字符串的内容)。由于书上是将 buffer 先强转为 void*
再进行打印,我也试了试这个办法,竟然发现两次打印的结果不同!
我当时就有点迷惑,因为我记得 C 语言中对数组取地址和数组的地址是相同的。下面,就让我们来一探究竟。
(ps:其实这个问题很简单,如果你懂的话,可以不浪费你的时间了)
在学习 C 语言的时候,我们都知道数组也是可以取地址的:
extern "C" void test3()
{
int array[10] = { 0 };
printf("&array = %p", &array);
}
(extern "C"
会指示编译器编译这部分代码以 C 语言的形式进行编译,如果你使用 .c
文件写的,可以忽略这部分)
而且我们会发现,以 %p
的格式来打印array
和 &array
的值是相同的:
printf("array = %p, &array = %p", array, &array);
那么这两个地址有什么区别呢?
用 typeid().name()
函数我们可以查看变量的类型:
printf("array: %s\n", typeid(array).name());
printf("&array: %s\n", typeid(&array).name());
// 输出:
array: int [10]
&array: int (*)[10]
所以这两个地址的区别就在于类型。array
是数组首元素的地址,而 &array
是整个数组的地址。
指针的一个重要的性质就是 指针的类型决定了指针 ++/--
操作时的步长 。比如,char*
类型的指针的步长就是 1 个字节,而 int*
类型的指针的步长就是 4 个字节(32 位机器)。
在本例中:
printf("array = %p, &array = %p\n", array, &array);
printf("array + 1 = %p, &array + 1 = %p\n", array + 1, &array + 1);
// 打印:
array = 012FFD08, &array = 012FFD08
array + 1 = 012FFD0C, &array + 1 = 012FFD30
array
的步长是 4 个字节(int
的大小);而 &array
的步长是 40 个字节 int[10]
的大小。
了解了这个之后,回过头来看我们的问题,我们先在 C 语言中模拟一下前面出现的问题:
char* buffer = (char*)malloc(sizeof(char) * 256);
printf("buffer = %p &buffer = %p\n", buffer, &buffer);
// 打印
buffer = 0120E230 &buffer = 00EFFD1C
区别就在于:**前面在声明数组时,我们使用的格式是:int array[10]
而 后面我们用的是 char* buffer = malloc
**
这有什么不同呢?不同之处在于数组真正存在的位置不同:array 存在于栈,而 buffer 存在于堆
观察上面 buffer
和 &buffer
发现,这两个指针的大小差距很大。因此这两个指针一定不在同一个内存区域。
如果你还是不能确定,你可以声明一个在栈上的变量,然后输出一下它的地址:
int a = 10;
printf("&a = %p\n", &a);
// 输出:
buffer = 0132E230 &buffer = 00D6FB84
&a = 00D6FB78
还剩最后一步,如果把 buffer 声明在栈上,是否 buffer 和 &buffer 打印出来的地址就一样呢?
char buffer2[256] = "Hello World";
printf("buffer2 = %p &buffer2 = %p\n", buffer2, &buffer2);
// 打印:
buffer2 = 00D6FA70 &buffer2 = 00D6FA70
到此为止,这个问题就算是解决了。前面我们讨论了,array
与 &array
的区别;进而探讨了 buffer
和 &buffer
的区别。主要还是本人对指针理解的不够充分,惭愧!
本人能力有限,如果有什么问题,还望大佬指出。