Конечное условие для факторинга

Добрый вечер,

У меня проблемы с назначением.

По сути, мы должны кодировать программу, которая будет вычислять основные факторы данного stdin, Данные могут войти в программу только через stdinбудь то через echo или < file.txt, Поток данных никогда не будет длиннее 80 символов (они могут быть числами или нет).

Функции, которые я использую в программе: read(), strotol() а также strtok()и "нерелевантный" код выглядит следующим образом:

  1. Пользы malloc выделить 80 начальных байтов памяти.
  2. Магазины в int, через read() количество прочитанных символов (и я считаю, последний \0).
  3. перераспределяет память с realloc() чтобы сохранить как можно больше памяти (я знаю, что в этом случае это тривиально, ну да ладно...).

Теперь немного сложнее:

  1. Поскольку данные должны быть разделены пробелами, максимальное количество проверяемых элементов не должно превышать: (n/2)+1, где n количество прочитанных символов в верхней точке nº 2.
  2. Создает массив long с максимальным размером число, полученное в точке № 1.
  3. заливка numbers[0] с результатом: strtol(strtok(line, delim), &end, 10),
  4. Добавляет 1 к counter и входит в while цикл:

    while((numbers[counter] = strtol(strtok(NULL, delim), &end, 10)) != NULL) {
        if(!*end) {
            // Check whether it's 0, 1, negative, prime or extract its factors
        }
        else {
            fprintf(stderr, "\"%s\" is not a non-negative integer", end)
        }
        counter++;
    }
    

Теперь вот некоторые входы и их выходы:

Входные данные: echo 1 2 3 4 5 6 7 8 9 10 | ./factors

Выход:

1
2    
3
    2    2
5
    2    3
7 
    2    2    2
    3    3
    2    5
Segmentation Fault (core dumped). 

вход ./factors < integers.txtГде целые числа содержат КОЛОННУ целых чисел.

Выход:

Все целые числа просто хорошо разлагаются и в конце выводит:

Segmentation Fault (core dumped). 

Входные данные: echo abc 12 13 14 15 | ./factors

Выход:

"abc" is not a non-negative integer
13
    2    7
    3    5
Segmentation Fault (core dumped). 

Входные данные: echo -1 -2 -3 -4 -5 | ./factors

Выход:

"-1" is not a non-negative integer
"-2" is not a non-negative integer
"-3" is not a non-negative integer
"-4" is not a non-negative integer
"-5" is not a non-negative integer

Входные данные: echo abc abc abc | ./factors

Выход:

"abc" is not a non-negative integer

(И не продолжает проверку).

Входные данные: echo 3 4 0 6 7 | ./factors

Выход:

3
    2    2

(И не продолжает проверку).

Так что, насколько я вижу, он терпит неудачу, когда сталкивается с 0более одного экземпляраinteger или в основном в конце здорового integerпоток данных.

Любая идея, как я мог бы заняться этим в то время и почему это терпит неудачу так очевидно случайно?

Я должен сообщить вам, что я новичок в C...

Большое спасибо в продвинутом.

================================================== ==

EDIT1: согласно запросу, вот фрагменты кода, которые генерируют numbers[]и читать из stdin:

char *line;
char *end;
char *delim = " \n";
int charsread, counter; 

line = malloc(80);
charsread = read(0, line, 81);
if (charsread == 0) {
    return EX_OK;
}
realloc(line, charsread);
maxelem = (charsread / 2) + 1;
long numbers[maxelem];
numbers[0] = strtol(strtok(line, delim), &end, 10);
if (!*end) {
    zeroone(numbers[0]);
}
else {
    fprintf(stderr, "\"%s\" is not a non-negative integer\n", end);
}
counter = 1;
while [...]

3 ответа

Решение

Большое спасибо за ваш проницательный ответ.

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

long number;
item = strtok(line, delim);
while (item != NULL) {
       number = strtol(item, &rest, 10);
       if (*rest == 0) {
           zeroOne(number);
       }
       else {
           fprintf(stderr, "\"%s\": not a non-negative int.\n", item);
       }
       item = strtok(NULL, delim);
}   

