Home > Software design >  Find largest number in file
Find largest number in file

Time:03-02

I need to find largest integer number in a file and print it. Numbers can have more than 100 digits, and after each number there is a comma, except for last number after which comes nothing.

Example 1:

-87654,-987,-23,-12344

Example 2:

12345123451234512345,678,90,12345123451234512346,12344

Here is my code:

#include <stdio.h>

int main() {
    const char file[] = "numbers.txt";
    FILE *fp = fopen(file, "r");
    int c = fgetc(fp);
    int prev = 0, max = 0, final_max, count = 1, start;
    while (c != EOF) {
        prev = max;
        max = 0;
        while (1) {
            c = fgetc(fp);
            count  ;
            max  ;
            if (c == 44 || c == EOF) {
                count--;
                break;
            }
        }
        if (prev > max) {
            final_max = prev;
            start = count - final_max;
        }
    }
    fclose(fp);
    FILE *fp_fp = fopen(file, "r");
    int i = 0;
    while (1) {
        c = fgetc(fp_fp);
        i  ;
        if (i >= start && i < start   final_max - 1)
            printf("%c", c);
        if (i == start   final_max)
            break;
    }
    fclose(fp_fp);
    return 0;
}

Using arrays, strings, and function fscanf is not allowed


My algorithm is the following (variable names are in code):

  • find number of digits of longest number (final_max)
  • store starting index of longest number without arrays (start)
  • last index of longest number is start final_max - 1
  • close file and open it again
  • when starting index is found start printing numbers one by one until last index is reached

I have two problems here:

This sometimes adds extra numbers before or after numbers.

This doesn't work for negative numbers.

Could you help me modify my code to work properly?

CodePudding user response:

Which number is larger?

  • 999
  • 1000

The longer number is larger.


Which number is larger?

  • 123
  • 132

The number with the largest leftmost digit is larger.

This second one takes a little thinking about it to see that it is right. As long as the leftmost digits are the same, they can be ignored. Hence:

12345  -->  2345  -->  345  -->  45
12372  -->  2372  -->  372  -->  72  -->  (7 > 4) therefore (12372 > 12345)

Which number is larger?

  • -7
  • 5

Positive numbers are always larger than negative numbers.


Which number is larger?

  • -123
  • -132

Both numbers are negative, making the answer the inverse of what they were when both positive. In other words, 123 <  132 therefore -123 > -132.


What makes this difficult is the injunction to not use arrays (strings) of any kind. I am continuing with the presumption that this includes the current largest number.

Unfortunately your current code is a bit of a logical mess...
You need to think more about how you intend to solve the problem before you write a whole bunch of code. Here are some hints:

We cannot store strings, but we can track read locations in a file using ftell() and fseek().

Something else we can do to make life easier is to open the input file twice — once for the current largest number and once for the current number being compared. This allows us to use the standard fgetc() for each file without having to fseek() back and forth for every digit of the two numbers.

You should write yourself a function to compare two numbers from the two file objects:

int compare( FILE * lhs, FILE * rhs );
// returns -1 if lhs <  rhs
// returns  0 if lhs == rhs
// returns  1 if lhs >  rhs

This function is really the hardest part. In my own solution I found that the following functions were also helpful:

int fpeek( FILE * f )
{
  int c = fgetc( f );
  ungetc( c, f );
  return c;
}

int sign( FILE * f );
// returns -1 or 1
// if the next character in f is a '-':
//   then discard it and return -1 (negative)
//   else return 1 (positive)

int next( FILE * f );
// Returns a digit '0'..'9'
// or 0 if end of number (character was a ',' or EOF)

void skip( FILE * f )
// Skip to next number
{
  while (next( f )) { }
}

