我一直在关注 CS50,我很确定我一直听说指针只是一个地址
并且数组的地址只是该数组中第一项的地址
但是当我运行以下代码时:
// we can also just create strings we need by using char * like this
char *name = "Emma 123";
char *another_string = "4";
printf("This is the string we get from name: %sn", name);
// Print the value of the pointer pointing to name
printf("This is the pointer we get from name: %pn", name);
// Now print out the address of the first letter in Emmas name
printf("This is the pointer we get by resolving &name: %pn", &name);
printf("This is the pointer we get by resolving &name[0]: %pn", &name[0]);
printf("Hmmmm. There is something different between &name and &name[0]. Somehow, I thought they should be the same ")
我得到这个作为输出:
This is the string we get from name: Emma 123
This is the pointer we get from name: 0x4007ad
This is the pointer we get by resolving &name: 0x7ffd2d7d5468
This is the pointer we get by resolving &name[0]: 0x4007ad
我一直在阅读背景文章,但不知何故,我似乎无法理解为什么 &name 和 &name[0] 不一样
编辑:我删除了c ++标签,因为我错误地认为这些元素是c和c ++共有的 编辑:然后我把它加了回来,因为看起来其他人也做了同样的事情,然后决定这是一个坏主意。尽量不得罪人
char *name = "Emma 123";
name
存储第一个元素 ('E') 的地址。
&name
是name
的地址。它是指向指针的指针。
&name[0] = &(*(name+0)) = (address of first element) = name
&name
是指向数组的指针的内存位置。
&name[0]
是数组中第一个字符的内存位置。
注意:由于这是一个多标记的C/C++问题:此答案适用于C++
<小时 />来自会员访问运营商:
内置下标运算符提供对指针或数组操作数指向的对象的访问权限。[...]
内置的下标表达式
E1[E2]
与表达式完全相同*(E1 + E2)
[除了求值顺序(自 C++17 起)],即指针操作数(可能是数组到指针转换的结果,并且必须指向某个数组的元素或一个过尾的元素)被调整为指向同一数组的另一个元素, 遵循指针算术的规则,然后取消引用。
意思是&name[0]
,&(name[0])
等价于&(*name)
。
另请注意,字符串文本应该是常量(编译器应拒绝程序,或发出有关不符合C++的警告)。更正的示例(C++,而不是 C):
#include <iostream>
int main() {
const char * name = "Emma 123";
std::cout << name << "n"; // Emma 123
std::cout << &name << "n"; // 0x7ffd2d7d5468
std::cout << &(*name) << "n"; // Emma 123
std::cout << &(name[0]) << "n"; // Emma 123
}
由于name
是指针,因此&name
是指向指针的指针。
#include <type_traits>
const char * name = "Emma 123";
static_assert(std::is_same_v<decltype(&name), const char **>);
static_assert(std::is_same_v<decltype(&(*name)), const char *>);
static_assert(std::is_same_v<decltype(&(name[0])), const char *>);
现在,虽然std::basic_ostream<CharT,Traits>::operator<<
有一个带有函数参数const void *
的重载,但它有一个非成员重载或用于const char*
字符和字符串参数(例如,类型
char
或const char*
)由非成员重载处理operator<<.
因此,对于const char*
参数,将选择非成员重载,这将打印字符数组中的字符,其第一个元素由const char*
指针指向。
但是,对于const char**
,将选择成员const void*
:
std::cout << &name << "n"; // 0x7ffd2d7d5468
std::cout << static_cast<const void*>(&name) << "n"; // 0x7ffd2d7d5468
对于C++(我不知道 C,但我知道这段代码无论是 C 还是 C++ 都是不同的):
字符串文本是常量。它应该是
const char *name = "Emma 123";
除此之外,name
已经是指向数组中第一个元素的指针。您可以通过以下方式获得预期输出:
#include <iostream>
int main(){
const char* name = "Emma";
std::cout << static_cast<const void*>(name) <<"n";
std::cout << static_cast<const void*>(&name[0]) << "n";
}
可能的输出:
0x402005
0x402005
需要静态强制转换来绕过打印字符串的char*
的ostream::operator<<
。
&name
是存储name
的地址,而不是存储在name
中的地址。
这个答案适用于C和C++,除了"在C++"的段落。
为什么 &name 与 &name[0] 不同?
因为存储指针的地址与指针指向的地址(数组所在的位置)是分开的。
并且数组的地址只是该数组中第一项的地址
您似乎将数组和指针混为一谈。数组不是指针,指针也不是数组。引用的句子是关于数组的,它不适用于指针。
char *name = "Emma 123";
这在C++中格式不正确(自 C++11 年以来)。字符串文本不可转换为指向非常量字符的指针。要解决此问题,请使用const char*
。
printf("This is the pointer we get from name: %pn", &name); printf("This is the pointer we get by resolving &name: %pn", &name);
该程序的行为未定义。必须传递正确类型的参数,并且在传递char*
和char**
时void*
%p
的正确类型。更正的示例:
const void* v_name = name;
void* v_name_a = &name;
printf("This is the pointer we get from name: %pn", v_name);
printf("This is the pointer we get by resolving &name: %pn", &v_name_a);