c - 如何根据每行末尾的值对文件行进行排序

标签 c sorting file-io

我正在尝试创建一个程序,它接受一个输入文件并根据每行末尾的数字按升序将其排序为新的输出文件。例如,如果输入文件包含以下三行:

a good man 50
65
better are 7

相应的排序输出文件将是三行但排序:

better are 7
a good man 50
65

我目前的代码:

int sortLines(char * inputFileName, char * outputFileName)
{
   FILE *fpin = fopen(inputFileName, "r");//open file to to read
   if (!fpin)
   {
      printf("Error in file opening\n");
      exit (-1);
   }
   FILE *fpout = fopen(outputFileName, "w");//open file to to write
   if (!fpout)
   {
      printf("Error in opfile opening\n");
      exit (-1);
   }
   char file[10][1024];
   int i = 0;
   while(fgets(file[i], sizeof(file[i]), fpin))
      i++;
   int total = i;
   for(i = 0; i<total; ++i)
      printf("%s", file[i]);
   return 0;
}

最佳答案

从注释继续,您可以将这些行读入一个结构(包含该行和一个 int),然后使用 strrchr 查找每行中的最后一个空格(或者如果为 null,则只取整行),将字符串用strtolatoi等进行转换,设置struct的int字段。然后根据 int 成员对结构进行排序是一件简单的事情。我会把对结构的阅读留给你,排序示例是:

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

#define MAXL 32

struct data {
    char line[MAXL];
    int n;
};

int compare_n (const void *a, const void *b)
{
    struct data *ia = (struct data *)a;
    struct data *ib = (struct data *)b;
    return (int)(ia->n - ib->n);
}

int main (void)
{
    struct data lines[] = {{"a good man 50", 50}, {"65", 65}, {"better are 7", 7}};
    size_t nstr = sizeof lines / sizeof *lines;
    size_t i = 0;

    qsort (lines, nstr, sizeof *lines, compare_n);

    for (i = 0; i < nstr; i++)
        printf (" %s\n", lines[i].line);

    return 0;
}

输出

$ ./bin/struct_sort_int
 better are 7
 a good man 50
 65

完整示例

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

#define MAXL 64

/* simple struct holding char array and int */
struct data {
    char line[MAXL];
    int n;
};

/* qsort comparison function for int 'n' */
int compare_n (const void *a, const void *b)
{
    struct data *ia = (struct data *)a;
    struct data *ib = (struct data *)b;
    return (int)(ia->n - ib->n);
}

int main (int argc, char **argv)
{
    if (argc < 2 ) {    /* validate at least 1 argument provided */
        fprintf (stderr, "error: insufficient input, usage: %s filename\n", argv[0]);
        return 1;
    }

    struct data lines[MAXL] = {{{0}, 0}};   /* array of struct      */
    char *ln = NULL;    /* buffer for getline, getline allocates    */
    size_t n = 0;       /* initial size of buf, 0 getline decides   */
    ssize_t nchr = 0;   /* getline return, no. of chars read        */
    size_t idx = 0;     /* index for array of struct                */
    size_t i = 0;       /* general iteration variable               */
    FILE *fp = NULL;    /* file pointer for input file              */

    if (!(fp = fopen (argv[1], "r"))) {     /* validate file open   */
        fprintf (stderr, "error: file open failed. '%s'\n", argv[1]);
        return 1;
    }

    /* read each line in file */
    while ((nchr = getline (&ln, &n, fp)) != -1)
    {
        while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r'))
            ln[--nchr] = 0;     /* strip newline or carriage rtn    */

        if (!nchr) continue;            /* skip blank lines         */

        if (nchr > MAXL - 1) {          /* test for line > MAXL -1  */
            fprintf (stderr, 
                    "warning: line will exceeded %d chars.\n", MAXL);
            continue;                   /* number at end invalid    */
        }

        strcpy (lines[idx].line, ln);  /* copy to struct.line       */

        char *p = NULL;
        if (!(p = strrchr (ln, ' ')))   /* pointer to last space    */
            p = ln;                     /* if no space, then line   */

        lines[idx].n = atoi (p);        /* convert string to int    */

        idx++;                          /* increment index          */

        if (idx == MAXL) {              /* if MAXL read, break      */
            fprintf (stderr, "warning: %d lines read.\n", MAXL);
            break;
        }
    }

    if (fp) fclose (fp);                /* close input file         */
    if (ln) free (ln);                  /* free line buffer mem     */

    qsort (lines, idx, sizeof *lines, compare_n);   /* sort struct  */

    for (i = 0; i < idx; i++)           /* print sorted array       */
        printf (" %s\n", lines[i].line);

    return 0;
}

