C fgets (), как определить, больше ли строка указанного размера - PullRequest
4 голосов
/ 24 апреля 2019

Я использую fgets() для чтения строк из popen("ps -ev", "r"), и я не могу узнать, как узнать, читает ли fgets() строку частично или полностью, а если частично, как читать / выбрасывать лишнее.

При чтении каждой строки из popen() я читаю первые 1024 символа и получаю от них нужную информацию, которая прекрасно работает. Проблема возникает, когда строки длиннее 1024 символов, а затем следующая прочитанная мной строка является продолжением предыдущей строки, которая находится не в нужном мне формате (это значение каждого столбца в начале каждой строки). Если я могу знать, что я только частично читаю строку (то есть строка содержит 1024 или более символов, я хочу читать и выбрасывать каждые 1024 символа, пока она не достигнет конца. По окончании я могу снова вызвать fgets() и на этот раз он будет читать с начала следующей строки, а не с продолжения предыдущей строки.

Я знаю, что fgets() читает до тех пор, пока не найдет новую строку или не достигнет указанного предела, а затем продолжит чтение оставшейся части строки. Я попытался проверить, что последний символ равен «\ 0», а второй последний символ в строке - «\ n», но это не работает. Я опубликую этот код ниже на случай, если это поможет.

Если вы запустите код, вы увидите LINE: num S num:num.num ... (где num - число), с которого должна начинаться каждая строка. Вместо этого некоторые строки будут выглядеть примерно так: LINE: AAAAAAQAAABMAAAAQAAAAAAAAAAMAAAAFAAAAEAAAAAAAAAADAAAACwAAABA.... Это строки, которые являются избыточными по сравнению с предыдущей строкой, и именно они вызывают проблемы, поскольку они имеют неправильный формат.

Любая помощь высоко ценится.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#define NEWLINE() printf("\n");
#define DIVIDER() printf("============================================================================\n");
#define PL(l) printf("LINE: %s\n", l);

int const MAX_PROCESSES = 20;
int const BUFFER_SIZE = 1024;

int exhaustedLine(char* line) {
    if (line[sizeof line - 1] == '\0' && line[sizeof line - 2] != '\n') {
        printf("n:%c 0:%c\n", line[sizeof line - 2], line[sizeof line - 1]);
        NEWLINE();
        return -1;
    }
    return 0;   
}

int main(int argc, char const *argv[]) {
    FILE* fp = popen("ps -ev", "r");
    char buf[BUFFER_SIZE];
    char* line = (char*)1;

    while (line) {
        DIVIDER();
        line = fgets(buf, BUFFER_SIZE, fp);
        PL(line);
        if (exhaustedLine(line) != 0) {
            printf("END OF LINE\n");
        }
    }

    return 0;
}

Ответы [ 2 ]

3 голосов
/ 24 апреля 2019

У вас правильная идея: если полная строка была прочитана, буфер содержит новую строку.В противном случае строка либо длиннее буфера, либо мы находимся в конце файла, а последняя строка не определена.

Основная проблема с вашей реализацией - char* line ... sizeof line.sizeof возвращает размер типа выражения его операнда, поэтому sizeof line означает sizeof (char *), то есть размер указателя, а не размер массива, на который указывает line.

Кроме того, если была прочитана более короткая строка, line[SIZE - 1] получит доступ к неинициализированной памяти.

Самое простое решение:

int is_full_line(const char *line) {
    return strchr(line, '\n') != NULL;
}

Просто используйте strchr, чтобы найти строку '\n'.

Чтобы отбросить оставшуюся часть слишком длинной линии, у вас есть несколько вариантов:

  • Вы можете снова вызвать fgets в цикле.
  • Вы можете вызватьfgetc в цикле: int c; while ((c = fgetc(fp)) != EOF && c != '\n') {}
  • Вы можете использовать fscanf: fscanf(fp, "%*[^\n]"); fscanf(fp, "%*1[\n]");

Относительно

int const BUFFER_SIZE = 1024;

Обратите внимание, чтоconst не объявляет константы в C;он объявляет переменные только для чтения.char buf[BUFFER_SIZE] считается массивом переменной длины, потому что размер не является константой.

Чтобы получить истинную целочисленную константу в C, вам нужно использовать enum вместо:

enum { BUFFER_SIZE = 1024 };
2 голосов
/ 24 апреля 2019

Ваша проблема в этом бите:

line[sizeof line - 1]

line в этом случае char*, поэтому sizeof line соответствует размеру указателя , а не размеру строки. Вам нужно сделать что-то вроде этого:

size_t len = strlen(line);
if (len && '\n' == line[len - 1]) ...

Вам не нужно проверять это line[len] == '\0'; это верно для всех строк. (Заметьте, что не для всех символьных массивов, но любая стандартная библиотечная функция, которая возвращает строку, вернет массив с нулевым символом в конце.)

...