【问题标题】:Corrupted data when using a multidimensional char array使用多维 char 数组时数据损坏
【发布时间】:2021-03-05 08:39:24
【问题描述】:

我目前正在实现一个使用“外部排序”方法的函数,因为我必须在 RAM 低的设备上对一个大文件(+200K 行)进行排序,现在只是想让它在 Windows pc 上运行. 我正在研究将文件拆分为小排序文件的功能。

我面临的问题是,在函数创建的微小排序文件中,某些行上的数据被截断。

我很确定我在某个地方犯了错误,但还没有找到。你能帮我找出问题吗?

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

#define MAX_LINE_LEN 50
#define MAX_LINES_SORTED 130

void createSortedFiles(FILE*);

int main()
{
    FILE *fp = fopen("C:\\C\\Tests\\1.txt", "r+");

    if(fp == NULL){
        printf("Error opening fp");
        return 1;
    }

    createSortedFiles(fp);

    fclose(fp);

    return 0;
}

int cmp(const void *p1, const void *p2) {
    return strcmp(p1, p2);
}

void createSortedFiles(FILE* fp) {
    FILE* sfp;
    //FILE* sfp2 = fopen("C:\\C\\Tests\\test.txt", "w+");
    char lines[MAX_LINES_SORTED][MAX_LINE_LEN + 1] = {0}, buffer[MAX_LINE_LEN + 1] = { 0 }, fnum[6];
    char fname[20] = "C:\\C\\Tests\\";
    char *p;
    int i = 0, j = 0 /*file names*/, int max_lines = MAX_LINES_SORTED - 1;
    size_t N;

    while (1){
        p = fgets(buffer, MAX_LINE_LEN, fp);
        // fwrite(buffer, strlen(buffer), 1, sfp2);

        if(strlen(buffer) > 0 || i > 0){
            if(p != NULL)
                memcpy(lines[i], buffer, strlen(buffer));


            //If reached the max number of lines accepted in the array
            //Or reached EOF
            //=> Sort and write the array "lines"
            if (i >= max_lines || p == NULL) {
                N = sizeof(lines) / sizeof(lines[0]);
                qsort(lines, N, sizeof(*lines), cmp);

                //sets the name of the current file
                memset(&fname[11], 0, 9);
                itoa(j, fnum, 10);
                strcat(fname, fnum);

                if ((sfp = fopen(fname, "w+")) == NULL) {
                    printf("Error opening sfp");
                    return;
                }

                for (i = 0; i < N; i++) {
                    fwrite(lines[i], strlen(lines[i]), 1, sfp);
                }

                fclose(sfp);

                memset(lines, 0, sizeof(lines[0][0]) * MAX_LINES_SORTED * MAX_LINE_LEN);

                j++; i = -1; //because incremented right after
            }
        }

        if(p == NULL){
            break;
        }

        i++;
    }

    //fclose(sfp2);

    return;
}

以下是 fp 文件的示例(每行以 \r\n 结尾):

8023796280724;00060-014.W47
8023796280731;00060-014.W48
;0009070305/08007
;0009470337/08007
;0009490338/13001
;0010480311/08007
;0010830308/08007
;0011S
8033280129293;002004GRS4XL
;002015RSM
5708628117005;00207-630-06T42
5708628117012;00207-630-06T44
5708628117036;00207-630-06T46
4051428088756;647530241000045
4051428088763;647530241000046
4051428088770;647530241000047
;647BLPMF
4051428092586;648510256000040
4051428092593;648510256000041
4051428092609;648510256000042
4051428092616;648510256000043
4051428092623;648510256000044
4051428092630;648510256000045
4051428092647;648510256000046

【问题讨论】:

  • char lines[MAX_LINES_SORTED][MAX_LINE_LEN + 1] = {0}, buffer[MAX_LINE_LEN + 1], *p, fname[20] = "C:\\C\\Tests\\", fnum[6];? 全部在一行?这几乎是不可读的。将尽可能多的代码塞进一行只会导致难以阅读的代码和错误。
  • 注意到,对可读性感到抱歉,我更正了它
  • p = fgets(buffer, ...); 一切正常后,请记住检查返回值p尝试使用buffer
  • 你读过Introduction to algorithms 吗?花几天时间读完那本书。然后阅读Modern C
  • 旁白:itoa(j, fnum, 10); 好于 j &lt;= 99,999,999,否则缓冲区溢出。不是一个大问题,因为 j 不太可能这么大,但考虑一个缓冲区来处理所有可能的 itoa() 结果。

标签: c sorting external-sorting


【解决方案1】:

您的“截断行”并不是真正的截断行,它们是先前文件留在缓冲区中的杂散数据。

这个数组:

#define MAX_LINE_LEN 50
#define MAX_LINES_SORTED 130

char lines[MAX_LINES_SORTED][MAX_LINE_LEN + 1];

有 6630 字节,但在这里:

memset(lines, 0, sizeof(lines[0][0]) * MAX_LINES_SORTED * MAX_LINE_LEN);

您仅将 6500 个字节归零并保留最后两行。

您可以通过在大小计算中使用 (MAX_LINE_LEN +1) 来解决此问题,但数组可以更简洁(并且更可靠)清零,只需:

memset(lines, 0, sizeof(lines));

【讨论】:

  • 谢谢,确实,现在我明白了,我不知道为什么我认为使用 MAX_LINE_LEN 而不是 MAX_LINE_LEN + 1 它不会将每个字节的最后一个字节初始化为 0我的数组中的行,但如果我理解正确,它并没有重置我的数组的最后一行
  • 是的,您错过了从字节 6528 和 6579 开始的两行。这是一个容易犯的错误。
  • (还有一个问题:当你检查是否i &gt;= 130时,你已经将缓冲区复制到lines[130]中,这是超出数组末尾的一个。它会损坏内存(可能只有@ 987654329@) 并且会让你丢失每 131 行输入。)
  • 是的,我在几分钟前发现了它,这就是程序运行如此随机的原因。我相信现在一切都很好
猜你喜欢
  • 2012-10-24
  • 1970-01-01
  • 1970-01-01
  • 2011-12-16
  • 1970-01-01
  • 2020-01-22
  • 2021-02-01
  • 2013-03-17
  • 1970-01-01
相关资源
最近更新 更多