char * 到字符串文字如何有效?
Posted
技术标签:
【中文标题】char * 到字符串文字如何有效?【英文标题】:how is char * to string literal valid? 【发布时间】:2017-04-28 07:31:45 【问题描述】:所以从我的理解指针变量指向一个地址。那么,以下代码在 C++ 中如何有效?
char* b= "abcd"; //valid
int *c= 1; //invalid
【问题讨论】:
您最好使用const char*
for b,除非您打算更改字符串中的字符。
选择一种语言,而不是两种。 C 和 C++ 在这里是不同的。
【参考方案1】:
第一行
char* b= "abcd";
在 C 中是有效的,因为“字符串文字”在用作初始化器时,归结为文字中第一个元素的地址,它是一个指针(指向 char
)。
相关,C11
,第 §6.4.5 章,字符串文字,
[...] 多字节字符 然后使用序列来初始化静态存储持续时间和长度的数组 足以包含序列。对于字符串文字,数组元素有 键入
char
,并使用多字节字符的各个字节进行初始化 顺序。 [...]
然后,第 6.3.2.1 章(强调我的)
除非它是
sizeof
运算符、_Alignof
运算符或 一元&
运算符,或 是用于初始化数组的字符串文字,具有 type ''array of type'' 被转换成一个类型为 ''pointer to type'' 的表达式,它指向 到数组对象的初始元素并且不是左值。
但是,如 cmets 中所述,在 C++11
之后,这不再有效,因为字符串文字的类型为 const char[]
,在您的情况下,LHS 缺少 const
说明符。
哦,
int *c= 1;
无效(非法),因为1
是一个整数常量,与int *
的类型不同。
【讨论】:
请注意,将字符串文字分配给 non-constchar*
指针在 C++11 中已弃用。
顺便说一句,它只在 C++11 之前有效;之后,不允许删除 const
。
好的,我专注于 C 标记。将将此信息添加到答案中。
@RemyLebeau 在 C++03 中已弃用,在 C++11 中出现错误【参考方案2】:
在 C 和非常旧的 C++ 版本中,字符串文字 "abcd"
的类型为 char[]
,即字符数组。这样的数组自然会被 char*
指向,但不能被 int*
指向,因为这不是兼容的类型。
但是,C 和 C++ 是不同的,通常是不兼容的编程语言。大约 20 年前,他们放弃了彼此的兼容性。
在标准 C++ 中,字符串文字的类型为 const char[]
,因此您发布的代码在 C++ 中均无效。这不会编译:
char* b = "abcd"; //invalid, discards const qualifier
这将:
const char* c = "abcd"; // valid
【讨论】:
所以c指针将指向“abcd”是不是指针应该指向地址,否则如果指向其他任何东西它会输出错误? @sorryiamrookie 它将指向存储文字"abcd"
的地址。事实证明,这是一个只读地址。因此,如果您尝试修改那里的内容,程序可能会崩溃。因此,在 C 和 C++ 中,在指向字符串文字时始终使用 const char* c
是一个好习惯。
更准确地说,在这种特殊情况下,将字符串文字转换为非const
指针在 C++03 中已被弃用(即它仍然是合法的,但计划在未来标准)并最终在 C++11 中删除。这样做的结果是,使用这种转换的代码在 C++11 之前可以合法编译,但编译器会(如果配置适当以发出警告)给出警告。这种隐式转换在 C++ 中是非法的,因此不会编译,仅从 C++11 开始。
在 c 中,您必须始终使用 gcc 标志 `-Wwrite-strings` 进行编译,以检查并警告您,以防您忘记了文字的 const,但在 C++ 中默认启用。【参考方案3】:
"abcd"
实际上是 const char[5]
类型,语言允许将其分配给 const char*
(遗憾的是,char*
尽管 C++11 以后不允许这样做。)。
int *c = 1;
是 C++ 或 C 标准不允许的,因为您不能将 int
分配给 int*
指针(0
除外,在这种情况下,您的意图会更清楚地表达通过分配 nullptr
代替)。
【讨论】:
糟糕。是时候喝杯咖啡了。 @M.M.是时候再喝杯咖啡了——也许我会在周末从阁楼里拿出我的大学笔记;-)【参考方案4】:"abcd"
是包含五个字节序列97 98 99 100 0
的地址——在源代码中您看不到地址是什么,但编译器仍会为其分配一个地址。
1
也是您的 [虚拟] 内存底部附近的地址。这对您来说似乎没有用,但它是useful to other people,因此即使“标准”可能不希望允许这样做,但您可能遇到的每个编译器都会支持这一点。
【讨论】:
由于互操作性规则,字符串文字(本质上是一个数组)将衰减为指针类型。 int 不会衰减为指向 int 的指针。您是否尝试过在“每个编译器”上编译代码?我的肯定不会。 (谢天谢地) " 五个字节的序列 97 98 99 100 0" - 假设特定的编码,不保证。最后一个字节总是 0。 @sigbjornlo 你肯定会在正确的提示下使用,因为这种代码仍然很常见。 @Bathsheba sorryiamrookie 问题的哪一部分让您认为他们可以访问非 ASCII 系统? 问题上的标签。【参考方案5】:虽然所有其他答案都给出了为什么您的代码无法正常工作的正确答案,但使用 复合文字 来初始化 c
是让您的代码工作的一种方法,例如 p>
int *c= (int[]) 1 ;
printf ("int pointer c : %d\n", *c);
注意,C 和 C++ 在使用复合字面量方面存在差异,它们仅在 C 中可用。
【讨论】:
虽然非常正确,但这可能不是 OP 想要的。"abcd"
和 1
之间存在差异,OP 看起来对此很感兴趣。 :)
这很难说。这是我能想到的从文字 1
初始化 int *
的唯一方法,以使其看起来像他正在尝试做的事情——工作。
int *c= (int[]) 1 ;
获取临时数组的地址。
@DavidC.Rankin 正如我所说,你一点都没错,这只是恕我直言,不是在正确的上下文中,仅此而已。同样,这只是我的意见。
“细微差别”是指 C 有复合文字而 C++ 没有以上是关于char * 到字符串文字如何有效?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 GCC 中将重复或相乘的字符串文字合并为一个 [重复]
如何使用省略尾随 '\0' 的字符串文字初始化 std::array<char, N>