The principles I outlined above are what you need to test the numbers. The hardest part of it is working with comparing length and value. I wrote mine doing both things at once, but you might find it easier to do more or less what you were initially thinking:

  1. Compare signs. If different you’re done!
    (largest is the non-negative one)
  2. Compare lengths. If different you’re done!
    (largest is the longest if sign==1, the shortest if sign==-1)
  3. Seek back and compare values. First difference and you’re done!
    largest is first larger value if sign==1, ...
  4. No differences, you’re done: (a==b)!

Remember that the sign stuff flips the result between -1 and 1. You can do this with an easy multiplication. For example, if you wished to return that lhs was the larger number if it were positive then return -1 * sign;.


The next kind of hard part is in main(), but this is easier than the comparison function at least. You just need to find the beginning of each number in a loop and do a comparison. Remember to use ftell() to be able to reset the positions after calling compare() and skip() to the next number.

FILE * f_largest = fopen( "numbers.txt", "r" );
FILE * f_current = fopen( "numbers.txt", "r" );

The f_largest file object is for the currently-largest number.
The f_current file object is for looping through the numbers to compare.

This part of the algorithm works like any “find the max number” algorithm: keep track of the largest number found until you have looked at all the numbers. Do you see how using two file objects makes this easy?

while current is not at EOF:
  position of largest = ftell largest
  position of current = ftell current

  compare largest and current. If current > largest:
    largest position = current position

  fseek in largest to position of largest
  fseek in current to position of current
  skip current to next

Once you have finished the main loop you just need to print the number at f_largest.


Evil homeworks!

This stuff is designed to stretch your brain really hard. This particular assignment, IMHO, is a little over-the-top for a CS 101, but it should still be doable.

These kinds of assignments do get tricker as you go. The whole point is for you to struggle until you can wrap your brain around a solution. The more you can figure that solution yourself the better.

It certainly helps to have more experience with programming in general, though. This assignment kind of assumes a few jumps that I don’t think are really under your belt yet, but I could be wrong abouty what level you are expected to function.

In any case, hopefully this edit has made things more clear in terms of how to handle this. The underlying point is that a file is just another source of characters, just like a string. You simply have to access it with seek and get functions instead of array indexing.

That, and you will notice that I (regularly) advocate for little helper functions. Split your task into smaller pieces and it becomes much more manageable.

CodePudding user response:

The restriction to not use arrays or strings is a bit difficult and prevents stream handling as you must be able to seek backwards.

Here is an implementation of the method described by Dúthomhas. Note however that it does not handle leading zeroes, signs nor spaces:

#include <stdio.h>

int is_digit(int c) { return c >= '0' && c <= '9'; }

int main() {
    const char file[] = "numbers.txt";
    FILE *fp = fopen(file, "r");
    FILE *fp2 = fopen(file, "r");
    long largest = 0, current = 0;
    int c, c2, cmp = 0, neg = 0, neg2 = 0;

    for (;;) {
        c = getc(fp);
        if (c == '-') {
            neg = 1;
            c = getc(fp);
        }
        c2 = getc(fp2);
        if (c2 == '-') {
            neg2 = 1;
            c2 = getc(fp2);
        }
        if (is_digit(c)) {
            if (is_digit(c2)) {
                if (cmp == 0)
                    cmp = c - c2;
                continue;
            }
            /* number is longer than largest */
            cmp = 1;
        } else
        if (is_digit(c2)) {
            /* current is shorter */
            cmp = -1;
        } else {
            /* current and largest have the same length */
        }
        if (neg) {
            if (neg2 && cmp < 0)
                largest = current;
        } else {
            if (neg2 || cmp > 0)
                largest = current;
        }
        fseek(fp2, largest, SEEK_SET);
        /* skip remaining digits */
        while (is_digit(c))
            c = getc(fp);
        current = ftell(fp);
        cmp = neg = neg2 = 0;
        if (c == EOF)
            break;
    }
    while ((c = getc(fp2)) != ',' && c != EOF)
        putchar(c);
    putchar('\n');
    fclose(fp);
    fclose(fp2);
    return 0;
}
  • Related