%s 或 %c 格式的 C 中 char 数据类型的大小?

The size of char datatype in C which is in format of %s or %c?

在网上查到C编程中char的资料如下:

Datatype        Size        Range           Format

char            1 byte     −128 to 127        %c

signed char     1 byte     −128 to 127        %c

unsigned char   1 byte        0 to 255        %c

但我知道有 %s 的 char(数据类型)格式,它用于处理字符串。我的问题是:这两种格式的大小和范围有什么区别吗? 谢谢大家!

A char 是单个 character/letter,例如使用 "%c" 打印,例如'X'.
"%s" 打印的是一个由许多字符组成的以零结尾的字符串,例如可以给出"foobar"。请注意不同的引号。
顺便说一句,在处理它们并尝试存储它们时,一个常见的错误是没有足够的 space 作为最后的零。通常需要多一个而不是显而易见的。)

比较https://en.cppreference.com/w/cpp/io/c/fprintf

%s通常指的"range"很难定义。可能是书。

%s 打印的内容有时被描述为 "C pseudo-string",但没有这样的数据类型。

C 中的字符串被定义为字符数组,其中包含以零字符“\0”结尾的字符序列。

例如,字符串文字 "Hello" 的类型为 char[6](考虑终止零字符)。所以运算符 sizeof( "Hello" ) 产生值 6.

转换说明符%s指定输出字符串并等待指向字符串第一个字符的指针。字符串的大小仅受所用系统资源的限制,不能大于类型size_t.

中存储的最大值

Th 转换说明符 %c 旨在输出 char 类型的标量对象。 char 类型的对象的大小等于 1sizeof(char ) 等于 1)。请记住,在 C 中,字符文字的类型为 int。因此,例如 sizeof( 'A' ) 产生 4(如果 int 类型的对象的大小等于 4)。

这是一个演示程序

#include <stdio.h>

int main(void) 
{
    printf( "sizeof( \"Hello\" ) = %zu\n", sizeof( "Hello" ) );

    char c = 'A';

    printf( "sizeof( char ) = %zu, sizeof( 'A' ) = %zu\n", sizeof( c ), sizeof( 'A' ) );

    return 0;
}

它的输出是

sizeof( "Hello" ) = 6
sizeof( char ) = 1, sizeof( 'A' ) = 4

注意 char 类型的取值范围取决于编译器选项,char 类型可以表现为 signed charunsigned char 类型。所以写

会更正确
char            1 byte     −128 to 127        %c
or
char            1 byte     0 to 255           %c

来自 C 标准(5.2.4.2.1 整数类型的大小)

2 If the value of an object of type char is treated as a signed integer when used in an expression, the value of CHAR_MIN shall be the same as that of SCHAR_MIN and the value of CHAR_MAX shall be the same as that of SCHAR_MAX. Otherwise, the value of CHAR_MIN shall be 0 and the value of CHAR_MAX shall be the same as that of UCHAR_MAX. The value UCHAR_MAX shall equal 2CHAR_BIT − 1.

%c 用于打印单个字符值,并期望其对应的参数具有类型 char:

char c = 'A';
printf( "%c\n", c );

%s 用于打印 strings,它们是包含零值终止符的字符值序列,并期望其对应的参数具有类型 char *(指向char的指针),也就是字符串第一个字符的地址

char s[] = "hello"; // equivalent to {'h', 'e', 'l', 'l', 'o', 0}
printf( “%s\n”, s ); // equivalent to passing &s[0]

除非它是 sizeof 或一元 & 运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,表达式 类型 "N-element array of T" 将被转换 ("decay") 为“指向 T 的指针”类型的表达式,表达式的值将是第一个元素的地址数组。所以当我们将 表达式 s 传递给 printf 时,实际传递的是 s[0] 的地址,而不是数组内容本身. 基本等同于写

char s[] = "hello";
char *p = s;
while ( *p != 0 )
  putchar( *p++ ); // print the character p points to, then advance
                   // p to point to the next character in the string

