如何排序文件输出?

时间:2015-05-31 01:13:33

标签: c file sorting struct

我有一个程序,它接受用户输入并创建包含用户输入的几个字段的记录。要求用户输入人员,地址,城市,州,邮政编码和电话号码的名字和姓氏。我试图按照每个记录的城市的字母顺序对记录进行排序。我将如何解决这个问题,我对如何根据一个变量排序然后正确打印整个记录感到困惑。

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

typedef struct Record Record;

struct Record
    {
        char fname[51];
        char lname[51];
        char address[51];
        char city[51];
        char state[51];
        char zipcode[51];
        char phoneNumber[51];

        Record *next;
    };


int main()
{
    FILE *fileWriter;
    const char filename[] = "data.txt";
    char answer = '\0';
    Record *records = NULL;
    Record *records_first = NULL;
    Record *records_previous = NULL;

    fileWriter = fopen(filename,"wt");

    if(fileWriter != NULL) {

        for( ; ; ) {
            records = (Record*) malloc(sizeof(Record));  

            if(records_first == NULL)
                records_first = records;

            if(records_previous != NULL)
                records_previous->next = records;

            records = records_first;
            printf("First Name: \n");
            scanf("%s", records->fname);
            fprintf(fileWriter,"%s\t",records->fname);

            printf("Last Name: \n");
            scanf("%s", records->lname);
            fprintf(fileWriter,"%s\t",records->lname);

            printf("Address: \n");
            scanf(" %[^\n]", records->address);
            fprintf(fileWriter,"%s\t",records->address);

            printf("City: \n");
            scanf("%s", records->city);
            fprintf(fileWriter,"%s\t",records->city);

            printf("State: \n");
            scanf("%s", records->state);
            fprintf(fileWriter,"%s\t",records->state);

            printf("Zipcode: \n");
            scanf("%s", records->zipcode);
            fprintf(fileWriter,"%s\t",records->zipcode);

            printf("Phone Number: \n");
            scanf("%s", records->phoneNumber);
            fprintf(fileWriter,"%s\t\n",records->phoneNumber);

            records->next = NULL;
            records_previous = records;

            printf("Are there anymore records? [y/n] ");
            scanf(" %c", &answer);

            if(tolower(answer) != 'y') {
                free(records);
                fclose(fileWriter);
                break;
            }
        }

    } else
        printf("Error opening file.");

    return 0;
}

                        **Edited Version**

我尝试使用qsort()。但后来又出现了致命的错误。最重要的是,当我只能对一个字段进行排序时,如何正确打印整个记录?

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

struct Record
    {
        char fname[51];
        char lname[51];
        char address[51];
        char city[51];
        char state[51];
        int zipcode;
        int phoneNumber;
    };

int compare_city(const void *const p1, const void *const p2)
 {
    struct Record *r1 = (struct Record *) p1;
    struct Record *r2 = (struct Record *) p1;

    return strcmp(r1->city, r2->city);
 }


int main()
{
    FILE *fileWriter;
    const char filename[] = "data.txt";
    char answer = 'y';
    int size = 1;
    int i = 0;
    int count = 1;
    struct Record *records = NULL;
    struct Record *records_temp = NULL;


    fileWriter = fopen(filename,"wb");
    if(fileWriter != NULL)
        while(answer == 'y' || answer == 'Y')
        {
            if(records_temp == NULL)
            {
                struct Record *records_temp = realloc(records,(size)*sizeof(*records));
            }

            records = records_temp;
            printf("First Name: \n");
            scanf("%s", records[i].fname);


            printf("Last Name: \n");
            scanf("%s", records[i].lname);


            printf("Address: \n");
            scanf(" %[^\n]", records[i].address);


            printf("City: \n");
            scanf("%s", records[i].city);


            printf("State: \n");
            scanf("%s", records[i].state);


            printf("Zipcode: \n");
            scanf("%s", records[i].zipcode);


            printf("Phone Number: \n");
            scanf("%s", records[i].phoneNumber);

            //stores all record info

            printf("Are there anymore records? [y/n] ");
            scanf(" %c", &answer);


        if(tolower(answer) == 'y')
        {
            i++;
            count++;
        }

        for(i = 0; i < count ; i++)
        {
            qsort(records, count, sizeof(struct Record), compare_city);
            fprintf(fileWriter,"%s\n",records[i].fname);
            fprintf(fileWriter,"%s\n",records[i].lname);
            fprintf(fileWriter,"%s\n",records[i].address);
            fprintf(fileWriter,"%s\n",records[i].city);
            fprintf(fileWriter,"%s\n",records[i].state);
            fprintf(fileWriter,"%d\n",records[i].zipcode);
            fprintf(fileWriter,"%d\n",records[i].phoneNumber);
        }

        free(records);
    }
    return 0;
}

