【问题标题】:why print out a char pointer yield the entire array instead of the memory addr of the pointer?为什么打印出一个 char 指针产生整个数组而不是指针的内存地址?
【发布时间】:2016-03-17 09:44:54
【问题描述】:
int aryint[4] = {1,2,3,4};
char *ptr = "1234";
char ch ='a'; 
char *chptr = &ch;

//chptr =  3509449623 (mem addr)
printf("chptr =  %u,  chptr);

//aryint =  3509449648 (mem addr)
printf("aryint =  %u ", aryint);

//ptr =  1234 
printf("ptr =  %s, ptr);

为什么打印出一个字符点“ptr”会返回整个char数组(整个字符串),而打印出一个字符点“chptr”会返回“chptr”的mem addr?

如果这是因为“ptr”指向一个数组,那么为什么打印出数组“aryint”只返回aryint的mem addr(而不是整个数组)? 所以打印出整个数组只适用于字符串常量?还是因为 %s?

但是当我尝试在 ptr 的 printf() 上用 %u 替换 %s 时,我也得到了一个常量 (4197008),它相当于整个数组/字符串 (1234),而不是内存地址:

//ptr u =  4197008 (a constant not mem addr), ptr s = 1234,
printf("ptr u =  %u, ptr s = %s”, ptr, ptr)

但是,当我尝试打印 char 数组“str”时,当我在“str”上应用 %u(而不是 ptr 中的整个数组)时,我得到了 mem 地址。但是当 %s 应用于“str”时,我再次打印了整个数组,而不是之前在 chptr 和 aryint 中的内存地址。

char str[5] = "1234"; 
//str u = 3509449696 (mem addr), str s = 1234
printf("str u = %u,  str s =%s”, str, str );

这对我来说似乎有点奇怪。在用 C 编码时,我还应该注意什么其他奇怪的现象?我是新手。

任何帮助将不胜感激!

【问题讨论】:

  • 打印指针使用%p,而不是%u。使用错误的格式说明符会调用未定义的行为
  • 因为 %s 打印整个数组,而所有其他格式说明符只打印一个项目。这就是它的全部内容。
  • 'ptr' 上的 %u 也是如此。

标签: c arrays string pointers char


【解决方案1】:

printf 需要一个名为 格式字符串 的字符串,其中包含 格式说明符。这些由printf 解析(并由前导'%' 表示)。每当遇到一个时,printf 从传递的参数数量中获取下一个参数,并将格式说明符的含义“应用”到参数。

例子:

printf("%d", 1);

在上面的例子中,遇到了格式说明符"%d",它有自己的含义:它需要一个int类型的参数。 1 是一个int,所以程序定义明确,很好。

为什么打印出一个字符点“ptr”会返回一个完整的字符数组(整个字符串)[...]

因为这就是 "%s" 格式说明符的工作方式。它需要 char* 并打印所有 chars,直到找到空字节 ('\0')。

[...] 并打印出一个字符点“chptr”返回“chptr”的mem addr?

它是undefined behavior,因为格式说明符(期望unsigned int)和参数类型(char*)不匹配,并且两者之间没有隐式转换。它根本没有被标准定义。
当心:这就是标准所说的。请记住,该标准只是描述了一个抽象机器。具体机器确实在所述抽象机器的范围内运行,但是虽然抽象机器通过“未定义”定义了一组可能的结果,但具体机器表现出真实行为。实际行为取决于标准下的所有内容(托管实现和硬件上的操作系统),但这就是printf("chptr = %u, chptr); 在普通机器上实际发生的情况:

  1. 打印前导部分"chptr = "
  2. 遇到百分号,解析"%u"
  3. %u 表示unsigned int,所以unsigned int 会从参数列表中弹出。 printf 不知道参数的确切类型,因为它使用变量参数列表。它是类型不安全的
  4. 获取sizeof(unsigned int) 字节,将其解析为unsigned int,然后打印出来。 sizeof(char*) == sizeof(int) 是否取决于实现,因此很可能会弹出太多/太少的字节,从而导致整个程序崩溃。毕竟,这是未定义的行为。

最后,请记住始终使用适当的格式说明符 not to use printf(user_defined_string) or puts(user_defined_string),并阅读标准以了解可能的未定义行为实例。

【讨论】:

    【解决方案2】:

    它是字符串的 %s 说明符,当它到达空字符 (\0) 时会停止打印。另一方面,%u 是无符号十进制整数的说明符。

    阅读printf() 和格式说明符here。您应该使用%p 来打印指针地址。

    【讨论】:

      【解决方案3】:

      ptr 指向一个array of characters (string)。当您使用说明符%s 执行printf 时,您是在告诉程序您希望打印string,因此当您给它ptr 时,它会打印出string

      如果要打印pointer value,请改用%p

      【讨论】:

        【解决方案4】:

        'ptr' 是一个指针,它已被初始化为指向一个字符串常量。字符串常量通过指向其第一个元素(即字符数组的第一个元素)的指针访问。

        如果 'printf' 接收到一个指向字符数组开头的指针 - 它将访问相关的字符串常量并打印字符串 ...

        参见 Ritchie 等人第 87 页“C 编程语言”

        【讨论】:

          猜你喜欢
          • 2011-08-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多