看一看,如果您有任何问题,请告诉我。您的数据在文件 dat/endno.txt 中供我测试。有机会我会添加评论。

注意:已更新以跳过空行并根据 MAXL 检查行长度,以消除超出行尾的写入和跳过将被截断呈现的行的可能性最后的数字无效。


没有struct静态分配的数组

下面是一个使用两个二维数组的示例,一个用于,另一个保存原始行索引和行尾的编号。与下面的动态分配示例不同,此示例仅限于从文件中读取 MAXL 行或每行不超过 MAXS 个字符。如果一行恰好是 MAXS 个字符长(包括空终止符),则必须丢弃它,因为无法知道末尾的数字是否仍然有效。包含行索引和末尾数字的二维数组根据末尾的数字进行排序,然后根据原始行索引打印行,从而导致行按末尾的数字排序打印。虽然这可能看起来更简单,但它比使用 struct 的方法或下面的动态分配方法要受限得多。这就是我能想到的让你继续前进的全部。祝你好运。如果您有任何问题,请写信。

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

#define MAXL 64
#define MAXS 128

int cmpint (const void *a, const void *b);

int main (int argc, char **argv) {

    if (argc < 2 ) {    /* validate at least 1 argument provided */
        fprintf (stderr, "error: insufficient input, usage: %s filename\n", argv[0]);
        return 1;
    }

    int numidx[MAXL][2] = {{0}};    /* array of integers                        */
    char lines[MAXL][MAXS] = {{0}}; /* array of strings                         */
    char ln[MAXS] = {0};            /* buffer for fgets, MAXS in length         */
    ssize_t nchr = 0;               /* getline return, no. of chars read        */
    size_t idx = 0;                 /* index for array of struct                */
    size_t i = 0;                   /* general iteration variable               */
    FILE *fp = NULL;                /* file pointer for input file              */

    if (!(fp = fopen (argv[1], "r"))) {         /* validate file open   */
        fprintf (stderr, "error: file open failed. '%s'\n", argv[1]);
        return 1;
    }

    /* read each line in file */
    while (fgets (ln, MAXS, fp) != NULL)
    {
        nchr = strlen (ln);             /* get length of ln         */

        while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r'))
            ln[--nchr] = 0;     /* strip newline or carriage rtn    */

        if (!nchr || nchr == MAXS - 2)  /* skip blank lines + full  */
            continue;                   /* lines (end no. invalid)  */

        strcpy (lines[idx], ln);        /* copy ln to lines[idx]    */

        char *p = NULL;
        if (!(p = strrchr (ln, ' ')))   /* pointer to last space    */
            p = ln;                     /* if no space, then line   */

        numidx[idx][0] = atoi (p);      /* save end no. in array    */
        numidx[idx][1] = idx;           /* save line index in array */

        idx++;                          /* increment index          */

        if (idx == MAXL) {              /* if MAXL read, break      */
            fprintf (stderr, "warning: %d lines read.\n", MAXL);
            break;
        }
    }

    fclose (fp);

    qsort (numidx, idx, sizeof (int) * 2, cmpint);/* sort array     */

    for (i = 0; i < idx; i++)           /* print sorted array       */
        printf (" %s\n", lines[numidx[i][1]]);

    return 0;
}

/* qsort integer compare function */
int cmpint (const void *pa, const void *pb )
{
    const int *a = pa;
    const int *b = pb;
    if (a[0] < b[0]) 
        return -1;
    return (b[0] < a[0]);
}

没有struct,动态分配数组

要避免使用结构来保存字符串和数字,您可以使用 2 个数组。一个保存字符串,另一个二维数组保存原始行索引和行尾的数字(2 个整数)。然后,您对 (number at end) 元素上的整数数组 qsort 进行循环,然后循环遍历每一行,根据排序数组的行索引值按排序顺序打印出行。这被设置为处理任何长度的行并根据需要重新分配行数(在每个数组中)。由于动态分配可能有点多,我也在研究静态数组版本,但明天才有时间。这是第一个版本:

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

#define MAXL 64

int cmpint (const void *a, const void *b);
char **realloc_char (char **sp, size_t *n);
int **realloc_int (int **ip, size_t *n);

