Почему этот код с fork() генерирует ошибку во время выполнения в ejudge?

#c #scanf #fork

Вопрос:

Почему этот код может генерироваться Runtime Error в ejudge? Эта программа подсчитывает количество stdin введенных слов. Слова могут быть разделены любым количеством ' ' и 'n' . Похоже fork() , это может вызвать проблему, но я не уверен, почему я не получаю ту же ошибку на своем компьютере.

ejudge использует gcc — простой C, 64-разрядный, используя -std=c11 или -std=gnu11

Задача:

В стандартном входном потоке задается текстовая строка, состоящая из слов (последовательность символов, не являющихся пробелами), между которыми может быть любое количество пробелов, включая строки.

Вам нужно рассчитать количество слов, если вы знаете, что их не более 255, и вывести это значение в стандартный поток вывода.

Используйте создание новых процессов, чтобы каждый процесс считывал не более одного слова, например, используя scanf(«%s»,…).

Вы можете вывести результат только из процесса, который был запущен первым (т. Е. из исходной программы).

Полученная программа должна вернуться с кодом возврата 0.

Размер каждого слова не превышает 4096 байт.

Мой код:

 #include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

#define DBG(args...) fprintf(stderr, args)
//#define DBG(args...)

int main(int argc, char* argv[])
{
    int status;
    pid_t pid;
    pid_t first_child;

    for (int i = 0; i < 256;   i) {
        pid = fork();

        if (pid == 0) { // child continue reading
            char str[4097];
            if (scanf("%s", str) != EOF)
                continue;
            exit(1);
        } else {
            if (i == 1) {
                first_child = pid;
            }
            if (wait(amp;status) == first_child) {
                break;
            } else {
                exit(WEXITSTATUS(status)   1);
            }
        }
    }

    fprintf(stdout, "%in", WEXITSTATUS(status));
    fflush(stdout);
    fclose(stdout);

    return 0;
}
 

Комментарии:

1. Почему вы закрываетесь вручную stdout ? Это может привести к ошибке в некоторых системах, когда ваша программа завершает работу и пытается закрыть ее снова. Кроме того, можете ли вы предоставить более подробную информацию об ошибке, которую вы получаете?

2. Кроме того, обратите внимание, что stdin может не получиться EOF даже после того, как закончатся фактические входные данные, это опять же зависит от среды.

3. Статус выхода ограничен 255. Это не сработает, если длина файла превышает 255 строк.

4. Это решение не будет работать, потому что stdio использует буферизацию ввода. scanf() может буферизировать больше входных данных, чем возвращаемое слово, и следующий дочерний процесс не начнет чтение с того места, на котором он остановился.

5. Я думаю if (i == 1) , так и должно быть if (i == 0) .

Ответ №1:

Переписал алгоритм, и он сработал! В первой версии было сделано много ненужных вилок. Например, если предполагалось 6, то создавалось 12.

 #include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

// #define DBG(args...) fprintf(stderr, args)
#define DBG(args...)

int main(int argc, char* argv[])
{
    int status;
    pid_t first_pid;
    pid_t pid = fork();

    if (pid != 0) {
        wait(amp;status);
        printf("%in", WEXITSTATUS(status));
        return 0;
    }

    for (int i = 0; i < 256;   i) {
        char str[4097];
        if (scanf("%s", str) == EOF) {
            DBG("PID %in", pid);
            exit(0);
        }
        pid = fork();
        if (pid != 0)
            break;
    }

    DBG("PID %i waitingn", pid);
    wait(amp;status);
    exit(WEXITSTATUS(status)   1);
}