查找文件中的最大数

Find largest number in file

我需要在文件中找到最大的整数并打印出来。数字可以超过 100 位,每个数字后面有一个逗号,除了最后一个数字,后面什么都没有。

示例 1:

-87654,-987,-23,-12344

示例 2:

12345123451234512345,678,90,12345123451234512346,12344

这是我的代码:

#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;
}

不允许使用数组、字符串和函数fscanf


我的算法如下(变量名在代码中):


我这里有两个问题:

这有时会在数字之前或之后添加额外的数字。

这不适用于负数。

你能帮我修改我的代码以使其正常工作吗?

哪个数字更大?

  • 999
  • 1000

更长的数字更大。


哪个数字更大?

  • 123
  • 132

最大最左边位的数字较大。

第二个稍微想一想就知道是对的。只要最左边的数字相同,就可以忽略。因此:

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

哪个数字更大?

  • -7
  • 5

正数总是大于负数。


哪个数字更大?

  • -123
  • -132

两个数字都是负数,这使得答案与两个数字都为正数时的结果相反。换句话说,+123 < +132 因此 -123 > -132.


让这变得困难的是禁止使用任何类型的数组(字符串)的禁令。我继续假设这包括当前最大的数字。

不幸的是,您当前的代码有点逻辑混乱...
在编写一大堆代码之前,您需要更多地考虑您打算如何解决问题。这里有一些提示:

我们无法存储字符串,但我们可以使用ftell()fseek()跟踪文件中的读取位置。

为了让生活更轻松,我们可以做的其他事情是打开输入文件 两次 — 一次打开当前最大的数字,一次打开当前正在比较的数字。这允许我们为每个文件使用标准 fgetc(),而不必为两个数字的每个数字来回 fseek()

您应该自己编写一个函数来比较两个文件对象中的两个数字:

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

这个函数真的是最难的部分。在我自己的解决方案中,我发现以下功能也很有帮助:

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 )) { }
}

我上面概述的原则是您测试数字所需要的。其中最难的部分是比较 lengthvalue。我写了我的 同时做这两件事,但您可能会发现或多或少地做您最初的想法会更容易:

  1. 比较符号。如果不同你就完成了!
    (最大的是non-negative一个)
  2. 比较长度。如果不同你就完成了!
    (如果sign==1最大就是最长,如果sign==-1就是最短)
  3. 返回并比较值。第一个差异,你就完成了!
    如果 sign==1,最大的是第一个较大的值,...
  4. 没有区别,大功告成:(a==b)!

请记住,符号会翻转 -11 之间的结果。您可以通过简单的乘法来做到这一点。例如,如果您希望 return lhs 是较大的数字 如果它是正数 那么 return -1 * sign;.


下一个比较难的部分在main(),但这至少比比较函数简单。您只需要在循环中找到每个数字的开头并进行比较即可。请记住使用 ftell() 以便能够在调用 compare()skip() 到下一个数字后重置位置。

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

f_largest 文件对象用于 currently-largest 号码。
f_current 文件对象用于循环比较数字。

这部分算法的工作原理与任何“查找最大数”算法类似:跟踪找到的最大数,直到您查看了所有数字。您看到使用 两个 文件对象如何使这变得简单了吗?

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

完成主循环后,您只需在 f_largest 处打印数字。


邪恶的作业!

这些东西旨在真正地锻炼您的大脑。恕我直言,这项特殊作业对于 CS 101 来说有点 over-the-top,但它应该仍然可行。

这些类型的作业确实会随着您的进行而变得更加棘手。重点是让你 努力 直到你能全神贯注地想出一个解决方案。您自己想出的解决方案越多越好。

不过,拥有更多的一般编程经验当然会有所帮助。这个作业假设了一些我认为你还没有真正掌握的跳跃,但我可能对你期望的功能水平有误。

无论如何,希望这次编辑让事情在如何处理这个问题上变得更加清晰。基本点是文件只是字符的另一个来源,就像字符串一样。您只需使用 seek 和 get 函数而不是数组索引来访问它。

那个,你会注意到我(经常)提倡使用小辅助函数。将您的任务分成更小的部分,它变得更易于管理。

不使用数组或字符串的限制有点困难,并且会阻止流处理,因为您必须能够向后查找。

这里是 Dúthomhas 描述的方法的实现。但请注意,它不处理前导零、+ 符号或空格:

#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;
}