C编程:为什么printf格式说明符%s对于数字“ 123”无效?

问题描述

我是一名C编程新手。

有了其他问题的答案,我可以理解“字符”一词可以表示各种元素;例如字母和数字。

我将“字符串”视为字符。

然后,请看以下几行:

#include <stdio.h>

main()
{
    int numbers = 123;
    printf("%c%s\n","N",numbers); 
}

当我尝试编译此代码时,显示错误消息,并且编译失败。

教科书“ The C Programming Language”第13页像下面这样说到printf格式说明符;

%c代表字符”

%s用于字符串”。

一个问题:

尽管“ N”是一个字符,但%c说明符为何无效?

第二个问题:

尽管变量“数字”的值为“ 123”,但它们是数字,包含在字符中。

我认为字符等于“字符串”。

然后,尽管我将%s用作“ 123”,但为什么无效?

我知道我的代码可以正常工作,如果我像下面这样修改它们:

#include <stdio.h>

main()
{
    int numbers = 123;
    printf("%s%d\n",numbers); 
}

但是我想了解为什么上面的代码无效。

解决方法

“尽管"N"是一个字符,但为什么%c说明符无效?”

"N"不是字符常量。它是字符串文字。 'N'是一个字符常量,与%c匹配。单引号和双引号之间的区别很重要。

说明符也永远是无效的。只有参数类型可以。

“然后,尽管我将%s用于"123",但为什么无效?”

您没有使用"123",它是字符串文字,并且会发出char *。您使用123123是存储在int numbers类型的对象中的整数值。 int格式说明符不允许使用%s参数,它需要类型为char *而不是int的参数。

那是区别。

,

说明

printf("%c%s\n","N",numbers); 

包含两个错误。

  1. 格式说明符%c期望传递单个字符。我们在C语言中定义字符常量的方式是使用单引号'N'
    通过使用双引号"N",您使用的是语法糖方式 C可以表示一个字符串,即由字符串终止符'\0'

    关闭的字符数组
  2. 123是一个整数,就像您正确编写了%d格式说明符一样

谈到最后一个错误,您给出了一个原始的解释

尽管变量“ numbers”的值为“ 123”,但它们是数字,包含在字符中。

我认为字符等于“字符串”。

然后,尽管我将%s用作“ 123”,但为什么无效?

尽管这显然是错误的解释,但我觉得它很有趣,并且值得解释。

123是一个字符串,是一个字符序列吗?就是这样!但这是源代码中的字符串。编译器将解析此字符序列,将识别整数,并确保此值存储在包含整数的内存位置中。在大多数现代计算机中,它将转换为0/1序列,代表4个字节中的数字123。

0b01111011

源代码的角度来看,"123"不一样吗?好吧,不。该数字用双引号引起来,因此编译器会将其解释为实际的字符串,并以n终止的字符序列存储在内存中

--------------------------
| '1' | '2' | '3' | '\0' |
--------------------------

并在内存中存储代表这些数字的ASCII值(假设使用ASCII编码)

-----------------------------
| 0x31 | 0x32 | 0x33 | 0x00 |
-----------------------------
,

我会直接回答你的问题。

第一个问题:

C编程语言区分双引号和单引号。双引号将创建string文字,而单引号将创建character文字。因此,例如'N'character,而"N"string仅包含一个字符,即N。因此,%c为何不这样有用,因为它需要一个字符,但是您要给它字符串 "N"

第二个问题:

变量numbers的值为“ 123”。使用C语言表示法,“ 123”将是包含字符“ 1”,“ 2”和“ 3”的字符串,而变量numbers现在包含整数 123 ,这就是%s无法为numbers工作的原因。尽管您可以将变量123的值转换为这样的字符串:

#include <stdio.h>

main()
{
    int numbers = 123;
    char numbers_string[4];
    sprintf(numbers_string,"%d",numbers); // conversion happens here
    printf("%s\n",numbers_string); 
}

此外,您的问题中的“字符串”和“字符”这两种类型之间似乎存在混淆。重要的是要了解这两种类型是不同的。字符是一个字节(通常),该字节保存所需字符的ASCII码。例如,字符'A'(ASCII码= 65)。但是“字符串”是字符的集合,例如"Apple",在C语言中,通常使用char*来实现“字符串”,该指针指向存储了字符的内存位置按顺序。 (这就是为什么我使用字符数组来保存将numbers转换为“字符串”的结果的原因)

,

尽管“ N”是一个字符,但%c指定符为何无效?

"N" string ,不是单个字符-双引号表示字符串文字。 'N'(单引号)将是字符常量 1 ,因此

printf( "%c\n",'N' );

将正常工作。要打印"N",您需要使用%s转换说明符:

printf( "%s\n","N" );

%s转换说明符期望其对应的参数具有类型char *(指向char的指针),并且它将告诉printf打印从以下位置开始的字符序列指定的地址,直到看到字符串终止符为止。

表达式"N"的类型为“ char的2元素数组”(char [2]),数组的内容为{'N',0}。在C语言中,字符串是字符值的序列,包括一个用于标记字符串结尾的0值终止符。字符串(包括字符串文字)存储在字符类型的数组中。

在大多数情况下,类型为“ T”(T [N])的N元素数组的表达式将被转换(“衰变”)为类型的表达式“ T的指针”(T *),表达式的值将是数组第一个元素的地址。

在上面的printf语句中,表达式"N"从类型char [2]转换为char *,表达式的值是第一个字符的地址。

尽管变量“数字”的值为“ 123”,但它们是数字,包含在字符中。

让我们看一下numbers的声明:

int numbers = 123;

首先,numbers变量的 type int,而不是char *。它包含什么值都没有关系,它不是%s期望的类型。其次,123不是字符串-也不用引号引起来。而是一个整数常量。

numbers不是字符串-它不是存储字符串的正确类型,并且不包含带有0终止符的字符序列。这是一个整数,存储十进制值123的二进制表示形式。要打印出来(即在输出设备上产生该整数值的文本表示形式),请使用%d%i


  1. 在C中,像'N'这样的字符常量的类型为int,而在C ++中,它们的类型为char