printf参数的问题。C/C++

4
我们有以下代码片段:
char tab[2][3] = {'1', '2', '\0', '3', '4', '\0'};
printf("%s\n", tab);

我不明白为什么在调用printf时没有出现错误/警告。我确实收到了警告,但没有错误,程序运行良好,打印“12”。printf期望的是char *类型的参数,即指向char的指针。因此,如果我声明char arr[3],则arr是包含char的内存单元的地址,因此如果我使用它调用printf,则会衰减为pointer to char,即char *。类似地,tab是包含3个char的数组的地址,这些char类型的内存单元的地址是char,因此tab将衰减为char **,这应该是一个问题,因为printf期望char *。
有人能解释一下这个问题吗?
补充说明:
我得到的警告是:
a.c:6: warning: char format, different type arg (arg 2)

以下你说它可以工作,但在这里你又说明你得到了“一个错误/警告”。你确切地得到了什么?使用这种容易出错的代码会收到警告是合理的,但你是否收到了错误? - Daniel Daranas
4个回答

6

示例源代码

#include <stdio.h>

int main( void ) {
  char tab[2][3] = {'1', '2', '\0', '3', '4', '\0'};
  printf("%s\n", tab);

  return 0;
}

编译警告

$ gcc test.c
test.c: 在函数‘main’中:
test.c:5: 警告:格式为‘%s’的参数,预期类型为‘char*’,但实参的类型为‘char (*)[3]’

指针就是指针

printf函数中的%s参数表示该函数将接收一个指向字符串的指针。在C语言中,字符串只是一系列以ASCII-Z结尾的字节。而tab[2][3]变量是一个指针。有些编译器会发出关于指针不匹配的警告。然而,代码仍应该打印出12,因为printf函数从它所获得的指针开始遍历内存(打印字符),直到找到一个零字节。1、2和\0在内存中是连续设置的,从由tab变量表示的地址开始。

实验

作为一个实验,当您编译并运行以下代码时会发生什么:

#include <stdio.h>

int main( void ) {
  char tab[2][3] = {'1', '2', '\0', '3', '4', '\0'};
  printf("%s\n", tab[1]);

  return 0;
}

不要害怕尝试。看看你是否可以根据现有知识得出答案。在实验的基础上,您现在应该如何引用tab(以消除警告并仍然显示12)?


这很简单。这是调用printf的正确方式。tab [1]的类型为char [],与使用char *调用printf相同。因此,一切都是最优的。 - Ori Popowski
没错。所以要显示“12”,你应该使用tab[0]。 - Dave Jarvis

4

tab参数匹配printf()调用中的省略号。C和C++编译器没有义务检查这样的参数。


4
你认为 tab 会衰变成 char ** 是错误的: tab 的类型是 char [2][3],即它将衰变为 char (*) [3]。重要的是要明白,虽然数组和指针经常表现得相似,但它们并不是同一种东西。printf() 需要一个 char *,因此它会取出 char (*) [3] 的位并相应地解释它们。虽然在你的平台上它能工作,但 C 标准并不保证这一点:两个指针都引用相同的内存位置,但它们的表示可能不完全相同。

有关详细信息,请查看我的答案以及这个相关问题


+1,我知道这个问题已经在某个地方得到了解答,但我没有找到它。我所找到的唯一类似的东西是这个:http://stackoverflow.com/questions/232303/so-you-think-you-know-pointers - quinmars

1

你好像已经解释得很清楚了,我不知道还有什么需要补充的。

tab 是一个包含两个 char * 的数组。每个 tab 的元素是一个字符串,可以被 printf 使用,但 tab 本身是不可接受的,因为它是一个指向指针的指针。


1
tab和tab [0]指向相同的位置(“12”字符串),因此它们都可以工作,尽管不匹配。 - Carson Myers
您的问题似乎是编译器接受了代码。请参考Neil Butterworth的答案,了解原因所在。坦率地说,我很惊讶编译器能够识别printf()的语义并对其参数进行任何类型检查。 - Ari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接