2 个答案:

答案 0 :(得分:2)

按原样,您有一个列表结构,无法使用qsort()进行排序,但您可以使用数组,并使用malloc() + realloc()动态分配它。< / p>

要对可以使用qsort()的条目进行排序,例如假设您要按名字排序,那么

int compare_first_name(const void *const p1, const void *const p2)
 {
    struct Record *r1 = (struct Record *) p1;
    struct Record *r2 = (struct Record *) p1;

    return strcmp(r1->fname, r2->fname);
 }

然后

qsort(base, count, sizeof(struct Record), compare_first_name);

答案 1 :(得分:1)

与大多数列表和#34;添加内容一样,通常很少有快速解释如何在列表实现中执行唯一的操作。

在我们查看按排序顺序(按您的问题中的城市)阅读列表数据之前,让我们看一些有助于对您的列表执行任何操作的基础知识。首先,并且几乎总是如此,将输入保存/输出例程分开。在您的情况下,您打开文件以便以"wt"模式保存。这意味着每次调用输入函数时,都会清除文件中的所有现有数据,并只写入您读取的新值。虽然这对main中的一次性输入很好,但这很难实现。

此外,在处理列表时,您的代码会相当快地增长。试图在main中完成这一切会让你感到沮丧。这必然意味着创建一个函数来处理您需要的不同列表操作。 (这将有助于使您的代码更易于管理和阅读。将现有代码移动到insert_records以处理来自stdin的收集输入将会这样做。输入处理的一个示例转移到函数中修剪的文件输出如下:

size_t insert_records (Record **records)
{
    // FILE *fileWriter;
    // const char filename[] = "dat/lldata.txt";
    char answer = 0;
    // Record *records = NULL;
    // Record *records_first = NULL;
    // Record *records_previous = NULL;
    Record *iter = NULL;
    size_t cnt = 0;
/*
    if (!(*filename)) {
        printf ("\nEnter filename for list data: ");
        scanf (" %m[^\n]%*c", filename);
    }

    if (!(fileWriter = fopen (*filename, "at"))) {
        fprintf (stderr, "%s() error: invalid filename '%s' (file not found).\n", 
                __func__, *filename);
        return 0;
    }
*/
    if (*records) {
        iter = *records;
        while (iter->next) iter = iter->next;
    }

    for (;;) 
    {
        Record *rec = malloc (sizeof *rec);     /* use malloc correctly */

        if (!rec) {
            fprintf (stderr, "%s() error: memory exhausted.\n", __func__);
            return 0;
        }

        printf ("\n  First Name: ");
        scanf (" %[^\n]%*c", rec->fname);    /* fix scanf format strings */
        // fprintf (fileWriter, "%s\t", rec->fname);

        printf ("   Last Name: ");
        scanf ("%[^\n]%*c", rec->lname);
        // fprintf (fileWriter, "%s\t", rec->lname);

        printf ("     Address: ");
        scanf ("%[^\n]%*c", rec->address);
        // fprintf (fileWriter, "%s\t", rec->address);

        printf ("        City: ");
        scanf ("%[^\n]%*c", rec->city);
        // fprintf (fileWriter, "%s\t", rec->city);

        printf ("       State: ");
        scanf ("%[^\n]%*c", rec->state);
        // fprintf (fileWriter, "%s\t", rec->state);

        printf ("     Zipcode: ");
        scanf ("%[^\n]%*c", rec->zipcode);
        // fprintf (fileWriter, "%s\t", rec->zipcode);

        printf ("Phone Number: ");
        scanf ("%[^\n]%*c", rec->phoneNumber);
        // fprintf (fileWriter, "%s\t\n", rec->phoneNumber);

        rec->next = NULL;

        if (!*records) {
            iter = *records = rec;
        } else {
            iter->next = rec;
            iter = iter->next;
        }

        cnt++;

        printf ("\nEnter additional records? [y/n] ");
        scanf (" %c%*c", &answer);

        if (answer == 'n' || answer == 'N') { /* why include ctype.h for this? */
            // free (records);
            // fclose (fileWriter);
            break;
        }
    }

    return cnt;
}

注意返回类型已声明为size_t,因此您可以返回成功输入的记录数(它永远不会是负数,因此int不是&#39 ;你最好的选择)。此外注意该函数将列表指针的地址(即Record **records)作为每次更改列表中第一个(起始)节点时所需的参数(除非您使用)一个单独的虚指针作为具有不同地址的第一个节点)。

要将列表保存到文件,单独的例程可以提供更好的防止意外数据覆盖的保护。只需要一个小的save_list功能。 (注意 filename指针地址的传递方式与上面的records类似,因此可以在函数本身中进行更改和更新。

size_t save_list (Record *rec, char **filename)
{
    if (!rec) {
        fprintf (stderr, "%s() error: list is empty.\n", __func__);
        return 0;
    }

    FILE *fp = NULL;
    Record *iter = rec;
    size_t cnt = 0;

    if (!(*filename)) {
        printf ("\nEnter filename for list data: ");
        scanf (" %m[^\n]%*c", filename);
    }

    if (!(fp = fopen (*filename, "wt"))) {
        fprintf (stderr, "%s() error: invalid filename '%s' (file not found).\n", 
                __func__, *filename);
        return 0;
    }

    for (; iter; iter = (iter->next ? iter->next : NULL))
    {
        fprintf (fp, "%s", iter->fname);
        fprintf (fp, "\t%s", iter->lname);
        fprintf (fp, "\t%s", iter->address);
        fprintf (fp, "\t%s", iter->city);
        fprintf (fp, "\t%s", iter->state);
        fprintf (fp, "\t%s", iter->zipcode);
        fprintf (fp, "\t%s\n", iter->phoneNumber);

        cnt++;
    }

    fclose (fp);

    return cnt;
}

将数据保存到文件几乎没用,除非您可以将其实际读回到程序中。由于我们将基于将数据读入列表的第二个副本进行排序,因此将数据读回到程序中的示例输入例程可能是:

size_t read_records (Record **records, char **filename)
{
    FILE *fp = NULL;
    Record *iter = NULL;
    size_t cnt = 0;

    if (!(*filename)) {
        printf ("\nEnter filename for list data: ");
        scanf (" %m[^\n]%*c", filename);
    }

    if (!(fp = fopen (*filename, "r"))) {
        fprintf (stderr, "%s() error: invalid filename '%s' (file not found).\n", 
                __func__, *filename);
        if (*filename) free (*filename);    /* prevent returning invalid name */
        *filename = NULL;
        return 0;
    }

    if (*records) {
        iter = *records;
        while (iter->next) iter = iter->next;
    }

    for (;;)
    {
        Record *rec = malloc (sizeof *rec);
        if (!rec) {
            fprintf (stderr, "%s() error: memory exhausted.\n", __func__);
            return 0;
        }

        if (fscanf (fp, " %[^\t] %[^\t] %[^\t] %[^\t] %[^\t] %[^\t] %[^\n]%*c",
                rec->fname, rec->lname, rec->address, rec->city, rec->state,
                rec->zipcode, rec->phoneNumber) != 7)
        {
            free (rec);
            break;
        }

        rec->next = NULL;

        if (!*records) {
            iter = *records = rec;
        } else {
            iter->next = rec;
            iter = iter->next;
        }

        cnt++;
    }

    fclose (fp);

    return cnt;
}

将数据读入列表后,有一些方法可以查看它:

void prn_records (Record *records)
{
    if (!records) return;

    Record *iter = records;
    size_t cnt = 0;

    while (iter) {
        printf ("\n    record[%3zu]:\n\n", cnt);
        printf ("\t%s, %s\n", iter->lname, iter->fname);
        printf ("\t%s\n", iter->address);
        printf ("\t%s, %s %s\n", iter->city, iter->state, iter->zipcode);
        printf ("\t%s\n", iter->phoneNumber);
        cnt++;
        iter = iter->next;
    }
}

现在我们可以转向你问题的关键。 如何按城市对列表数据进行排序?。正如您所知,没有办法qsort链接列表,而您可以将列表转换为array of structs然后qsort结构数组,它就像易于以排序顺序将数据读入列表的第二个副本。这基本上只是修改您的read_records功能,根据城市按字母顺序插入记录。有一些更优雅的方法可以将指针传递给通用读取函数以允许对任何成员进行排序,但是出于此目的,单独使用 city 排序的函数就足够了:

size_t read_city_sorted (Record **records, char **filename)
{
    FILE *fp = NULL;
    Record *iter = NULL;
    size_t cnt = 0;
    size_t inserted = 0;

    if (!(*filename)) {
        printf ("\nEnter filename for list data: ");
        scanf (" %m[^\n]%*c", filename);
    }

    if (!(fp = fopen (*filename, "r"))) {
        fprintf (stderr, "%s() error: invalid filename '%s' (file not found).\n", 
                __func__, *filename);
        if (*filename) free (*filename);    /* prevent returning invalid name */
        *filename = NULL;
        return 0;
    }

    for (;;)
    {
        inserted = 0;
        Record *rec = malloc (sizeof *rec);
        if (!rec) {
            fprintf (stderr, "%s() error: memory exhausted.\n", __func__);
            return 0;
        }
        rec->next = NULL;

        if (fscanf (fp, " %[^\t] %[^\t] %[^\t] %[^\t] %[^\t] %[^\t] %[^\n]%*c",
                rec->fname, rec->lname, rec->address, rec->city, rec->state,
                rec->zipcode, rec->phoneNumber) != 7)
        {
            free (rec);
            break;
        }

        if (!*records) {    /* if no records insert as first */
            *records = rec;
        } else 
        {
            iter = *records;
            /* use strcmp to find location of city in sorted list */
            while ((strcmp (iter->city, rec->city) < 0) && iter->next) 
            {   
                /* check if alphetical order between iter & iter->next */
                if (strcmp (rec->city, iter->next->city) < 0) 
                {
                    rec->next = iter->next; /* insert in order      */
                    iter->next = rec;
                    inserted = 1;           /* set inserted flag    */
                    break;
                }

                iter = iter->next;
            }

            if (!inserted) {
                if (iter == *records) {     /* insert at beginning  */
                    rec->next = *records;
                    *records = rec;
                }
                else {                      /* insert at end        */
                    iter->next = rec;
                }
            }
        }

        cnt++;
    }

    fclose (fp);

    return cnt;
}

现在列表操作的令人沮丧的部分是有许多小细节,将拼图的各个部分放在一起,没有一些工作示例,上面的函数就是函数。为了帮助解释,我整理了一个小的驱动程序来将各个部分组合在一起(由于必要的小部件,它们比最初计划的时间长得多)。代码被注释,最后有几个注释。消化它,如果您有任何问题,请告诉我。

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

typedef struct Record Record;

struct Record {             /* static arrays are fine, but inefficient  */
    char fname[51];
    char lname[51];
    char address[51];
    char city[51];
    char state[51];
    char zipcode[51];
    char phoneNumber[51];   /* avoid mixed caPs (camelCase) in C */

    Record *next;           /* avoid initial Caps (not a hanging offence) */
};

size_t insert_records (Record **records);
size_t read_records (Record **records, char **filename);
size_t read_city_sorted (Record **records, char **filename);
size_t save_list (Record *rec, char **filename);
void prn_records (Record *records);
void free_records (Record *rec);

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

    Record *records = NULL; /* list pointer for linked-list */
    Record *sorted = NULL;  /* list pointer for sorted linked-list */
    char *datafile = argc > 1 ? strdup (argv[1]) : NULL;
    char c = 0;
    size_t numrec = 0;      /* number of records in list */
    size_t sortrec = 0;     /* number of records in sorted list     */

    char *fname = NULL;     /* allow save in new filename   */
    char *sfname = NULL;    /* save sorted list in separate filename */

    if (datafile)       /* if filename given on command line, read */
        numrec = read_records (&records, &datafile);

    for (;;)
    {   /* quick menu for list operations */
        printf ("\nSelect operation from list, 'q' when done:\n\n");
        printf ("\t1)  Insert Records Manually\n");
        printf ("\t2)  Read Records from File\n");
        printf ("\t3)  Read/Print Records from File (sorted on city)\n");
        printf ("\t4)  Show Number of Records in list\n");
        printf ("\t5)  Show Number of Records (sorted list)\n");
        printf ("\t6)  Print Records\n");
        printf ("\t7)  Print Sorted Records (on city)\n");
        printf ("\t8)  Save Records to File\n");
        printf ("\t9)  Save (sorted ) Records to File\n");
        printf ("\tq)  Quit\n");
        printf ("\n    selection: ");
        scanf (" %c%*c", &c);

        if (c == 'q' || c == 'Q') break;

        switch (c)
        {
            case '1' : numrec += insert_records (&records);
                break;
            case '2' : numrec += read_records (&records, &datafile);
                break;
            case '3' : sortrec = read_city_sorted (&sorted, &datafile);
                break;
            case '4' : printf ("\n  The list contains '%zu' records\n", numrec);
                break;
            case '5' : printf ("\n  The (sorted list) contains '%zu' records\n", sortrec);
                break;
            case '6' : prn_records (records);
                break;
            case '7' : prn_records (sorted);
                break;
            case '8' : save_list (records, &fname);
                break;
            case '9' : save_list (sorted, &sfname);
                break;
            default  : printf ("\n error: invalid selection\n");
                break;
        }
    }

    if (sorted) free_records (sorted);  /* no forced save of sorted, up to you  */

    if (records) {
        save_list (records, &fname);    /* force save before free, save in new  */
        free_records (records);         /* fname to keep original datafile      */
    }
    if (fname) free (fname);
    if (sfname) free (sfname);
    if (datafile) free (datafile);

    return 0;
}

size_t read_records (Record **records, char **filename)
{
    FILE *fp = NULL;
    Record *iter = NULL;
    size_t cnt = 0;

    if (!(*filename)) {
        printf ("\nEnter filename for list data: ");
        scanf (" %m[^\n]%*c", filename);
    }

    if (!(fp = fopen (*filename, "r"))) {
        fprintf (stderr, "%s() error: invalid filename '%s' (file not found).\n", 
                __func__, *filename);
        if (*filename) free (*filename);    /* prevent returning invalid name */
        *filename = NULL;
        return 0;
    }

    if (*records) {
        iter = *records;
        while (iter->next) iter = iter->next;
    }

    for (;;)
    {
        Record *rec = malloc (sizeof *rec);
        if (!rec) {
            fprintf (stderr, "%s() error: memory exhausted.\n", __func__);
            return 0;
        }

        if (fscanf (fp, " %[^\t] %[^\t] %[^\t] %[^\t] %[^\t] %[^\t] %[^\n]%*c",
                rec->fname, rec->lname, rec->address, rec->city, rec->state,
                rec->zipcode, rec->phoneNumber) != 7)
        {
            free (rec);
            break;
        }

        rec->next = NULL;

        if (!*records) {
            iter = *records = rec;
        } else {
            iter->next = rec;
            iter = iter->next;
        }

        cnt++;
    }

    fclose (fp);

    return cnt;
}

size_t read_city_sorted (Record **records, char **filename)
{
    FILE *fp = NULL;
    Record *iter = NULL;
    size_t cnt = 0;
    size_t inserted = 0;

    if (!(*filename)) {
        printf ("\nEnter filename for list data: ");
        scanf (" %m[^\n]%*c", filename);
    }

    if (!(fp = fopen (*filename, "r"))) {
        fprintf (stderr, "%s() error: invalid filename '%s' (file not found).\n", 
                __func__, *filename);
        if (*filename) free (*filename);    /* prevent returning invalid name */
        *filename = NULL;
        return 0;
    }

    for (;;)
    {
        inserted = 0;
        Record *rec = malloc (sizeof *rec);
        if (!rec) {
            fprintf (stderr, "%s() error: memory exhausted.\n", __func__);
            return 0;
        }
        rec->next = NULL;

        if (fscanf (fp, " %[^\t] %[^\t] %[^\t] %[^\t] %[^\t] %[^\t] %[^\n]%*c",
                rec->fname, rec->lname, rec->address, rec->city, rec->state,
                rec->zipcode, rec->phoneNumber) != 7)
        {
            free (rec);
            break;
        }

        if (!*records) {    /* if no records insert as first */
            *records = rec;
        } else 
        {
            iter = *records;
            /* use strcmp to find location of city in sorted list */
            while ((strcmp (iter->city, rec->city) < 0) && iter->next) 
            {   
                /* check if alphetical order between iter & iter->next */
                if (strcmp (rec->city, iter->next->city) < 0) 
                {
                    rec->next = iter->next; /* insert in order      */
                    iter->next = rec;
                    inserted = 1;           /* set inserted flag    */
                    break;
                }

                iter = iter->next;
            }

            if (!inserted) {
                if (iter == *records) {     /* insert at beginning  */
                    rec->next = *records;
                    *records = rec;
                }
                else {                      /* insert at end        */
                    iter->next = rec;
                }
            }
        }

        cnt++;
    }

    fclose (fp);

    return cnt;
}

size_t insert_records (Record **records)
{
    // FILE *fileWriter;
    // const char filename[] = "dat/lldata.txt";
    char answer = 0;
    // Record *records = NULL;
    // Record *records_first = NULL;
    // Record *records_previous = NULL;
    Record *iter = NULL;
    size_t cnt = 0;
/*
    if (!(*filename)) {
        printf ("\nEnter filename for list data: ");
        scanf (" %m[^\n]%*c", filename);
    }

    if (!(fileWriter = fopen (*filename, "at"))) {
        fprintf (stderr, "%s() error: invalid filename '%s' (file not found).\n", 
                __func__, *filename);
        return 0;
    }
*/
    if (*records) {
        iter = *records;
        while (iter->next) iter = iter->next;
    }

    for (;;) 
    {
        Record *rec = malloc (sizeof *rec);     /* use malloc correctly */

        if (!rec) {
            fprintf (stderr, "%s() error: memory exhausted.\n", __func__);
            return 0;
        }

        printf ("\n  First Name: ");
        scanf (" %[^\n]%*c", rec->fname);    /* fix scanf format strings */
        // fprintf (fileWriter, "%s\t", rec->fname);

        printf ("   Last Name: ");
        scanf ("%[^\n]%*c", rec->lname);
        // fprintf (fileWriter, "%s\t", rec->lname);

        printf ("     Address: ");
        scanf ("%[^\n]%*c", rec->address);
        // fprintf (fileWriter, "%s\t", rec->address);

        printf ("        City: ");
        scanf ("%[^\n]%*c", rec->city);
        // fprintf (fileWriter, "%s\t", rec->city);

        printf ("       State: ");
        scanf ("%[^\n]%*c", rec->state);
        // fprintf (fileWriter, "%s\t", rec->state);

        printf ("     Zipcode: ");
        scanf ("%[^\n]%*c", rec->zipcode);
        // fprintf (fileWriter, "%s\t", rec->zipcode);

        printf ("Phone Number: ");
        scanf ("%[^\n]%*c", rec->phoneNumber);
        // fprintf (fileWriter, "%s\t\n", rec->phoneNumber);

        rec->next = NULL;

        if (!*records) {
            iter = *records = rec;
        } else {
            iter->next = rec;
            iter = iter->next;
        }

        cnt++;

        printf ("\nEnter additional records? [y/n] ");
        scanf (" %c%*c", &answer);

        if (answer == 'n' || answer == 'N') { /* why include ctype.h for this? */
            // free (records);
            // fclose (fileWriter);
            break;
        }
    }

    return cnt;
}

void prn_records (Record *records)
{
    if (!records) return;

    Record *iter = records;
    size_t cnt = 0;

    while (iter) {
        printf ("\n    record[%3zu]:\n\n", cnt);
        printf ("\t%s, %s\n", iter->lname, iter->fname);
        printf ("\t%s\n", iter->address);
        printf ("\t%s, %s %s\n", iter->city, iter->state, iter->zipcode);
        printf ("\t%s\n", iter->phoneNumber);
        cnt++;
        iter = iter->next;
    }
}

size_t save_list (Record *rec, char **filename)
{
    if (!rec) {
        fprintf (stderr, "%s() error: list is empty.\n", __func__);
        return 0;
    }

    FILE *fp = NULL;
    Record *iter = rec;
    size_t cnt = 0;

    if (!(*filename)) {
        printf ("\nEnter filename for list data: ");
        scanf (" %m[^\n]%*c", filename);
    }

    if (!(fp = fopen (*filename, "wt"))) {
        fprintf (stderr, "%s() error: invalid filename '%s' (file not found).\n", 
                __func__, *filename);
        return 0;
    }

    for (; iter; iter = (iter->next ? iter->next : NULL))
    {
        fprintf (fp, "%s", iter->fname);
        fprintf (fp, "\t%s", iter->lname);
        fprintf (fp, "\t%s", iter->address);
        fprintf (fp, "\t%s", iter->city);
        fprintf (fp, "\t%s", iter->state);
        fprintf (fp, "\t%s", iter->zipcode);
        fprintf (fp, "\t%s\n", iter->phoneNumber);

        cnt++;
    }

    fclose (fp);

    return cnt;
}

void free_records (Record *rec)
{
    if (!rec) {
        fprintf (stderr, "%s() error: list is empty.\n", __func__);
        return;
    }

    Record *iter = rec;
    Record *victim = NULL;

    while (iter) 
    {
        victim = iter;
        iter = iter->next;
        if (victim) free (victim);
    }
}

示例使用/输出

注意:要读取的数据文件可以作为程序的参数提供,也可以选择2) Read Records from File并输入文件名。另请注意,代码强制在退出时以新文件名保存原始列表数据。这样可以保持原始数据文件不变。 (您将被要求在退出时输入新文件名)

$ ./bin/ll_ins_sort dat/lldata.txt

Select operation from list, 'q' when done:

        1)  Insert Records Manually
        2)  Read Records from File
        3)  Read/Print Records from File (sorted on city)
        4)  Show Number of Records in list
        5)  Show Number of Records (sorted list)
        6)  Print Records
        7)  Print Sorted Records (on city)
        8)  Save Records to File
        9)  Save (sorted ) Records to File
        q)  Quit

    selection: 3

