Yotam Kasznik
Yotam Kasznik

Reputation: 55

Code in C to find largest and smallest numbers from text file

I am attempting to write a program that takes a user's inputted text file and returns the largest number, smallest number, average of the numbers and the standard deviation of the numbers. The text file that we input is formatted as such (with the first number being "N", or the total number of numbers, and the second row the list of all the numbers):

5

4.34 23.4 18.92 -78.3 17.9

So far, this is my code

int main(int argc, char*argv[])
{
    double average, num = 0, min = 0, max = 0, sum = 0, N, std_dev, sum_sqs;
    FILE * pFile;
    pFile = fopen("argv[1]", "r");
    fscanf(pFile, "%lf", &N);

    while(!feof(pFile))
    {
            fscanf(pFile, "%d", &num);
            if (num < min)
                    min = num;
            if (num > max)
                    max = num;
            sum += num;
            sum_sqs += (num*num);
    }
    average = sum/N;
    std_dev = sqrt((sum_sqs/N)-(average*average));

    printf("Smallest: %.2lf\n", min);
    printf("Largest: %.2lf\n", max);
    printf("Average: %.2lf\n)", average);
    printf("Standard deviation: %.3lf\n", std_dev);
return(0);
}

Currently, the compiler does not let me get past an error about an undefined reference to sqrt and i cannot figure out what's wrong. Thank you in advance to everybody who takes the time to respond! I really appreciate any help, I am still getting the hang of C. If my code is not doing what I intend it to do please dont hesitate to correct me!

Updated the messy part to below. Still not sure what exactly im doing with the rest though haha pFile = fopen(argv[1], "r"); fscanf(pFile, "%lf", &N);

    if (fscanf(pFile, "%lf", &N) == 1)
    {
            for (int i = 0; i < N; i++)
            {
            if (fscanf(pFile, "%lf", &num) == 1)
                    if (num < min)
                            min = num;
                    if (num > max)
                            max = num;
                    sum += num;
                    sum_sqs += (num*num);
    }
    average = sum/N;
    std_dev = sqrt((sum_sqs/N)-(average*average));

Upvotes: 0

Views: 12323

Answers (2)

Jonathan Leffler
Jonathan Leffler

Reputation: 753525

Analysis

There is a wealth of problems in these few lines:

pFile = fopen("argv[1]", "r");
fscanf(pFile, "%lf", &N);

while(!feof(pFile))
{
        fscanf(pFile, "%d", &num);
  1. You probably wanted to open the file designated by argv[1], not a file called argv[1]. Remove the quotes.
  2. You didn't check that you were passed an argument.
  3. You don't check that fopen() succeeded, so you probably crashed in your first fscanf().
  4. You don't check that fscanf() succeeded. It is also odd to read what should probably be an integer value into a double, but the notation used will work.
  5. You should not use feof() like that, especially if …
  6. You don't check that the second fscanf() succeeded, and it won't work properly (but might not report the problem) because …
  7. You are trying to read integers (%d) into a double.

So, you should have written:

if (argc <= 1)
    …report error and exit…(or use pFile = stdin)…
FILE *pFile = fopen(argv[1], "r");
if (pFile == 0)
    …report error and exit…
if (fscanf(pFile, "%lf", &N) == 1)
{
    for (int i = 0; i < N; i++)
    {
        if (fscanf(pFile, "%lF", &num) != 1)
            …report error, close file, and exit…
        …as before…more or less…subject to fixing any as yet undiagnosed errors…
    }
}
fclose(pFile);

Incidentally, you forgot to set sum_sqs to zero before you started adding to it, so you won't know what value you got. Also, if all the numbers are negative, you'll report that the maximum is 0; if all the numbers are positive, you'll report that the minimum is 0. Fixing that is a tad fiddly, but you could use if (i == 0 || num < min) min = num; etc.


Linking Problem

Your linking problem (undefined reference to sqrt()) indicates that you are running on a system where you need to link the maths library; that is usually -lm on the end of the linking command line.


Synthesis

#include <stdio.h>
#include <math.h>

int main(int argc, char*argv[])
{
    double average, num = 0, min = 0, max = 0, sum = 0, N, std_dev, sum_sqs = 0.0;

    if (argc <= 1)
    {
        fprintf(stderr, "Usage: %s file\n", argv[0]);
        return 1;
    }

    FILE *pFile = fopen(argv[1], "r");
    if (pFile == 0)
    {
        fprintf(stderr, "%s: failed to open file %s\n", argv[0], argv[1]);
        return 1;
    }
    if (fscanf(pFile, "%lf", &N) == 1)
    {
        for (int i = 0; i < N; i++)
        {
            if (fscanf(pFile, "%lF", &num) != 1)
            {
                fprintf(stderr, "%s: failed to read number\n", argv[0]);
                return 1;
            }

            if (num < min || i == 0)
                min = num;
            if (num > max || i == 0)
                max = num;
            sum += num;
            sum_sqs += (num*num);
        }
    }

    fclose(pFile);
    average = sum/N;
    std_dev = sqrt((sum_sqs/N)-(average*average));

    printf("Smallest: %7.2lf\n", min);
    printf("Largest: %7.2lf\n", max);
    printf("Average: %7.2lf\n", average);
    printf("Standard deviation: %7.3lf\n", std_dev);
    return(0);
}

Results

Given data file data:

5    
4.34 23.4 18.92 -78.3 17.9

The result of running the program is:

Smallest:  -78.30
Largest:   23.40
Average:   -2.75
Standard deviation:  38.309

Those values mostly look plausible; my calculation of the standard deviation came to 42.83 (using a different tool altogether). The difference is between the sample standard deviation and the population standard deviation (a factor of √1.25) — so your value is OK as you calculated it.

# Count    = 5
# Sum(x1)  = -1.374000e+01
# Sum(x2)  =  7.375662e+03
# Mean     = -2.748000e+00
# Std Dev  =  4.283078e+01
# Variance =  1.834476e+03
# Min      = -7.830000e+01
# Max      =  2.340000e+01

So, the code works for me. What result are you getting?

Upvotes: 6

Christian Ternus
Christian Ternus

Reputation: 8492

If you want the sqrt function, you need to add

#include <math.h>

to the top of your C file.

  • if you want to read a float with scanf, you should be using the %f format specifier, not %d (which will read an integer).
  • In your fopen call, remove the quotes around argv[1], otherwise it'll look for a file with that name.

Upvotes: 0

Related Questions