【问题标题】:The size of char datatype in C which is in format of %s or %c?C 中 char 数据类型的大小,格式为 %s 或 %c?
【发布时间】:2020-06-06 15:51:35
【问题描述】:

在网上查到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

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

【问题讨论】:

  • Hoang Louis,请告诉我如何让我的回答对您更有帮助。
  • "我知道有 char (datatype) 的格式 %s" --> 否。"%s" 期望“指向字符类型数组的初始元素的指针”,如 @987654323 @,不是char

标签: c types char sizeof c-strings


【解决方案1】:

char 是单个字符/字母,例如printfed 与 "%c" 和例如'X'.
使用"%s" 打印的内容是一个由许多字符组成的以零结尾的字符串,可以给出例如"foobar"。注意不同的引号。
顺便说一句,处理它们并尝试存储它们时的一个常见错误是没有足够的空间来存放最后的零。通常需要比显而易见的多一个。

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

%s 通常所指的“范围”很难定义。可能是书。

使用%s 打印的内容有时被描述为“C 伪字符串”,但没有这样的数据类型。

【讨论】:

    【解决方案2】:

    C 中的字符串被定义为一个字符数组,其中包含一系列以零字符 '\0' 结尾的字符。

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

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

    转换说明符%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 如果 char 类型的对象的值被视为有符号 在表达式中使用整数时,CHAR_MIN 的值应为 与 SCHAR_MIN 相同且 CHAR_MAX 的值应相同 与 SCHAR_MAX 一样。否则,CHAR_MIN 的值应为 0,并且 CHAR_MAX 的值应与 UCHAR_MAX 的值相同。这 值 UCHAR_MAX 应等于 2CHAR_BIT - 1。

    【讨论】:

      【解决方案3】:

      %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 或一元&amp; 运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,否则表达式 类型为“N- T" 的元素数组将被转换 ("decay") 为 "pointer to T" 类型的表达式,表达式的值将是数组第一个元素的地址。所以当我们传递表达式sprintf,实际上传递的是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
      

      【讨论】:

        【解决方案4】:

        %s%c 不是格式或类型。它们被称为“转换或格式说明符”,用于对printf()scanf() 系列的函数使用的一种字符类型或字符串进行正确格式化。因此,它们本身没有“大小”或“范围”。


        这两种格式的大小和范围有什么区别吗?

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

        字符串的“大小”在源代码中或程序运行时确定(variable length arrays);字符串没有通用的固定大小。

        字符串没有“范围”之类的东西,因为它具有字符或整数类型。

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

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

        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 个字节,并且可以存储/表示从 -128 到 127/0 到 255 的值。

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

        【讨论】:

          【解决方案5】:

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

          字符串是由第一个空字符终止并包括第一个空字符的连续字符序列。

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

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

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

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

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-09-14
            • 1970-01-01
            • 1970-01-01
            • 2012-03-21
            • 2013-05-10
            • 2012-07-19
            • 2013-12-05
            • 1970-01-01
            相关资源
            最近更新 更多