【问题标题】:About character pointers in C关于 C 中的字符指针
【发布时间】:2023-04-06 09:38:01
【问题描述】:

考虑这个定义:

char *pmessage = "now is the time";

在我看来,pmessage 将指向内存中包含这些字符的连续区域,最后是'\0'。所以我从中得出,只要我在这个区域的范围内,我就可以使用指针算法来访问这个字符串中的单个字符。

那么为什么他们说 (K&R) 修改单个字符是未定义的?
此外,为什么我在运行以下代码时会出现“Segmentation Fault”?

*(pmessage + 1) = 'K';

【问题讨论】:

  • 那么,如果我们这样定义,为什么可以修改字符串: char amessage[] = "now is the time";使用这个:message[1] = 'K'; ?有什么区别?
  • SIGSEGV 是当您执行 K&R 认为未定义的事情时可能发生的事情之一。
  • @Leif:在这种情况下,您不会修改字符串文字本身。您已在当前范围内定义了一个字符数组,并要求编译器确保该数组已初始化为某个字符串。你可以随意修改你的数组,因为它没有被声明为 const。
  • 标准C/C++ docs.sun.com/source/819-3689/Ch3.Std.html#23706987654321@的解释

标签: c arrays pointers


【解决方案1】:

C 中的字符串文字是不可修改的。字符串文字是在程序的源代码中定义的字符串。编译器会经常将字符串文字存储在已编译二进制文件的只读部分中,因此您的 pmessage 指针实际上位于您无法修改的该区域。可以使用上述语法修改存在于可修改内存中的缓冲区中的字符串。

试试这样的。

const char* pmessage = "now is the time";

// Create a new buffer that is on the stack and copy the literal into it.
char buffer[64];
strcpy(buffer, pmessage);

// We can now modify this buffer
buffer[1] = 'K';

如果你只想要一个可以修改的字符串,你可以避免使用具有以下语法的字符串文字。

char pmessage[] = "now is the time";

该方法直接将字符串创建为栈上的数组,可以就地修改。

【讨论】:

  • 不应该是“char * buffer = malloc(512);”吗?
  • 是的,我最初有 char buffer[] = new char[512];并错误地转换它。谢谢。
  • @David: 是的,应该是 char *buffer,或者许多其他的东西,而不是所示的不完整类型。最好是 'char buffer[] = "now is time";'并且没有 malloc() 所以没有泄漏 - 也没有字符串复制。
  • 从技术上讲,使用数组方法,您不会在某个时候将文字复制到堆栈上,从而复制字符串吗?我将修改示例以摆脱动态内存使用。
  • 编译器会初始化变量——是的,所以在某处会有一个字符串副本。但它不会溢出边界等。现在这是一个很好的答案 - 做得好。
【解决方案2】:

字符串是常量,不能修改。如果你想修改它,你可以这样做:

char pmessage[] = "now is the time";

这会初始化一个字符数组(包括 \0),而不是创建一个指向字符串常量的指针。

【讨论】:

  • 这将与问题中的原始示例存在相同的问题。
  • 没有实际查找,我不这么认为。这相当于将 char pmessage[16] 初始化为“现在是时间”(单个字符后跟 \0)。我认为它有效。
  • @David 我也是这么理解它的工作原理的。而且我无权使用 C 编译器来尝试它:P 我暂时让我的无知代表它,如果它是无知的话:P
  • char pmessage[] 与问题中提到的问题不同。这里的 pmessage 是读写缓冲区。答案绝对没问题。
【解决方案3】:

您可以使用指针算法从字符串文字中读取,但不能写入它。 C 标准禁止修改字符串文字。

【讨论】:

  • 可能是这样,但不是编译器抱怨,而是内存保护抱怨。我怀疑他在某些嵌入式非保护模式硬件上运行它会遇到问题。
  • 那又怎样?就 C 标准而言,它仍然是未定义的行为。
  • 是的,但是在我学习 C 的系统上(CP/M,Mac OS 6 左右)它可以正常工作(对于某些工作值),当然不会有内存保护问题。
  • “正常工作”通常是未定义行为的表现方式 :-)
  • 一些编译器允许您将所述字符串存储在 R/W 存储中,尽管我从不使用该功能。 IBM XLC 允许您这样做:publib.boulder.ibm.com/infocenter/comphelp/v8v101/…
【解决方案4】:

“字符串”字面量是在只读内存中定义的,因此您不应该修改它。

【讨论】:

    【解决方案5】:

    pmessage 的字面值进入代码,并且在大多数情况下它们被放置在代码内存中。 只读

    【讨论】:

      【解决方案6】:

      当你写: char *pmessage = "现在是时候";

      编译器将其视为您编写的:

       const char internalstring[] = "now is the time";
       char *pmessage = internalstring;
      

      之所以不能修改字符串,是因为如果你要写:

       char *pmessage1 = "now is the time";
       char *pmessage2 = "now is the time";
      

      编译器会把它当作你写的:

       const char internalstring[] = "now is the time";
       char *pmessage1 = internalstring;
       char *pmessage2 = internalstring;
      

      所以,如果你要改变一个,你会改变两个。

      【讨论】:

      • 编译器不需要这样做,但可以。它也不必将内部字符串放入只读存储器。这对标准无关紧要,因为一旦您尝试修改它,您就会陷入未定义的行为,并且编译器所做的任何事情都可以。
      • 另外,我认为你的例子不是“const”干净的。我不确定它是否会编译。当然,指针应该指向 const char,否则整个 const 就没有意义了。
      • @Ingo - 是的,如果这样写,那不会。然而,这仍然是内部正在发生的事情。文字字符串是 const char[],但隐含转换为(非 const)char*。隐含的转换仅适用于文字字符串。
      • @David:对不起,我并不是要暗示编译器必须这样做,只是它可以这样做,以解释为什么修改数组被声明为未定义行为。
      【解决方案7】:

      如果你定义一个字面量的形式:

      char* message = "hello world";
      

      编译器会将字符视为常量,并可能将它们放入只读内存中。

      因此,建议使用 const 关键字,这样任何更改文字的尝试都会阻止程序编译:

      const char* message = "hello world";
      

      我猜想文字上的 const 没有作为语言的一部分强制执行的原因只是为了向后兼容不存在 const 关键字的 C 的预标准版本。有人知道吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-04-01
        • 2013-07-12
        • 1970-01-01
        • 1970-01-01
        • 2014-05-13
        • 1970-01-01
        相关资源
        最近更新 更多