int main (int argc, char **argv) {

    if (argc < 2 ) {    /* validate at least 1 argument provided */
        fprintf (stderr, "error: insufficient input, usage: %s filename\n", argv[0]);
        return 1;
    }

    int **numidx = NULL;    /* array of pointers-to-pointer-to-int      */
    char **lines = NULL;    /* array of pointer-to-pointer-to-char      */
    char *ln = NULL;        /* buffer for getline, getline allocates    */
    size_t n = 0;           /* initial size of buf, 0 getline decides   */
    ssize_t nchr = 0;       /* getline return, no. of chars read        */
    size_t idx = 0;         /* index for array of struct                */
    size_t i = 0;           /* general iteration variable               */
    size_t maxl = MAXL;     /* holds current allocation size of arrays  */
    FILE *fp = NULL;        /* file pointer for input file              */

    if (!(fp = fopen (argv[1], "r"))) {         /* validate file open   */
        fprintf (stderr, "error: file open failed. '%s'\n", argv[1]);
        return 1;
    }

    /* allocate MAXL pointers to int* */
    if (!(numidx = calloc (MAXL, sizeof *numidx))) {
        fprintf (stderr, "error: memory allocation failed.\n");
        return 1;
    }

    /* allocate MAXL pointers to char* */
    if (!(lines = calloc (MAXL, sizeof *lines))) {
        fprintf (stderr, "error: memory allocation failed.\n");
        return 1;
    }

    /* read each line in file */
    while ((nchr = getline (&ln, &n, fp)) != -1)
    {
        while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r'))
            ln[--nchr] = 0;     /* strip newline or carriage rtn    */

        if (!nchr) continue;            /* skip blank lines         */

        lines[idx] = strdup (ln);       /* copy ln to lines[idx]    */

        /* allocate space for 2 int at numidx[idx] */
        if (!(numidx[idx] = calloc (2, sizeof **numidx))) {
            fprintf (stderr, "error: memory allocation failed.\n");
            return 1;
        }

        char *p = NULL;
        if (!(p = strrchr (ln, ' ')))   /* pointer to last space    */
            p = ln;                     /* if no space, then line   */

        numidx[idx][0] = atoi (p);      /* save end no. in array    */
        numidx[idx][1] = idx;           /* save line index in array */

        idx++;                          /* increment index          */

        if (idx == maxl) {              /* if idx = maxl reallocate */
            size_t tsz = maxl;          /* tmp var, each get maxl   */
            numidx = realloc_int (numidx, &tsz);
            lines = realloc_char (lines, &maxl);
        }
    }

    if (ln) free (ln);
    fclose (fp);

    qsort (numidx, idx, sizeof *numidx, cmpint);  /* sort struct  */

    for (i = 0; i < idx; i++)           /* print sorted array       */
        printf (" %s\n", lines[numidx[i][1]]);

    for (i = 0; i < idx; i++) {         /* free allocated memory    */
        free (numidx[i]);
        free (lines[i]);
    }
    free (numidx);
    free (lines);

    return 0;
}

/* qsort integer compare function */
int cmpint (const void *a, const void *b)
{
    const int **ia = (const int **)a;
    const int **ib = (const int **)b;
    return (*ia)[0] - (*ib)[0];
}

/** realloc an array of pointers to strings setting memory to 0.
*  reallocate an array of character arrays setting
*  newly allocated memory to 0 to allow iteration
*/
char **realloc_char (char **sp, size_t *n)
{
    char **tmp = realloc (sp, 2 * *n * sizeof *sp);
    if (!tmp) {
        fprintf (stderr, "Error: struct reallocation failure.\n");
        // return NULL;
        exit (EXIT_FAILURE);
    }
    sp = tmp;
    memset (sp + *n, 0, *n * sizeof *sp); /* memset new ptrs 0 */
    *n *= 2;

    return sp;
}

/** realloc an array of pointers to int* setting memory to 0.
*  reallocate an array of integer arrays setting
*  newly allocated memory to 0 to allow iteration
*/
int **realloc_int (int **ip, size_t *n)
{
    int **tmp = realloc (ip, 2 * *n * sizeof *ip * 4);
    if (!tmp) {
        fprintf (stderr, "Error: struct reallocation failure.\n");
        // return NULL;
        exit (EXIT_FAILURE);
    }
    ip = tmp;
    memset (ip + *n, 0, *n * sizeof *ip * 4); /* memset new ptrs 0 */
    *n *= 2;

    return ip;
}

关于c - 如何根据每行末尾的值对文件行进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30246849/

相关文章:

c - 一键使用不同的参数多次运行应用程序

用于指定多个条件的 C++ 可变参数宏

c++ - 排序然后搜索( vector C++)

Matlab:如何读取以空格分隔的字符串但忽略单个空格(使用textscan)?

安卓文件选择器

c - 如何在代码块控制台中编写?

ios - 对 NSDictionary 的 NSArray 进行排序...未完全正常工作

python - 应该将学生分类为类(class)角色的代码错误

c# - 检测 File.Move 是否需要 'Copy -> Delete' 或只是改变文件系统表中的位置

c - 如果文件为空,我的代码将返回段错误,如果文件不为空,则返回段错误?