2015-05-31 35 views
0

我有一個程序,它接受用戶輸入並創建用戶輸入的幾個字段的記錄。要求用戶輸入人名,地址,城市,州,郵編和電話號碼的名字和姓氏。我試圖按照與每個記錄的城市相關的字母順序對記錄進行排序。我怎麼去解決這個問題,我非常難以理解如何基於一個變量進行排序,然後正確地打印整個記錄。如何對文件輸出進行排序?

#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; 
} 
+0

**建議**:使用'scanf(「%50s」,records-> fname);'以防止緩衝區溢出。你不需要''malloc()''返回值](http://stackoverflow.com/a/605858/1983495),但你必須檢查'malloc()'沒有返回NULL。 –

回答

2

AS是,你有列表結構,其不能與qsort()進行排序,但可以使用一個數組代替,並動態地通過使用malloc() + realloc()分配它。

你能夠使用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); 
+0

在鏈表上qsort? –

+0

@ A.S.H在我開始寫答案後,我回頭看看_array_的元素是如何計算的,突然間我發現它是一個鏈表,然後......我對自己說,哦,不,我已經完成了答案的寫作,儘管可能我會將其刪除,但這取決於OP對將其更改爲數組的建議的看法。 –

+0

我最初嘗試使用數組,但遇到問題並不斷出現訪問衝突,有人建議使用鏈接列表使同一文件上的多個記錄更容易打印。 – Karlioh

1

與大多數列表「新增」,通常很少有關於如何執行在您的列表實施中會做的很簡單的說明,其中是唯一的

在我們按照排序順序閱讀列表數據(在您的問題的城市中)之前,讓我們看看一些基本知識,這些基礎知識將有助於您的列表做任何事情。首先,幾乎總是這樣,將輸入保存/輸出例程分開。在你的情況下,你打開的文件保存在"wt"模式。每次您調用輸入函數時,都會清除文件中的所有現有數據,並只寫入您讀取的新值。雖然這對你的一次性輸入main很好,但這是不現實的。

此外,在處理列表時,您的代碼會相當快地變得相當長。試圖做到這一切在main將驅動你batty。這一定意味着創建一個函數來處理您將需要的不同列表操作。 (這將有助於使你的代碼更易於管理和讀取,將你現有的代碼移動到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是不是你的最佳選擇)。另外注意的函數將您的列表指針的地址(即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; 
    } 
} 

現在我們可以談談你的問題癥結。 如何按城市對列表數據進行排序?。正如你所發現的,沒有辦法去鏈接列表,雖然你可以將列表變成array of structs,然後qsort結構數組,但是將數據讀入列表的第二個副本也是一樣的容易在排序順序。這基本上只不過是修改你的read_records函數,以基於城市的字母順序插入記錄。有更優雅的方式將指針傳遞到一個通用的讀取功能以允許任何成員排序,但目的在這裏,一個單獨的函數來排序城市就足夠了:

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

示例使用/輸出

注:數據文件中讀取,可以作爲參數提供給程序,或者你可以選擇,輸入文件名。還要注意,代碼在退出時強制保存原始列表數據在新文件名下。這保持原始數據文件不變。 (你會promted進入退出新的文件名)

$ ./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 

有序輸出文件創建排序

$ 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 
上保存
+0

**注意:**上面,'scanf'用於使用'%m..'轉換說明符分配文件名。在較舊版本的'scanf'和窗口中,如果您收到警告或錯誤,則需要將'%a'替換爲'%m'。 –

相關問題