为什么我的程序不能正确处理大文件(650M)?K&R 发挥 5-13 尾巴

Why doesn't my program work with large files(650M) correctly? K&R exersice 5-13 tail

提问人:hansoko 提问时间:9/11/2023 最后编辑:hansoko 更新时间:9/11/2023 访问量:62

问:

练习 5-13。编写程序尾部,打印最后 n 行 的输入。默认情况下,n 设置为 10,让我们说,但它可以是 通过可选参数更改,以便“tail -n”打印最后 n 线。无论如何,程序都应该理性地运行 n的输入或值不合理。编写程序,使其 充分利用可用存储空间;行应按 第 5.6 节的排序程序,不在二维数组中 固定大小。

我写的代码(我把它放在帖子的末尾)适用于小文件,但是当它是一个大文件时,它会给出奇怪的输出。该文件约为 650 兆字节,每行超过 1000 个字符,除了最后 11 行:1、2、3 到 11。当我使用 -11 运行它时,此输出一切正常:

Printing 11 lines
1
2
3
4
5
6
7
8
9
10
11

但是当我用 -1 运行它时,我得到以下输出:

Printing 1 line
input too big too handle

与运行大约需要 5 或 6 秒的 -11 不同,这个运行速度非常快,这意味着错误在程序中发生得太早。输出与 -1 中的输出相同,具有 -2、-3 和 -4。 在 -5 时,我得到这个:

Printing 5 lines
1
8
9
10
11

使用 -6 这个:

Printing 6 lines
1
7
8
9
10
11

它在 -7 及更高版本下正常工作:

Printing 7 lines
5
6
7
8
9
10
11

如果我删除最后一行 11,并使用 -5 或 -6 运行它,我会得到以下输出:

Printing 5 lines

7
8
9
10

Printing 6 lines

6
7
8
9
10

这是我写的代码:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

int isint(char s[]); 
int toint(char s[]); /* convert s to an integer */
int readlines(char *lineptr[], int no); /* read the last 'no' lines and save them in lineptr */
void writelines(char *lineptr[], int no);

#define MAXLINE 100 /* the maximum acceptable number of lines to be printed */

int main(int argc, char *argv[])
{
    int n = 10;
    char *lineptr[MAXLINE];

    while (--argc > 0) {
        if ((*++argv)[0] == '-' && isint(*argv) && toint(*argv) <= MAXLINE) {
            n = toint(*argv);
            break;
        }
        else
            printf("invalid argument %s\n", *argv);
    }

    printf("Printing %d line%s\n", n, n > 1 ? "s" : "");
    if (readlines(lineptr, n) >= 0) {
        writelines(lineptr, n);
        return 0;
    } else {
        printf("input too big too handle\n");
        return 1;
    }

    return 0;
}

int isint(char s[])
{
    while (*s == '-' || *s == '0')
        s++;
    if (isdigit(*s)) {
        while (*s != '\0')
            if (!isdigit(*s++))
                return 0;
        return 1;
    } else
        return 0;
}

int toint(char s[])
{
    while (*s == '-' || *s == '0')
        s++;
    return atoi(s);
}

#define MAXLEN 1000 /* maximum acceptable length of a line to be saved */

int readlines(char *lineptr[], int no)
{
    char *alloc(int n, int no);
    int get_line(char *, int); /* returns the length of a line excluding '\0' */
    void push(char *lineptr[], char *p, int len); /* pushes a pointer in lineptr */

    int len, i;
    char *p, line[MAXLEN];

    for (i = 0; i < no; i++)
        lineptr[i] = NULL;  /* in case the number of to-be-printed lines is less thatn 'no' */

    while ((len = get_line(line, MAXLEN)) > 0)
        if ((p = alloc(len, no)) == NULL) {
            return -1;
        } else {
            line[len-1] = '\0'; /* remove the nl character, -*/
                                /*-the last line of input is expected to end in a nl */
            strcpy(p, line);
            push(lineptr, p, no);
        }
    return 1;
}

void writelines(char *lineptr[], int no)
{
    int i;
    
    for (i = 0; i < no; i++)
        if (lineptr[i] != NULL)
            printf("%s\n", lineptr[i]);
}

int get_line(char *line, int lim)
{
    int i, c;

    i = 0;
    while (--lim > 0 && (c = getchar()) != EOF && c != '\n')
        line[i++] = c;
    if (c == '\n')
        line[i++] = c;
    line[i] = '\0';

    return i;
}

void push(char *lineptr[], char *p, int no)
{
    int i;

    for (i = 0; i < no-1; i++)
        lineptr[i] = lineptr[i+1];
    lineptr[no-1] = p;
}

#define ALLOCSIZE MAXLINE * MAXLEN

static char allocbuf[ALLOCSIZE];
static int allocn = 0; /* the number of allocations */
static char *allocp = allocbuf;
static char *leftalloc = allocbuf; /* left edge of the replaceable section of array */
static char *rightalloc = allocbuf - 1; /* right edge of the replaceable section of array */

char *alloc(int n, int no)
{
    int i;
    char *j;

    if (allocn%no == no - 1) {
        leftalloc = allocbuf;
        rightalloc = allocbuf - 1; /* no line is replaceable yet */
    }
    if (allocn >= no) {
        while (allocn-no >= no) /* reduce allocn to congruent modulo 'no' value to prevent overflow */
            allocn -= no;
        for (i = 0; i < allocn%no; i++)
            while (*rightalloc++ != '\0');
                ;
    }

    if (n <= rightalloc - leftalloc + 1) {
        leftalloc += n;
        allocn++;
        return leftalloc - n;
    } else if (n <= allocbuf + ALLOCSIZE - allocp) {
        allocp += n;
        allocn++;
        return allocp - n;
    } else
        return NULL;
}

我检查了一下,问题很可能来自alloc函数

数组 c 字符串 大文件

评论

4赞 Andrew Henle 9/11/2023
您需要考虑的事情:这些大文件中有多少行?
3赞 Ptit Xav 9/11/2023
在 get_line 中,您不测试最大行长度。还要检查每行影响中 i 的值。
0赞 Jabberwocky 9/11/2023
您是否尝试调试该函数?我建议你学习如何使用调试器。readlines
0赞 hansoko 9/11/2023
@AndrewHenle 254380(最后一行为 11 位数字)
0赞 hansoko 9/11/2023
@PtitXav (--lim > 0) 确保我不会超过限制。

答: 暂无答案