Кажется, более чистый подход и учитывает тот факт, что возвращаемое значение из strtok, когда оно NULL возвращается, прежде чем он пытается войти в while петля у меня была раньше. Затем, сегодня утром я вернулся сюда и прочитал ваш ответ:)

Последующий вопрос относительно вашего жестко запрограммированного \0 в строке читать: это означает, что мой последний strtok на самом деле выводит \0 токен и пытается войти в цикл, или он возвращает NULL когда он достигает сущности сразу после моего последнего введенного персонажа? Как правило, при использовании read() (или, возможно, другие функции чтения, такие как fgets() я должен всегда пытаться жестко закодировать \0 в строке, чтобы другие функции могли проверить EOL / EOF?

Если у кого-то еще возникают проблемы при использовании любой из этих функций (strtok а также strtol) Я рекомендую проверить эти два вопроса, размещенные на этом сайте:

относительно strtol второй аргумент: второй аргумент

относительно strtok Выходные данные: невозможно объединить выходную переменную strtok. strcat и strtok

Попробуйте использовать gdb для отладки segfault, сделайте дамп ядра при segfaulting, установив соответствующую переменную среды, или запустите его непосредственно в gdb. Segfault означает, что вы читаете / записываете часть памяти, которую вы не должны. Случайность означает, что вы, вероятно, разбиваете стек или что-то в этом роде. Я думаю, что виноваты "printf", проверь их аргументы. Вы также не проверяете, что числа меньше длины массива? это может заполонить это?

Хорошо, давайте рассмотрим несколько вещей, пока мы там, и посмотрим, сможем ли мы решить ваши проблемы.


Это не обязательно в вашей программе:

realloc(line, charsread);

Правильно пытаться уменьшить объем памяти, но если вы выделили слишком много, ну и что? Это 80 байтов. Не переусердствуйте, у вас уже достаточно на тарелке.


Это странно

maxelem = (charsread / 2) + 1;
long numbers[maxelem];

Это нормально и будет работать в вашем случае, но вы можете определить количество элементов более точно, посчитав группы чисел.


Я бы порекомендовал попробовать сделать всю добычу как в lopp


Относительно фактического segmentation fault... Я могу ошибаться, так как у меня нет возможности воспроизвести это на моей машине здесь, но я думаю, что ошибка возникает из-за того, что вы не прервали свою line с \0 персонаж. В C, как я уверен, вы уже знаете по просмотру фрагментов, которые вы разместили, строки обычно являются тем, что мы называем "NULL-terminated", поэтому по соглашению мы заканчиваем их значением 0, которое является числовым значением для NUL персонаж, также представлен как \0 (что иногда немного сбивает с толку, так как тогда люди путаются между "NULL-terminated", "NUL" char и "NULL pointers", что другое).

Это затем прерывает вашу программу, потому что в конце концов ваша программа пытается прочитать конец строки с помощью strtok но он не знает, где остановиться. Он не имеет представления о длине буфера и о том, где остановиться в этом буфере. Таким образом, он продолжает читать, достигая адреса памяти, к которому он не имеет доступа, и поэтому segmentation fault,

Итак, вы хотите просто:

/*
** If you keep your realloc, you need to allocate for the number of read
** characters from stdin, and for an extra char to terminate.
*/
line = realloc(line, charsread + 1); 
/*
** Terminate the string.
*/
line[charsread] = '\0';

Обновление: Ах, вы были на самом деле почти там, у вас была логика, но, вероятно, просто пропустили этот бит... Вы даже написали это сами:

Хранит в int через read() количество прочитанных символов (и, я полагаю, последний \0).

Что отчасти верно. Если вы действительно получили линию из 80 символов, ваш read вызов вернул бы строку с \0 в конце. Но в большинстве случаев у вас их меньше, поэтому в вашем буфере чтения читаются только видимые символы, и вам нужно завершить строку нулем самостоятельно.


Я также попытался бы переписать ваш цикл обработки, чтобы сделать первый начальный вызов strtok как часть его. Не всегда удобно писать, но обычно вид блока, почти идентичного тому, что находится внутри цикла непосредственно перед или сразу после цикла, заставляет меня думать, что есть лучший логический подход.

Другие вопросы по тегам