C在缓冲区中创建额外的字节

时间:2018-07-14 19:44:59

标签: c

我今天一直在搞弄C,当我注释掉这段代码中的第三个缓冲区时,我不理解输出的差异:

 #include <unistd.h>
 #include <string.h>
 #include <stdio.h>
 void main() {
     unsigned char letters[10];
    memset(letters, 0x00, 10);
    memset(letters, 0x41, 10);
    printf(letters);
    printf(" Total buffer len: %d bytes\n",strlen(letters));

     char nletters[10];
    memset(nletters, 0x00, 10);
    memset(nletters, 0x42, 10);
     printf(nletters);
    printf(" Total buffer len: %d bytes\n",strlen(nletters));

     int nums[10];
     memset(nums, 0x00, 10);
    memset(nums, 0x43, 10);
    printf(nums);
    printf(" Total buffer len: %d bytes\n",strlen(nums));   
 return 0;
}

区别在于删除了nums缓冲区周围的注释:

AAAAAAAAAA�7ǝ�U Total buffer len: 16 bytes
BBBBBBBBBBAAAAAAAAAA�7ǝ�U Total buffer len: 26 bytes

并保留缓冲区:

AAAAAAAAAA Total buffer len: 10 bytes
BBBBBBBBBBAAAAAAAAAA Total buffer len: 20 bytes
CCCCCCCCCC��U Total buffer len: 14 bytes

我没有得到的是:

  1. 注释掉第三个缓冲区如何影响其他缓冲区的大小?

  2. 缓冲区末尾的额外字节是什么?如何丢失/管理它们(如果我选择串联缓冲区)?

  3. 当我选择是否对第三个缓冲区进行注释时,为什么打印缓冲区大小和初始化大小的差异不一致?

  4. 缓冲区2应该是10个字节,为什么是20个字节?我不希望它是20,我只要求10。我不认为这是不合理的。

2 个答案:

答案 0 :(得分:3)

C语言中的

char字符串实际上称为 空终止 字节字符串以null结尾的位很重要,所有字符串函数都希望它知道字符串何时结束。

如果将未终止的字符串传递给字符串函数,它将超出范围,从而导致undefined behavior

终止符等于零,可以是整数0或字符'\0'

当然,这个空终止符需要在字符串中保留空格。这意味着10个字符的字符串必须有11个空格才能适合终止符。

简单的第一个看起来像

char letters[11] = { 0 };  // Space for ten character plus terminator
// The above definition also initializes all elements in the array to zero,
// which is the terminator character

memset(letters, 'A', 10);  // Set the ten first characters to the letter 'A'

printf("%s", letters);  // Never print a data string directly using printf's first parameter.

printf(" Total buffer len: %d bytes\n", strlen(letters));

请注意对printf的更改。这是因为,如果您从用户那里获得了字符串输入,则将其作为格式字符串直接传递到printf是一个非常糟糕的安全漏洞。如果字符串包含格式设置代码,但没有参数,则将导致未定义的行为

还要注意,我将magic number 0x41更改为它对应的ASCII字符。幻数是一个坏习惯,使代码更难于阅读,理解和维护。

答案 1 :(得分:0)

尝试一下:

memset(letters, 0x00, 10);
memset(letters, 0x41, 9);   /* <--- see the array size minus one there */

这将使printf(3)正常工作,但仅打印九个A的列表。如其他答复所述,这与C程序员将手工构建的终止字符串为null的噩梦有关。因此,使用<string.h>函数更为常见。

在另一个地方,不建议使用printf()的第一个参数而不包含字符串文字,例如,在您的字符串具有%字符的情况下,该字符将被解释为格式描述符,并且您会再次遇到更多不确定的行为。