【问题标题】:To mimic sort command of linux, to sort lines of a text file模仿linux的排序命令,对文本文件的行进行排序
【发布时间】:2020-05-22 14:42:09
【问题描述】:

Linux 的排序命令必须对文本文件的行进行排序,并将输出传输到另一个文件。但是我的代码给出了运行时错误。请纠正指针错误以便输出。

我应该在哪一行进行更改?因为毕竟没有输出。

我正在粘贴整个代码:

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

void sortfile(char **arr, int linecount) {
    int i, j;
    char t[500];

    for (i = 1; i < linecount; i++) {
        for (j = 1; j < linecount; j++) {
            if (strcmp(arr[j - 1], arr[j]) > 0) {
                strcpy(t, arr[j - 1]);
                strcpy(arr[j - 1], arr[j]);
                strcpy(arr[j], t);
            }
        }
    }
}

int main() {
    FILE *fileIN, *fileOUT;

    fileIN = fopen("test1.txt", "r");

    unsigned long int linecount = 0;
    int c;
    if (fileIN == NULL) {
        fclose(fileIN);
        return 0;
    }

    while ((c = fgetc(fileIN)) != EOF) {
        if (c == '\n')
            linecount++;
    }

    printf("line count=%d", linecount);
    char *arr[linecount];
    char singleline[500];

    int i = 0;
    while (fgets(singleline, 500, fileIN) != NULL) {
        arr[i] = (char*)malloc(500);
        strcpy(arr[i], singleline);
        i++;
    }

    sortfile(arr, linecount);

    for (i = 0; i < linecount; i++) {
        printf("%s\n", arr[i]);
    }
    fileOUT = fopen("out.txt", "w");
    if (!fileOUT) {
        exit(-1);
    }

    for (i = 0; i < linecount; i++) {
        fprintf(fileOUT, "%s", arr[i]);
    }

    fclose(fileIN);
    fclose(fileOUT);
}

【问题讨论】:

    标签: c sorting pointers file-handling


    【解决方案1】:

    您的代码中的问题是您在第一次读取输入流后没有倒回它以计算换行符的数量。您应该在下一个循环之前添加rewind(fileIN);

    但请注意,此代码中还有其他问题:

    • 换行符的数量可能少于成功调用fgets() 的数量:超过499 字节的行将被静默地分成多个块,导致fgets() 读取的项目多于换行符。最后一行可能不会以换行符结尾。只需计算成功调用fgets() 的次数即可。
    • 您为每行分配 500 个字节,这可能非常浪费。使用strdup() 仅分配必要的大小。
    • 交换排序例程中的行应该通过交换指针来完成,而不是复制内容。
    • 使用malloc 分配arr 比使用char *arr[linecount]; 将其定义为可变大小的数组更安全、更便携

    这是修改后的版本:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void sortfile(char **arr, int linecount) {
        for (;;) {
            int swapped = 0;
            for (int j = 1; j < linecount; j++) {
                if (strcmp(arr[j - 1], arr[j]) > 0) {
                    char *t = arr[j - 1];
                    arr[j - 1] = arr[j];
                    arr[j] = t;
                    swapped = 1;
                }
            }
            if (swapped == 0)
                break;
        }
    }
    
    int main() {
        FILE *fileIN, *fileOUT;
        char singleline[500];
        int i, linecount;
    
        fileIN = fopen("test1.txt", "r");
        if (fileIN == NULL) {
            fprintf(stderr, "cannot open %s\n", "test1.txt");
            return 1;
        }
    
        linecount = 0;
        while (fgets(singleline, 500, fileIN)) {
            linecount++;
        }
    
        printf("line count=%d\n", linecount);
    
        char **arr = malloc(sizeof(*arr) * linecount);
        if (arr == NULL) {
            fprintf(stderr, "memory allocation failure\n");
            return 1;
        }
    
        rewind(fileIN);
        for (i = 0; i < linecount && fgets(singleline, 500, fileIN) != NULL; i++) {
            arr[i] = strdup(singleline);
            if (arr[i] == NULL) {
                fprintf(stderr, "memory allocation failure\n");
                return 1;
            }
        }
        fclose(fileIN);
    
        if (i != linecount) {
            fprintf(stderr, "line count mismatch: i=%d, lilnecount=%d\n",
                    i, linecount);
            linecount = i;
        }
    
        sortfile(arr, linecount);
    
        for (i = 0; i < linecount; i++) {
            printf("%s", arr[i]);
        }
        fileOUT = fopen("out.txt", "w");
        if (!fileOUT) {
            fprintf(stderr, "cannot open %s\n", "out.txt");
            return 1;
        }
        for (i = 0; i < linecount; i++) {
            fprintf(fileOUT, "%s", arr[i]);
        }
        fclose(fileOUT);
    
        for (i = 0; i < linecount; i++) {
            free(arr[i]);
        }
        free(arr);
        return 0;
    }
    

    要获得不同的排序顺序,您需要更改比较函数。你可以用这个代替strcmp()

    #include <ctype.h>
    
    int my_strcmp(const char *s1, const char *s2) {
        /* compare strings lexicographically but swap lower and uppercase letters */
        unsigned char c, d;
        while ((c = *s1++) == (d = *s2++)) {
            if (c == '\0')
                return 0;   /* string are equal */
        }
        /* transpose case of c */
        if (islower(c)) {
            c = toupper(c);
        } else {
            c = tolower(c);
        }
        /* transpose case of d */
        if (islower(d)) {
            d = toupper(d);
        } else {
            d = tolower(d);
        }
        /* on ASCII systems, we should still have c != d */
        /* return comparison result */
        if (c <= d)
            return -1;
        } else {
            return 1;
        }
    }
    

    【讨论】:

    • 有没有办法可以修改代码以先打印以小写字母开头的行,然后打印以大写字母开头的行(即与 ascii 值的顺序相反)。我正在学习如何编码这真的很有帮助。
    • @smruthibt:我用这个订单的不同比较函数修改了答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-20
    • 1970-01-01
    • 2011-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多