【问题标题】:Difference between printf("%c",*(*(ptr+i)+x)) and printf("%s",*(*(ptr+i)+x))printf("%c",*(*(ptr+i)+x)) 和 printf("%s",*(*(ptr+i)+x)) 的区别
【发布时间】:2019-12-12 22:20:24
【问题描述】:

我有一个指针数组,当我尝试这个 C 代码时,得到了分段错误的错误。我在这里做错了什么?

  char *ptr[] = {"exam","example","testexample"};
    printf("%c\n",*(*(ptr+2)+7));
    printf("%s\n",*(*(ptr+2)+7));

在第一个打印语句的输出中给出预期的结果

   printf("%c\n",*(*(ptr+2)+7)); 
  m

但是第二个而不是输出

  mple

给予

   printf("%s\n",*(*(ptr+2)+7));    Segmentation fault (core dumped)

我在这里做错了什么?

【问题讨论】:

  • 在第二个示例中,您使用 'm' 的字符值作为指针,这是一个无效的指针值。删除一个*printf("%s\n",*(ptr+2)+7);
  • 让我们更容易理解正在发生的事情的一件事是记住对于任何指针ptr 和索引i,表达式*(ptr + i)完全 相等的到ptr[i]。尝试将您的指针算术表达式转换为数组索引语法,它应该会变得更加清晰。

标签: c pointers printf undefined-behavior c-strings


【解决方案1】:

表达式的类型

*(*(ptr+2)+7)

char。所以printf的第一次调用是正确的。

但第二次调用不正确,因为格式说明符%s 需要char * 类型的参数。因此,通过表达式*(*(ptr+2)+7) 获得的字符的值,即字符'm'(例如在ASCII 中具有值100)被解释为地址。

在第二次调用中使用

*(ptr+2)+7

这是一个演示程序

#include <stdio.h>

int main(void) 
{
    char *ptr[] = { "exam", "example", "testexample" };

    printf( "%c\n", *( *( ptr + 2 ) + 7 ) );

    printf( "%s\n", *( ptr + 2 ) + 7 );

    return 0;
}

它的输出是

m
mple

【讨论】:

  • 谢谢你,但你能解释一下为什么它会给出分段错误错误吗?
  • @ArnabBhowmick 未定义的行为! "%s" 格式需要一个指向以零结尾的数组(char * 类型)的第一个字符的指针。您在问题中使用显示的代码传递的是单个 char 元素。不匹配的格式说明符和参数是 UB。
  • 感谢@Someprogrammerdude 的澄清。我明白了
【解决方案2】:

您的论点 *(*(ptr+2)+7) 计算为 一个字符,其值为 'm',(在基于 ASCII 的平台上)与数字 109 相同。

当你这样做时

printf("%s\n",*(*(ptr+2)+7));

一模一样

printf("%s\n",'m');

它被编译为加载数字 109into a register and pushes that register on the stack. It doesn't tellprintfanything about _where it found_ that'm'` 的机器码——只有一个原始 ASCII 值被传递给函数。

printf 然后尝试将 109 解释为不是字符本身,而是作为指向某些字符的 指针 —— 因为这是你通过写 %s 要求它做的事情。不出所料,这会出现严重错误,因为 109 不是允许程序访问的任何地址。

如果你想打印字符串的尾部,你可以写

printf("%s\n", *(ptr+2)+7 );

* 运算符应用于您要传递的指针的位置。

【讨论】:

  • 您的描述不一定正确,例如也许系统使用不同的寄存器来传递指针而不是 int 值
  • @M.M:原则上是对的。但我认为很有可能在 OP 正在处理的系统上并非如此。
【解决方案3】:

((ptr+2)+7) 是一个char值

所以第一个语句是正确的,因为 "%c" 告诉 printf 第一个参数是一个字符:

printf("%c\n",*(*(ptr+2)+7));

但是在第二个语句中,"%s" 告诉 printf 第一个参数是 (char *),它是一个指向 char 的指针。 这样,当程序执行时

printf("%s\n",*(*(ptr+2)+7));

查看 ((ptr+2)+7) 的值(一个 char 值,在本例中为 'm' ),就好像它在哪里是一个 char 指针。 这就是分段错误的原因。

所以修正后的 secon 语句应该是

printf("%s\n",*(ptr+2)+7);

希望这会有所帮助。

【讨论】:

    【解决方案4】:

    问题在于*(*(ptr+2)+7) 表达式的使用——很难看出它的作用。该结构主要由尚未深入了解 C 的初学者使用。这就是为什么 C 有一个语法糖:*(*(ptr+2)+7) 完全等同于 ptr[2][7],这是您应该使用的形式。

    现在,ptr[2][7] 显然是 char,但 %s 需要一个 指向 char 的指针,它是空终止字符串中的第一个字符,所以让我们传入一个指向那个字符的指针

    printf("%s\n", &ptr[2][7]);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-26
      • 2023-04-11
      相关资源
      最近更新 更多