代码之家  ›  专栏  ›  技术社区  ›  Ree

修改指针指向的字符串是否有效?

c
  •  1
  • Ree  · 技术社区  · 16 年前

    下面是一个连接两个字符串的程序的简单示例。

    #include <stdio.h>
    
    void strcat(char *s, char *t);
    
    void strcat(char *s, char *t) {
        while (*s++ != '\0');
        s--;
        while ((*s++ = *t++) != '\0');
    }
    
    int main() {
        char *s = "hello";
        strcat(s, " world");
        while (*s != '\0') {
            putchar(*s++);
        }
        return 0;
    }
    

    9 回复  |  直到 16 年前
        1
  •  19
  •   MSN    16 年前

    未定义的行为意味着编译器可以发出执行任何操作的代码。工作是未定义的一个子集。

        2
  •  4
  •   overslacked    16 年前

        3
  •  2
  •   Norman Ramsey    16 年前

    也许令人惊讶的是,编译器已经分配了文本 "hello" 转换为读/写初始化数据,而不是只读初始化数据。你的作业会重击与该点相邻的任何东西,但你的程序又小又简单,以至于你看不到效果。(把它放在一个for循环中,看看你是否正在重击 " world" 文字的。)

    gcc 将字符串文字置于只读数据中,当您尝试写入时,硬件MMU对象。

        4
  •  1
  •   Martin Beckett    16 年前

    这次你很幸运。
    特别是在调试模式下,一些编译器会在声明周围放置备用内存(通常填充一些明显的值),以便您可以找到这样的代码。

        5
  •  1
  •   Paul Beckingham    16 年前

    char * ptr;
    

    可以更改ptr指向的内容,但不能更改ptr:

    char const * ptr;
    

    可以更改ptr,但不能更改ptr所指的内容:

    const char * ptr;
    

    无法更改任何内容:

    const char const * ptr;
    
        6
  •  1
  •   Christoph    16 年前

    根据C99规范(C99:TC3,6.4.5,§5),字符串文字是

    […]用于初始化静态存储的数组持续时间和长度 足以容纳序列的。[...]

    char [] ,即原则上可以修改。第6节解释了您不应该这样做的原因:

    适当的值。如果程序试图修改这样的数组,则该行为是 未定义。

    具有相同内容的不同字符串文字可以(但不必)映射到相同的内存位置。由于行为是未定义的,编译器可以自由地将它们放在只读部分,以便彻底失败,而不是引入可能难以检测的错误源。

        7
  •  1
  •   Pete Kirkham    16 年前

    我想知道它为什么有效

    没有。它导致Ubuntu x64上出现分段错误;要让代码正常工作,它不应该只是 work on your machine .

    int main() {
        char b[] = "hello";
        char c[] = " ";
        char *s = b;
    
        strcat(s, " world");
    
        puts(b);
        puts(c);
    
        return 0;
    }
    

    虽然只有当“世界”适合堆栈数据之间未使用的空间时,您才是安全的-更改 b “hello to”和linux检测到堆栈损坏:

    *** stack smashing detected ***: bin/clobber terminated
    
        8
  •  0
  •   Crashworks    16 年前

    const char *s = "hello";
    

    由于常量修饰符丢失,您基本上禁用了防止写入不应该写入的内存的安全性。C几乎不能阻止你射中自己的脚。在这种情况下,你很幸运,只擦伤了你的小拇指。

        9
  •  0
  •   Renze de Waal    16 年前

    s指向一个包含“hello”的内存位,但并不打算包含更多的内容。这意味着您很可能会覆盖其他内容。这是非常危险的,尽管它似乎起了作用。

    两项意见:

    1. *in*s--不是必需的。s--就足够了,因为您只想减小该值。
    2. 你不需要自己写strcat。它已经存在了(你可能知道,但我告诉你:-)。