%s%c 不是格式或类型。它们被称为 "conversion or format specifiers",用于关于一种字符类型或字符串的正确格式,由 printf()scanf() 系列的函数使用。因此,他们自己没有"size"或"range"。


Is there any difference in the size and range of these 2 formats?

在 C 语言中,字符串本身不是一种类型。字符串是连续的字符对象序列。

一个字符串的"size"是在源代码中或者程序中确定的运行(variable length arrays);字符串没有一般的固定大小。

字符串与 "range" 不同,它具有字符或整数类型。

你想问的是所有这些字符是否一起(可以)提供更大的范围。答案是否定的。

字符串中的所有字符在内存中都有自己专用的范围和大小,您不能将它们视为一种可以存储和表示更大值的化合物:

char a;      

a 的大小为 1 个字节,范围为 -128 到 127 或 0 到 255(取决于实现和平台,但在大多数现代系统上,它的范围为 -128 到 127 ).

char b[4];

b 在这种情况下有 4 个字节的大小,但它的范围不是从 -2,147,483,648 到 2,147,483,647(2³² = 4,294,967,296 个可存储值(注意符号表示的一位))。它仅由 4 个 char 对象组成,每个对象在内存中分配 1 个字节,并且可以 store/represent 值从 −128 到 127/0 到 255。

如果要为单个字符使用更宽的范围,请使用宽字符类型wchar_t

C 中没有字符串类型,但 C 标准库确实将字符串定义为以 null 结尾的字符数组 §7.1.1p1 of the C11 Draft Standard

A string is a contiguous sequence of characters terminated by and including the first null character.

OP显示的table是正确的,charsigned charunsigned char都是1个字节宽。标准中的类型指定了最小值范围,但没有绝对值范围;虽然 table 中的值范围很常见,但不能保证。特别是,char 是值范围为 0 到 255 的无符号类型并不少见。请注意,对于有符号的 char 类型,标准只需要 -127 到 127 的最小范围。即使是字节也必须具有 最小值 8 位宽度,但未指定恰好 8 位。实际细节是实现细节。

%c%s用于格式化I/O操作;这些与类型没有直接关系,而是用于描述函数期望的类型。对于 fprintf() 系列函数,%c 转换说明符告诉函数需要一个整数参数,该参数将被转换为 unsigned char 值并打印为字符。请注意,字符编码不需要是 ASCII(这是另一个实现细节),但这是当今最常见的。

%s 转换说明符告诉 fprintf() 函数期望指向字符数组第一个元素的指针。如果未指定 suitable 精度(例如 %5s 最多打印 5 个字符),则数组必须是字符串(即以 null 结尾)。

对于 fscanf() 系列函数,%c 指令告诉函数扫描输入中的一个或多个字符(即,在提供字段宽度时扫描多个字符,例如 %3c),并期望指向一个足够大的字符数组来保存结果。对于简单的scanf("%c", &some_char),扫描的最大字符数是1,而some_char只需要是char,例如定义为 char some_char;。但是对于像 scanf("%5c", five_chars) 这样的东西,five_chars 必须是一个能够存储 5 char 的数组,例如定义为 char five_chars[5];.

%s 指令与 fscanf() 函数的操作类似,但没有最大字段宽度规范,这将告诉 fscanf() 尝试匹配和存储字符,直到遇到空格输入。该函数需要一个指向能够保存所有匹配字符(加上空终止符)的字符数组的指针,因此您必须始终指定最大字段宽度以避免潜在的缓冲区溢出。另请注意,%s 指令 always 会导致在扫描最后一个字符后写入 [=38=] 终止符。因此,当存储声明为 char storage[100]; 时,使用 scanf("%99s", storage); 是正确的。这告诉 scanf() 在写入最终 [=38=] 之前匹配输入中的 至多 99 个字符,避免写入超过 storage[] 数组的末尾输入大的情况。

关于 fprintf() and fscanf() 有更多详细信息。请注意,fscanf() 是一个复杂的函数,很难正确使用。