【问题标题】:Incrementing character in string literal字符串文字中的递增字符
【发布时间】:2014-07-15 04:58:41
【问题描述】:
    #include<stdio.h>
    int main(){
       char *ptr="Helio";
       ptr++;
       printf("%s\n",ptr);
       //*ptr++;
       printf("%c\n",++*ptr);/*Segmentation fault on GCC*/
       return 0;
    }

Q1) 这在 Turbo C++ 中运行良好,但在 GCC 上会出现分段错误。我没有得到确切的原因。

可能运算符优先级是原因之一。

Q2) 每个编译器都有不同的运算符优先级吗?

正如我所见,here ++ 的优先级高于取消引用运算符。可能是 GCC 和 Turbo C++ 对待它们的方式不同。

【问题讨论】:

  • 不,这是因为您指向一个常量字符串,但您取消引用第一个字符
  • 你想增加ptr或ptr[0]中的值吗?
  • 运算符优先级不可能是问题...(++*)ptr 语法无效!
  • @MattMcNabb 但它会在注释掉的行中有所不同,没有括号它相当于*(ptr++)。也许这就是令人困惑的地方,两种形式之间的行为完全不同。

标签: c++ c gcc turbo-c++


【解决方案1】:

不,运算符优先级是由 C 标准定义的,所有编译器都遵循相同的。

这种情况下Turbo C++和GCC结果不同的原因是你修改了字符串字面量,这是未定义的行为。

改成:

char arr[] = "Helio";
char *ptr = arr;

你现在可以修改字符串的内容了。注意arr本身就是数组名,不能修改,所以我新增了一个指针变量ptr,并初始化为指向数组的第一个元素。

【讨论】:

    【解决方案2】:

    在最后一行printf() 中,表达式++*ptr 等价于++ptr[0],而后者又等价于ptr[0] = ptr[0]+1。由于ptr[0]=='H',您正试图将ptr[0] 的值更改为'I'

    这是那里的关键问题。由于&amp;ptr[0] 指向常量"Helio" 的第一个元素,因此尝试更改第一个字符H 会带来麻烦,因为它是未定义的行为。

    【讨论】:

    • @v.oddou +1 这是对正确答案的一次很好的尝试:)。没有反对意见。
    • @v.oddou:我的答案是一个非常简单且非常标准的答案,因此它没有真正的“所有者”。没有什么可以抄袭的。你的答案从错误的概念开始。另一方面,于浩在中心问题上并不完全清楚。所以,我决定给出一个清晰而简单的答案。 Jayesh 非常了解这种情况。
    • @pablo1977:我编辑了它,所以“从错误的概念开始”部分不再适用。在我看来,从来没有,但那只是我。其余的你都是对的。但请理解,人们只是决定盲目地遵循 quantdev 的言论,并且实际上现在让我的答案不可见,而实际上它比你的答案更多,而且你已经有一个赞成票,我对此感到坦率地感到痛苦。哪里公平
    • @v.oddou 为什么不公平地投票给好的答案?任何人都不会强迫任何人使用这样或这样的语法。让编译器保留它会做得最好。无论如何,您的尝试都是好的,并感谢所有 cmets。坚持下去。当您在其中制作版本时为您 +1。
    • @Jayesh:谢谢 :) 我很感激。为了让大家开心,我做了很多编辑。
    【解决方案3】:
    char* p = "some literal";
    

    这只是合法的,因为 C 人在标准委员会谈判期间争论不休。您应该将其视为为向后兼容而存在的奇怪之处。

    这是您通过 GCC 得到的信息:

    警告:不推荐将字符串常量转换为 'char*'

    请下次写下:

    char const* p = "some literal";
    

    让它成为你编码习惯的一种反映。那么你将无法编译你的错误行。

    这是:

    ++*ptr
    

    在这里,您将获取常量文字的第一个字符并尝试将其递增到 H 之后的内容,因此是 I。但是这个内存区域恰好在一个写保护的页面中,因为这是一个常数。这在标准中非常未定义,您应该认为它是非法的。你的段错误来自这里。 我建议你下次在valgrind 运行你的程序以获得更详细的错误消息。

    在于浩为你写的答案中,发生的事情是所有字符都被一个一个地复制,从存储文字的常量字符串池到堆栈分配的字符数组,通过代码编译器在初始化/声明站点写入,因此您可以取消引用其内容。

    【讨论】:

    • 这不是非法声明
    • 你应该像这样考虑。因为您将 const 从 const 转换为非 const。只要您仅以读取方式访问,就可以,但是以写入和繁荣的方式访问。一些编译器在这种声明上给出构建错误。
    • @v.oddou 一切都是对的,就像修改字符串文字是非法的,因为它是只读部分。但它的声明并不违法。它只是创建了一个指针并将其指向一个常量字符串。所以先纠正一下。
    • 我没有投反对票,但我觉得选择准确的措辞非常重要,而不是迂腐,并且是进入 StackOverflow 等 QA 网站的唯一途径。初学者很容易把你读成“这是非法的!它不应该编译!那么为什么我的编译器要编译这个?!”。要求苛刻对每个人都有好处。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-04-29
    • 2013-11-30
    • 1970-01-01
    • 1970-01-01
    • 2014-10-08
    • 1970-01-01
    相关资源
    最近更新 更多