让我们说
char arr[] = "test";
我读到数组就像一个指向字符串的指针。因此,当我这样做时:
cout << arr << endl;
我得到test
。当我做的时候
char *ptr = arr
变量ptr
现在应该存储arr
指针的地址。但是,如果我这样做
cout << ptr << endl
我得到test
。如果它基本上是一个指向指针的指针,为什么不进行“测试”:
cout << *ptr << endl;
有人可以根据内存的分配情况向我解释一下吗?
答案 0 :(得分:0)
&#34;&lt;&lt;&# operator将 char * 视为C字符串。因此它意味着arr [0-end]和ptr [0-end]; 当你这样做时:
char * ptr = arr
您只需为同一目标创建一个新的 char * 。因此,它也被视为C字符串并且隐含地&#34; cout&lt;&lt;&#打印它指向的字符。
这仅适用于 char * ;输入:
int a [] = {1,2}; cout&lt;&lt; a&lt;&lt; ENDL;
只需打印 a 数组的地址(第一个元素的地址)。
答案 1 :(得分:0)
char arr[] = "test";
声明数组并初始化为&#34; test&#34;,并且让基地址为1000
char *ptr = arr
声明字符类型指针并将其初始化为相同的基址1000
cout << ptr << endl
打印整个字符串&#34; test&#34;因为1000通过了 但* ptr给出1000的值,而ptr是char类型所以......
cout << *ptr << endl;
第一个问题&#39; t&#39;打印出现在地址1000.
答案 2 :(得分:0)
在C ++中,数组的名称会自动转换为指向其第一个元素的指针。
存储在内存中的内容可能因编译器而异,但让我们让一个编译器告诉我们,gcc 6.3.0 for x86_64。 -S
标志告诉gcc编译为人类可读的低级汇编代码。 -O
标志告诉它优化。我们可以使用g++ -Wall -Wextra -Wpedantic -Wconversion -std=c++14 -O -S
来编译以下文件:
char arr[] = "test";
char* ptr = arr;
char* ptr2 = &arr[0];
constexpr unsigned int arr_size = sizeof(arr)/sizeof(arr[0]); // 5
char (*ptr3)[arr_size] = &arr; // A pointer to an array of arr_size chars.
char* const optimized_out = arr;
我会稍微编辑一下输出,以便更容易理解。我们从此命令(以.s
结尾)获得的文件稍微重新排列的版本如下:
.data
.globl arr
arr:
.ascii "test\0"
.globl ptr
.align 8
ptr:
.quad arr
.globl ptr2
.align 8
ptr2:
.quad arr
.globl ptr3
.align 8
ptr3:
.quad arr
那么,这说什么呢? .data
声明意味着我们正在声明已编译代码的数据段的内容。这适用于我们可以修改其内容的变量。
.globl
声明表示arr
是可以与其他源文件链接的符号。未缩进的行arr:
,ptr:
等是表示当前地址的标签。因此,当我们稍后链接到arr:
时,我们将链接到.data
段内的地址,即我们告诉汇编器放在那里的任何字节。这些是五个ASCII字符t
,e
,s
,t
和终止NUL。
同样,ptr
是一个全局变量,是.data
段内的地址。这里有一个新的指令,.align 8
。这意味着将指针放在可被8整除的地址上。(如果gcc实际上以这种方式放置文件,则需要在数组中的五个字节和对齐的指针之间浪费三个额外的填充字节;事实上,它最后放arr
所以它不需要。)在x86_64上,对齐的内存读取比未对齐的读取更快。
然后,x86_64程序集中的.quad
是一个64位变量,指针的大小。 (64位是16位的4倍,现代64位桌面CPU的远端祖先,8086,是一个16位字的机器。所以quad代表四字。)
此64位内存位置中存储了什么?值arr:
,它是五字节.ascii
数组的地址。
您会注意到ptr2
和ptr3
在程序集中都有相同的定义。该标准保证数组的名称衰减或隐式转换为指向数组第一个元素的指针。并且数组的地址与其第一个元素的地址相同;在任何数组元素之前都不能有任何填充。
在C ++中,您不能在没有char[]
的情况下将char*
的地址分配给reinterpret_cast
:char *this_does_not_work = &arr;
不起作用。这只是因为他们有不同的类型。数组的类型为char[5]
,将ptr3
声明为指向五个char
对象数组的指针的语法为char (*ptr3)[5]
。在这种情况下,为了“简单”,我为arr
的大小定义了一个符号常量,以防我们传递给arr
的字符串发生变化。数组的大小除以元素的大小等于数组中的元素数。 (该标准保证始终如此。)
地址&arr
,arr
和&arr[0]
均由标准保证相同;他们之间的唯一区别是他们的类型。您会注意到程序集文件实际上不包含任何类型信息;这允许您在另一个文件中声明类似extern char* const ptr3;
的内容并让它工作。如果你还给它-g
标志,GCC会将这些信息存储在符号表中,以便进行调试。
您会注意到源文件中有两个没有相应汇编语言定义的变量,constexpr
变量arr_size
和const
变量optimized_out
。事实上,如果你告诉它不要优化,gcc将包括这两个。使用-O
标志,它不会为编译时已知的小常量分配内存;它只会将5
替换为arr_size
或arr
替换为optimized_out
。但是,如果你曾经拿过他们的地址,就需要在内存中的某处存储这些变量的副本,例如&optimized_out
。
其中一些在C中略有不同,而在于C ++。