【问题标题】:Increment char pointer递增字符指针
【发布时间】:2016-07-01 11:52:46
【问题描述】:

以下代码在第二行给出了段错误:

 char *tester = "hello";
 char a = (*tester)++;  // breaks here
 printf("Char is %c\n", a);

以下代码有效:

 char *tester = "hello";
 a = *tester;
 a++;
 printf("Char is %c\n", a);

 // prints i

为什么不能一次完成?

【问题讨论】:

  • testerchar *(*tester) 是一个常量字符。您正在尝试增加一个常量字符。

标签: c char increment


【解决方案1】:
 char *tester = "hello";

您正在尝试在此处直接创建指向字符串的指针。这将导致意外行为(因为它是只读空间)

相反,我建议您使用字符数组

【讨论】:

    【解决方案2】:

    我认为没有一个答案完全回答了 op 的问题:op 想将 'h' 取消引用到 'i',并且他还想知道 segmentFault 来自他的第一个代码 sn-p 的原因

    结合上面的答案/cmets,我在这里列出一个完整的答案:

    A. op的第一个困惑来自char s[]char *s的概念区别:

    char *s="hello"; 是将字符串文字“hello”放在只读内存中,并将s 作为指向该字符串文字的指针,从而使任何写入操作都是非法的。而如果定义:

    char s[]="hello"; 是将字符串字面量放入只读内存中,然后将该字符串复制到另一个栈上分配的内存,这样就可以直接读/写在堆栈内存上(仍然,您没有触及只读内存)。

    所以取消引用char *test 会给你一个常量字符,它是位于只读内存上的字符串文字的第一个字母,这就是尝试char a = (*tester)++ 会失败的原因,因为这是一个指针操作只读内存,行为未定义。

    B.为什么第二个代码 sn-p 有效?

    a = *tester;意味着你声明另一个变量char a,然后在堆栈内存上,为char分配一些空间并将其值初始化为'h'; 这相当于有以下内容:

    char a;
    a = 'h';
    

    当然你可以增加a

    这是显式打印地址的示例:run link

    #include <stdio.h>
    
    int main()
    {
        char * tester = "hello";
        printf("tester first  letter address=%p\n",  tester);       // print out address should be something like 0x400648
        printf("tester second letter address=%p\n", (tester+1));    // print out address should be something like 0x400649
    
        char a;
        a = *tester;
        printf("a address=%p\n", &a);                               // print out address should be something like 0x7ffe0bc6aab7
        a++;        
        printf("a address=%p\n", &a);                               // print out address should be something like 0x7ffe0bc6aab7
    
        return 0;
    }
    
    

    【讨论】:

      【解决方案3】:

      我猜你正在尝试做这样的事情..

      const char *tmp = "Hello world. This is a great test";
         int count = strlen(tmp);
         while(count>0)
         {
            printf("%s\n",tmp);
            tmp++;
            count--;
         }
      

      【讨论】:

        【解决方案4】:

        有可能,你只是在增加错误的东西。 (*tester)++ 递增tester 指向的数据。我相信您想要做的是*(++tester),它将增加指针然后取消引用它。

        【讨论】:

        • Nit: *(tester++) 计算出tester 指向的before增量;它在逻辑上等同于a = *tester; tester++。如果你想要第二个字符,你可以写*(++tester)
        • 我想将 'h' 增加到 'i'。
        • @JohnBode 你说的很对。我已经更正了我的答案
        【解决方案5】:

        char a = (*tester)++; 不会像您假设的那样增加指针;它增加了取消引用的指针,即指针指向的值。

        您实际上是在尝试对可能驻留在只读内存中的字符串文字进行更改,从而导致未定义的行为。

        参见 n1570, 6.4.5 字符串文字:

        7 不确定这些数组是否是不同的,前提是它们的 元素具有适当的值。如果程序试图 修改这样的数组,行为未定义。

        要增加指针,请使用char a = *(tester++);,或者只使用char a = *tester++;,这要归功于运算符优先级。

        【讨论】:

          【解决方案6】:

          如果你想增加字符,你可以给它加1,而不是使用增量运算符:

          char *tester = "hello";
          char a = (*tester) + 1; // instead of (*tester)++
          printf("Char is %c\n", a);
          

          希望这就是您要搜索的内容。

          说明

          在另一个答案中,zenith 评论了为什么不能使用增量运算符的解释:

          像“hello”这样的字符串字面量在只读存储器中初始化。不可能增加它的值。这就是为什么你必须先复制值,如果你想改变它。 char a = (*tester) + 1; 取第一个字符的值,将其加 1 并保存到 a

          【讨论】:

          • 谢谢。我看到这行得通,但不清楚为什么不能一口气完成。这是一个语法问题,而不是寻找一种不同的方法。
          • @CorryChapman 因为i++i = i+1 相同,所以i 改变了,而a = i+1 不改变i。为什么这有关系? i 是字符串文字的一个字符,更改它会导致未定义的行为。
          【解决方案7】:
          char *tester = "hello";
          

          这里 tester 指向一个字符串常量。它存储在只读存储器中。任何写入修改都会导致未定义的行为。

          正如@Taelsin 指出的那样,您似乎想要增加指针本身,而不是它指向的内容。你需要 *(++tester)。

          经过OP的澄清:

          如果你想将 H 增加到 I,那么 (*tester + 1) 就可以了。

          【讨论】:

          • 谢谢。不,我实际上想取消引用“h”并将其增加到“i”。我想我不明白为什么它是一个字符串常量。你能详细说明一下吗?
          • Tester 是一个指向字符串常量的指针。像 char tester[]="Hello" 不同于 char *tester = "Hello"
          • @CorryChapman 在 C 中,像 "hello" 这样的字符串文字存储在只读内存中。您不能直接修改该字符串的内容。这就是为什么在足够的警告级别上将该字符串文字分配给指向非 const 的指针(就像您所做的那样)会发出警告。如果要修改内容,必须先将字符串复制到可变数组:char tester[] = "hello";
          • @zenith 详细信息:在 C 中,尝试写入像 "hello" 这样的字符串文字的地址是未定义的行为。 C 没有定义存储"hello" 的内存类型。它可能在只读存储器中,它可能在可写存储器中。它可能会出错。它是UB。 "Hello" 被正确地称为 string literal.
          猜你喜欢
          • 2023-04-05
          • 1970-01-01
          • 2021-12-11
          • 1970-01-01
          • 2010-09-23
          • 2017-01-05
          • 1970-01-01
          相关资源
          最近更新 更多