fgetc空终止符

4

我正在进行K&R的练习:

编写一个程序detab,用正确数量的空格替换输入中的制表符以到达下一个制表位。

这是我目前的代码(没有对文件进行错误检查):

#include <stdio.h>
#define tab 2
#define MAX_LENGTH 1000
int main(int argc, char **argv)
{
    FILE *fp = fopen(argv[1], "r+");    
    int c, n;
    char buffer[MAX_LENGTH + 1];
    for (n = 0; n < MAX_LENGTH && (c = fgetc(fp)) != EOF; ++n) {
        if (c == '\t') {
            for (int x = 0; x < tab; ++x)
                buffer[n++] = ' ';
            --n;
        }
        else
            buffer[n] = c;
    }
    //buffer[n] = '\0';
    //rewind(fp);
    //fputs(buffer, fp);
    printf("%s\n", buffer);
    fclose(fp);
    return 0;
}

看起来它可以工作,但我想知道为什么末尾没有需要\0。我只是幸运吗?

4个回答

5

是的,你很幸运。为了避免这个问题,你可以使用fwrite,它不需要空终止符(因为你可以确切地指定要写入的字节数):

fwrite(buffer, 1, n, stdout);

4

您可以告诉printf(...)在给定的字符串中打印(最大)字符数。

printf("%.*s\n", n, buffer);

请查看printf(3),章节"The precision":

一个可选的精度,采用句点('.')后跟一个可选的十进制数字字符串的形式。而不是一个十进制数字字符串,可以写“*”[...]来指定精度在下一个参数[...]中给出,该参数必须为int类型。[...]这给了[...]要从s[...]转换中打印的字符串的最大字符数。

printf ("%.*s\n", 5, "Hello, world!")的实时演示:http://ideone.com/KHKLl


2
您可以使用以下方法初始化您的缓冲区:
memset(buffer, '\0', MAX_LENGTH + 1);

而且您无需担心空终止符。


1
在这种情况下,他不会超出缓冲区 - 检查缓冲区中的位置(n)是否小于MAX_LENGTH。在他的代码中,MAX_LENGTH是最大输出长度,而不是输入。 - Timothy Jones
啊,说得好。不知道为什么我“看到”他在for循环里使用了另一个变量。 - Francisco Soto

1

正如其他答案所指出的那样,你很幸运数组在正确的位置包含了 null。

你可以在创建数组时使用这个简写方式进行初始化:

char buffer[MAX_LENGTH + 1] = { 0 }; // all elements will be zero

请注意,这是因为编译器将使用零初始化未指定的条目 - 因此,如果您说
char buffer[MAX_LENGTH + 1] = { 'a' };

那么数组将会是{'a',0,0,0....}


谢谢你的提示。我从来没有注意到{0}会将所有元素设置为零,因为未指定的条目将被初始化为零。 - mwlow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接