如果 char *name = "Emma",为什么 &name 与 &name[0] 不同?



我一直在关注 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') 的地址。

&namename的地址。它是指向指针的指针。

&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*

字符和字符串参数(例如,类型charconst 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);

最新更新