<_snipped menu_>

    selection: 7

    record[  0]:

        James, George
        32 Jones Place
        Billings, Montana 30412
        901 992-2165

    record[  1]:

        Doe, Jane
        459 35th Street
        Bridge City, Colorado 78763
        303 534-6734

    record[  2]:

        Mayer, Alphred
        222 Two Lane
        Chemco, Texas 77722
        713 555-1212

    record[  3]:

        Jones, Jill
        4312 Meandering Way
        Dallas, Texas 75248
        214 789-5391

    record[  4]:

        Barnes, Bill
        227 North Street
        Moosejaw, Maine 10103
        312 832-2189

    record[  5]:

        Early, Robert
        13 Sunrise Ln.
        Sunset, California 80210
        505 555-1212

<_snipped menu_>

    selection: 9

Enter filename for list data: dat/lldatasort.txt

<_snipped menu_>

    selection: q

Enter filename for list data: dat/lldatanew.txt

原始输入(使用input_records创建)

$ cat dat/lldata.txt
Alphred Mayer   222 Two Lane    Chemco  Texas   77722   713 555-1212
George  James   32 Jones Place  Billings        Montana 30412   901 992-2165
Bill    Barnes  227 North Street        Moosejaw        Maine   10103   312 832-2189
Jane    Doe     459 35th Street Bridge City     Colorado        78763   303 534-6734
Jill    Jones   4312 Meandering Way     Dallas  Texas   75248   214 789-5391
Robert  Early   13 Sunrise Ln.  Sunset  California      80210   505 555-1212

按保存已排序<= strong>

创建的排序输出文件
$ cat dat/lldatasort.txt
George  James   32 Jones Place  Billings        Montana 30412   901 992-2165
Jane    Doe     459 35th Street Bridge City     Colorado        78763   303 534-6734
Alphred Mayer   222 Two Lane    Chemco  Texas   77722   713 555-1212
Jill    Jones   4312 Meandering Way     Dallas  Texas   75248   214 789-5391
Bill    Barnes  227 North Street        Moosejaw        Maine   10103   312 832-2189
Robert  Early   13 Sunrise Ln.  Sunset  California      80210   505 555-1212