нулевой терминатор fgetc

Я делаю упражнение в 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 не понадобилось в конце. Мне просто повезло?


person mwlow    schedule 05.01.2012    source источник


Ответы (4)


Да, вам повезло. Чтобы избежать этой проблемы, вы могли бы использовать fwrite, который не требует нулевого терминатора (поскольку вы точно указываете, сколько байтов нужно записать):

fwrite(buffer, 1, n, stdout);
person Greg Hewgill    schedule 05.01.2012

Вы можете указать printf(...) (максимум ) количество символов для печати для данной строки.

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

См. printf(3), раздел «Точность»:

Необязательная точность в виде точки ('.'), за которой следует необязательная строка десятичных цифр. Вместо строки десятичных цифр можно написать "*" [...], чтобы указать, что точность задается в следующем аргументе [...], который должен иметь тип int. [...] Это дает [...] максимальное количество символов, которые будут напечатаны из строки для s преобразований.

Живая демонстрация printf ("%.*s\n", 5, "Hello, world!"): http://ideone.com/KHKLl.

person kay    schedule 05.01.2012

Вы можете инициализировать свой буфер с помощью:

memset(buffer, '\0', MAX_LENGTH + 1);

И вам не придется беспокоиться о нулевом завершении.

person Francisco Soto    schedule 05.01.2012
comment
В этом случае он не будет переполнять буфер - проверяется, что позиция в буфере (n) меньше MAX_LENGTH. В его коде MAX_LENGTH — это максимальная длина вывода, а не ввода. - person Timothy Jones; 05.01.2012
comment
Хорошо, по какой-то причине я увидел, что он использует другую переменную в for. - person Francisco Soto; 05.01.2012

Как указывали другие ответы, вам повезло, что массив содержал нули в нужных местах.

Вы можете инициализировать его при создании, используя это сокращение:

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

Обратите внимание, что это связано с тем, что компилятор будет инициализировать неуказанные записи нулями, поэтому, если вы сказали

char buffer[MAX_LENGTH + 1] = { 'a' };

тогда массив будет {'a',0,0,0....}

person Timothy Jones    schedule 05.01.2012
comment
Спасибо за совет. Я никогда не замечал, что {0} устанавливает все элементы равными нулю только потому, что неуказанные записи будут инициализированы нулями. - person mwlow; 05.01.2012