模仿 linux 的排序命令,对文本文件的行进行排序

To mimic sort command of linux, to sort lines of a text file

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

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

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

  • 换行符的数量可能少于成功调用 fgets() 的数量:超过 499 字节的行将被静默地分成多个块,导致更多的项目被 [=13= 读取] 比换行符。最后一行可能不会以换行符结尾。只需计算成功调用 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 == '[=11=]')
            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;
    }
}