Почему мой код не читает правильные целые числа из файла? - PullRequest
0 голосов
/ 04 января 2019

Итак, немного поиграв с ответом Крейга Эстей, мне удалось получить следующий фрагмент кода:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 


int main(int argc,char **argv){
    char *filename = argv[1];
    if(filename == NULL) {
        printf("Please specify a filename.\n");
        exit(1);
    }
    FILE *fi = fopen(filename,"r");
    printf("Finding size...\n");
    int size = 0;
    while(fscanf(fi,"%*d") != -1) size++;
    rewind(fi);
    int numbers[size];
    while(fscanf(fi,"%d",&numbers[size]) != 1);
    fclose(fi);
    printf("Size of array: %d\n\n", size);
    int idx=0,idx2=1,idx3=1,idx4=1;
    printf("Elements: \n");
    while (idx < size){
        printf("%d\n",numbers[idx]);
        idx++;
    }
    int maximum = numbers[0];
    while (idx2 < size){
            if (numbers[idx2] > maximum){
                maximum  = numbers[idx2];
        }
        idx2++;
    }
    printf("\nMax: %d\n",maximum);
    int minimum = numbers[0];
    while (idx3 < size){
            if (numbers[idx3] < minimum){
                minimum  = numbers[idx3];
        }
        idx3++;
    }
    printf("Min: %d\n",minimum);
    int sum = numbers[0];
    while (idx4 < size){
        sum = sum + numbers[idx4];
        idx4++;
    }
    printf("Total: %d\n",sum);
}

Проблема в том, что теперь он выполняется без остановки, но все равно не дает праваответ.Мой файл 'abcd.txt' содержит следующие числа:

5564

4324

863

98743

Однако мой результатпосле выполнения reader.c это:

./reader abcd.txt
Finding size...
Size of array: 4

Elements: 
0
0
1384783917
32713

Max: 1384783917
Min: 0
Total: 1384816630

Почему это сейчас?Я не могу найти почему это отличается от ответа ниже.Если я выполню точный код в ответе, он вернет верный ответ.Заранее спасибо.

1 Ответ

0 голосов
/ 04 января 2019

Это предварено моими главными комментариями.

Вы не можете сделать: printf(numbers[idx2]); (то есть первый аргумент должен быть строкой формата).Итак, сделайте: printf("%d\n",numbers[idx2]);

Выполнение sizeof(numbers) / sizeof(int) делает не точного подсчета числа фактически заполнено. Это дает максимум , в конце которого будут значения мусора.

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

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

long int
findSize(char *filename)
{
    FILE *fp = fopen(filename, "r");

    if (fp == NULL) {
        printf("findSize: unable to open file '%s' -- %s\n",
            filename,strerror(errno));
        exit(1);
    }

    fseek(fp, 0L, SEEK_END);
    long int res = ftell(fp);

    fclose(fp);
    return res;
}

int
main(int argc, char **argv)
{

    char *filename = argv[1];
    if (filename == NULL) {
        printf("please specify a filename\n");
        exit(1);
    }

    printf("findSize\n");
    int numbers[findSize(filename)];

    printf("scanf\n");
    FILE *fi = fopen(filename,"r");
    int size = 0;
    while (1) {
        if (fscanf(fi,"%d",&numbers[size]) != 1)
            break;
        printf("scanf: %d\n",numbers[size]);
        ++size;
    }
    fclose(fi);

    printf("size: %d\n",size);
    for (int idx2 = 0;  idx2 < size;  ++idx2)
        printf("%d\n",numbers[idx2]);

    int maximum = numbers[0];
    for (int idx3 = 1;  idx3 < size;  ++idx3) {
        if (numbers[idx3] > maximum)
            maximum = numbers[idx3];
    }
    printf("Max: %d\n", maximum);

    int minimum = numbers[0];
    for (int idx4 = 1;  idx4 < size;  ++idx4) {
        if (numbers[idx4] < minimum)
            minimum = numbers[idx4];
    }
    printf("Min: %d\n", minimum);

    int sum = 0;
    for (int idx5 = 0;  idx5 < size;  ++idx5)
        sum = sum + numbers[idx5];
    printf("Total: %d\n", sum);

    return 0;
}

ОБНОВЛЕНИЕ:

Прежде всегоСпасибо большое за вашу работу.Глядя на ваш код (я больше не могу называть его моим кодом, поскольку он совершенно другой)

Да, он был задуман как руководство для вас, чтобы написать / переписать свой собственный код, что вы и сделали.

Я вижу, что функция findSize в основном не имеет значения.

Это технически правильно, но выделит [намного] больше места, чем необходимо.

Я пытался поместить другой fscanf вместо вызова функции findSize, но я не знаю, как эта функция работает точно.

Хорошо для вас при выяснении этого альтернативного алгоритма определения размера.

Посмотрим, получу ли я его: если есть третий аргумент, он сохраняет каждый элемент чтения в третьем аргументе (который должен быть переменной).Но если третьего элемента нет и вы вводите * во второй аргумент, он нигде не хранит прочитанные элементы.Я прав?

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

Кроме того, мы могли бы просто ввести дополнительную скалярную переменную int и сделать:

int size = 0;
while (1) {
    int val;
    if (fscanf(fi,"%d",&val) != 1)
        break;
    ++size;
}

Тем не менее, вы на самом деле второй цикл fscanf, который используется для чтения чисел, будет не работать:

while (fscanf(fi, "%d", &numbers[size]) != 1);

Это ставит все числа в одинаковом индексе, а именно size, что на один после конца массива numbers, так что это неопределенное поведение.

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

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

int idx0 = 0;
while (fscanf(fi, "%d", &numbers[idx0]) == 1)
    ++idx0;

После этого изменения весь ваш обновленный код [min / max / sum] работает нормально.


Некоторые примечания постиль:

Как вы заметили, мой исходный код был немного другим (например, замена циклов while на цикл fors).

Но одна вещь, которую я не сделал , это повторное использование индексной переменной.То есть нет необходимости иметь отдельные для каждого цикла.Все они могут быть изменены на одну переменную idx.

Использование разных символов не является неправильным, и может добавить ясности.Но idx, idx1, idx2 не так описательны, как могли бы.

Если вы хотите сохранить отдельные переменные, я бы предложил более описательные имена, такие как: inpidx, minidx, maxidx и sumidx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...