Функция неправильно увеличивает переменную на 1

У меня есть функция, которая возвращает количество строк, символов и слов в массиве. По какой-то причине, когда я перебираю массив для печати значений, я получаю только правильное значение для строк, символы и слова возвращаются как 0. Все функции предопределены моим профессором, и моя работа состоит в том, чтобы заполнить их.

int main(int argc, char **argv)
{
        int *myArray = get_counts(argv[1]);
        for (int i = 0; i < 3; i++)
        {
                printf("%d\n", myArray[i]);
        }
        return 0;
}
int *get_counts(char *filename)
{
        FILE *file;

        file = fopen(filename, "r");

        if (file == NULL)
        {
                printf("NULL FILE");
        }

        char c;
        int h;
        bool whitespace = true;
        static int arr[3] = {0,0,0};

        do
        {
                c = fgetc(file);
                if (c == '\n')
                {
                        arr[0] ++;
                }
        }while (c != EOF);

        while (true)
        {
                h = fgetc(file);

                if (feof(file))
                {
                        break;
                }
                else if (ferror(file))
                {
                        printf("error reading file");
                }
                arr[2] ++;

                if (whitespace && !isspace(h))
                {
                        arr[1] ++;
                        whitespace = false;
                }
                else if (!whitespace &&isspace(h))
                {
                        whitespace = true;
                }
        }
        fclose(file);
        return arr;
}

Используйте отладчик, чтобы пройтись по коду, чтобы выяснить, где находится ваша логическая ошибка и что происходит не так. Если вы не знаете, как пользоваться отладчиком, самое время начать учиться. Отладчик — это самый мощный инструмент, доступный программисту, и никогда не рано начать его использовать.

Ken White 11.10.2022 00:54

@Jason Fan После первого цикла do-while возникает условие EOF.

Vlad from Moscow 11.10.2022 00:54

Вам нужно сделать что-то другое, кроме как продолжать как обычно, если fopen не работает.

Allan Wind 11.10.2022 00:58

Использование переменной char (например, c) для хранения возвращаемого значения fgetc опасно, поскольку она не может содержать все возможные возвращаемые значения (EOF (-1) или 0..255). В лучшем случае, если ваш файл содержит символ 0xff, он будет рассматриваться как преждевременный EOF. В худшем случае (в системе, где char не имеет знака) он никогда не завершится.

Chris Dodd 11.10.2022 18:55
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

После первого цикла do-while возникает условие EOF.

    do
    {
            c = fgetc(file);
            if (c == '\n')
            {
                    arr[0] ++;
            }
    }while (c != EOF);

Таким образом, следующий цикл while не имеет никакого эффекта.

Вы должны использовать только один цикл для подсчета строк, слов и символов.

Обратите внимание, что переменная c должна быть объявлена ​​как имеющая тип int

int c;

Также необходимо выйти из функции, если файл не был открыт.

Ответ принят как подходящий

Лучший вариант, вероятно, — просто перебрать файл в одном цикле (вы также можете rewind() после первого цикла). Используйте возвращаемое значение fgetc(), чтобы определить, находитесь ли вы в EOF вместо отдельных вызовов feof(). Я также сделал массив результатов аргументом (out) вместо использования статической переменной (последняя не является реентерабельной, если вы когда-нибудь захотите вызывать это из нескольких потоков, и это легко сделать):

#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

void get_counts(char *filename, int arr[3]) {
    memset(arr, 0, 3 * sizeof(int));
    FILE *file = fopen(filename, "r");
    if (file == NULL) {
        printf("NULL FILE");
        return;
    }
    bool whitespace = true;
    for(;;) {
        int c = fgetc(file);
        if (c == EOF)
            break;
        else if (c == '\n')
            arr[0]++;
        else if (whitespace && !isspace(c)) {
            arr[1]++;
            whitespace = false;
        } else if (!whitespace && isspace(c))
            whitespace = true;
        arr[2]++;
    }
    fclose(file);
}

int main(int argc, char **argv) {
    int myArray[3];
    get_counts(argv[1], myArray);
    for (int i = 0; i < 3; i++) {
        printf("%d\n", myArray[i]);
    }
}

Вывод в указанном выше файле:

39
94
715

Количество слов 94 не согласуется с wc -w, но вы можете использовать другое определение того, что такое слово.

Рекомендуется разделить вычисления и ввод-вывод, поэтому рассмотрите возможность открытия и закрытия файла в main() и передачи дескриптора файла. Например, становится проще использовать дескриптор файла stdin, если вы не хотите использовать физический файл.

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

Почему в С++ (и в большинстве других языков) есть циклы for и while?/Что можно сделать с одним типом, чего нельзя сделать с другим?
Мне трудно преобразовать эту логику do while в цикл while. Какая логика скрыть это?
Как интерпретировать конъюнкцию как условие цикла?
Как закрыть этот файл, чтобы переименовать и удалить файл ("Поток закрыт")
Мне нужно разъяснение условного оператора цикла Java while при попытке найти самый длинный общий префикс из массива строк
Как заставить цикл while продолжать цикл, если определенные параметры не выполняются?
В цикле while, как вы храните данные, чтобы, когда цикл заканчивается, он выводил все введенные данные, а не просто сбрасывал в следующем цикле while
Почему замена содержимого файла в ArrayList возвращает нежелательные результаты?
Как сделать повторяющийся список списков с помощью цикла while
C - В то время как циклы один раз после проверки условия?