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

时间:2015-05-14 20:34:46

标签: 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;
}

2 个答案:

答案 0 :(得分:2)

从注释继续,您可以将行读入一个结构(包含行和一个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静态分配的数组

以下是使用两个2D数组的示例,一个用于lines,另一个用于保存原始行索引和行尾的数字。与下面动态分配的示例不同,此示例仅限于从文件中读取MAXL行或每行不超过MAXS个字符。如果一行长度恰好为MAXS个字符(包括空终止符),则必须将其丢弃,因为无法知道结尾处的数字是否仍然有效。包含行索引和末尾数字的2D数组根据末尾的数字进行排序,然后根据原始行索引打印行,从而导致行按编号顺序打印。虽然这可能看起来更简单,但它比使用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个整数)的2D数组。然后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;
}

答案 1 :(得分:0)

您可以将整个文件读入单个缓冲区,创建一个结构数组,其中包含指向行的指针和每行末尾的值(扫描换行符),然后按值对结构数组进行排序,以及根据排序的结构数组中的指针输出数据。