【问题标题】:Is a text's max size include a null(stop) char文本的最大大小是否包含空(停止)字符
【发布时间】:2026-01-03 10:55:01
【问题描述】:

我想定义一个宏来指示记录文本的最大大小。 像这样:

#define RECORD_TEXT_MAX_SIZE 255 /*the max size of the text which get from one record*/

然后像这样使用:

char text[RECORD_TEXT_MAX_SIZE+1];

用户必须定义​​数组大小“RECORD_TEXT_MAX_SIZE+1”以包含空字符。

但我想我可以这样定义

 #define RECORD_TEXT_MAX_SIZE 256 /*the max size of the text which get from one record*/

然后像这样使用:

char text[RECORD_TEXT_MAX_SIZE];

我无法决定使用哪个。

你能给我一个建议吗?

一般规范是什么?

【问题讨论】:

    标签: c text max-size


    【解决方案1】:

    这确实是一个偏好问题,但我的意见是:

    #define RECORD_TEXT_MAX_SIZE   255
    
    char text[RECORD_TEXT_MAX_SIZE + 1];
    

    原因是RECORD_TEXT_MAX_SIZE 仍然指示缓冲区中可以有多少实际字符,同时始终为空终止符留出空间。

    问题或与之相反的论点是,大多数strn... 函数(采用长度参数)包括在限制要写入的字节数时使用空终止符。 p>

    【讨论】:

    • 我也推荐这种风格,除了使用不同的词:size 代表 text 大小,值为 256 或使用 maxlengthlength,值为 255。跨度>
    • @chux,使用不同的词是个好主意。希望其他人知道。
    【解决方案2】:

    正如 Jonathan Reinhart 所指出的,这确实是一个偏好问题,他建议这样做:

    #define RECORD_TEXT_MAX_SIZE   255
    
    char text[RECORD_TEXT_MAX_SIZE + 1];
    

    这当然是一个非常好的习惯,从我的例子中会更清楚。

    然而,这由编译器决定。当到达文本的末尾时,编译器会自动附加空字符,即不需要为此烦恼。无论你在数组的“[]”中放入什么变成文本的大小。以我为此目的编写的程序为例:

    #include<stdio.h>
    #define text_max 10
    int main()
    {
      char txt[text_max+1];
      printf("please enter the text :\n");
      fgets(txt,sizeof txt,stdin);
      for(int i=0;txt[i]!='\0';i++)
      printf("%c",txt[i]);
      return 0;
    }
    

    这个程序输入一个字符序列,编译器会在十个字符后自动附加一个'\0',但是通过像这样声明数组大小增加一个空格不会让阅读程序的人甚至你自己感到困惑最后一个字符去哪里了。你总是知道你必须输入text_max个字符。

    输入:helloworldhi

    OUTPUT:helloworld //这里“hi”被截断,“d”后面输入“\0”,你不需要考虑最后一个字符,因为你声明数组大小为text_max+1。

    为了消除我的疑虑,我编写了另一个这样的程序:

    #include<stdio.h>
    #define text_max 10
    int main()
    {
      char txt[text_max];
      printf("please enter the text :\n");
       fgets(txt,sizeof txt,stdin);
     for(int i=0;txt[i]!='\0';i++)
      printf("%c",txt[i]);
      return 0;
    }
    

    然而,这个程序打印出 9 个字符,截断了一些额外的字符以适应 NULL 终止符:

    输入:helloworldhi

    OUTPUT:helloworl //此处“dhi”被截断,编译器在 9 个字符后输入 '\0'。

    这意味着无论您声明什么,编译器都会在文本末尾为“\0”字符腾出空间,但您可以看到这样声明是一个更好的习惯:

     #define RECORD_TEXT_MAX_SIZE   255
    
        char text[RECORD_TEXT_MAX_SIZE + 1];
    

    注意:编译器在 windows 上是 gcc。

    【讨论】:

    • 对于大于sizeof(txt)-1 的输入,您的示例会遇到未定义行为,因为scanf() 写入超出txt 的末尾。 scanf()(以你使用它的方式)不知道txt 有多大。 Valgrind 可以向你证明这一点。
    • 首先scanf()不写它读,至于scanf()的使用我特意用它来说明无论我们输入多大的文本编译器都会附加一个' \0' 在文本大小限制之后(如果文本较大)和文本末尾(如果文本较小)。我对否决票感到非常震惊。我没有使用调试器,但对于较大的文本它工作得很好,编译器没有显示错误
    • 第一个 scanf() 从文件中读取并将其写入内存位置。第二:“...无论我们输入多大的文本,编译器都会在文本大小的限制之后附加一个'\0'...”这在以下方式中是完全错误的:如果您将 100 个字节传递给 scanf()(如您的示例中的编码),它会读取 100 个字节,并将 100 个字节写入内存,即使提供的缓冲区要小得多。是的,第 101 个字节将是 '\0'。但是写入缓冲区的末尾会引发 UB。
    • 那为什么编译器不显示错误,如果有任何UB它应该在执行printf时正确显示,但它却准确显示了缓冲区大小的文本。
    • 因为这是 C。编译器假定程序员已经处理了足够大的缓冲区。要使scanf() 在一定数量的字符后停止读入缓冲区,请执行以下操作:char txt[10 + 1]; scanf("%10s", txt) 最多读取 10 个字符并确保编译器仍有空间添加'\0'。 UB 不需要让程序结束,UB 简单地可能导致任何事情发生