为什么我的代码无法从文件中读取正确的整数?

时间:2019-01-03 22:41:52

标签: c

所以在听了克雷格·埃斯蒂的回答后,我设法得到了以下代码:

#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 :(得分:-1)

这是我的主要评论开头。

您不能执行: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函数,但我不知道此函数的工作原理。

对您确定此替代大小调整算法很有帮助。

  

让我看看我是否明白:如果有第三个参数,它将每个read元素存储到第三个参数(应该是变量)中。但是,如果没有第三个元素,并且在第二个参数中添加了*,则它不会将读取的元素存储在任何位置。我说的对吗?

信不信由你,我不会过多地使用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,它是{{ 1}}数组,所以这是未定义的行为。

此外,循环条件与其应有的条件相反,因此仅填写一个数字。

要解决此问题,我们需要一个附加的索引变量,并且需要更改numbers循环的含义:

while

更改后,其余更新的代码[min / max / sum]可以正常工作。


关于样式的一些注释:

您注意到,原始发布的代码有些不同(例如,将int idx0 = 0; while (fscanf(fi, "%d", &numbers[idx0]) == 1) ++idx0; 循环替换为while循环)。

但是,我没有做的一件事是重用了index变量。也就是说,每个循环都不需要有单独的循环。它们都可以更改为单个for变量。

使用不同的符号并没有错,并且可以更加清晰。但是,idxidxidx1的描述性不够。

如果您想保留单独的变量,我建议使用更具描述性的名称,例如:idx2inpidxminidxmaxidx