2017-10-09 78 views
1

讀人數不詳不知其長度,線的我是比較新的C編程,我試圖用fgets來讀取stdin輸入。從標準

首先,我首先想到了讀書最多50行,每行最多50個字符,並且有這樣的事情:

int max_length = 50; 
char lines[max_length][max_length]; 
char current_line[max_length]; 
int idx = 0; 

while(fgets(current_line, max_length, stdin) != NULL) { 
    strcopy(lines[idx], current_line); 
    idx++; 
} 

的片段上方成功地讀取輸入,並將其存儲到lines陣列在那裏我可以排序並打印出來。

我的問題是我該如何處理未知數量的行,每行的字符數量未知? (請記住,我將不得不排序行並將其打印出來)。

+3

使用'malloc()'/'realloc()'有一個明智的策略(例如,當你用完時的雙倍大小)......檢查換行符以確定該行是否完整。我認爲這個問題太廣泛了...... –

+0

[長度未知時獲取用戶輸入的最佳方法是什麼? (C)](https://stackoverflow.com/questions/46395682/best-way-to-get-user-input-when-length-is-unknown-c) –

+1

嘗試編碼這些目標之一「未知數每行的字符數量未知「。避免使這篇文章太寬泛。 – chux

回答

1

雖然已經回答了這個問題的一些不同變化,但是如何去做的考慮可以使用一個段落。遇到這個問題時,無論您使用哪種庫或POSIX函數組合,該方法都是相同的。

本質上,您將動態分配合理數量的字符來保存每一行。自動爲您直到'\n'字符閱讀如果你使用getline POSIX getline將做到這一點,利用fgets你可以簡單地看一個固定的緩衝區滿字符,並追加他們(在必要時重新分配存儲)(或達到EOF

,那麼你必須分配內存,並複製填充的緩衝區。否則,您將覆蓋以前的每一行讀取的行,並且當您嘗試使用free每行時,您可能會因爲您反覆嘗試釋放相同的內存塊而使用雙免費或損壞的SegFault。

您可以使用strdup來簡單地複製緩衝區。但是,由於strdup分配存儲空間,因此在爲您的行集合分配指向新內存塊的指針之前,應驗證成功分配。

要訪問每一行,您需要一個指向每個行的開始位置(持有每行的內存塊)。 A 通常使用指向字符指針的指針。 (例如char **lines;)內存分配通常是通過分配一些合理數量的指針開始處理的,跟蹤你使用的數字,當你達到你分配的數字時,你的指針數量增加一倍。

與每次讀取一樣,您需要驗證每個內存分配。 (每個malloc,callocrealloc)您還需要通過內存錯誤檢查程序(例如Linux的valgrind)來驗證程序使用您分配的內存的方式。它們使用簡單,只需valgrind yourexename

把這些碎片放在一起,你可以做類似於下面的事情。以下代碼將讀取作爲程序的第一個參數提供的文件名中的所有行(如果未提供參數,則默認爲stdin),並將行號和行打印到stdout(請記住,如果您在第50000行文件)

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

#define NPTR 8 

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

    size_t ndx = 0,    /* line index */ 
     nptrs = NPTR,   /* initial number of pointers */ 
     n = 0;     /* line alloc size (0, getline decides) */ 
    ssize_t nchr = 0;   /* return (no. of chars read by getline) */ 
    char *line = NULL,   /* buffer to read each line */ 
     **lines = NULL;   /* pointer to pointer to each line */ 
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin; 

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

    /* allocate/validate initial 'nptrs' pointers */ 
    if (!(lines = calloc (nptrs, sizeof *lines))) { 
     fprintf (stderr, "error: memory exhausted - lines.\n"); 
     return 1; 
    } 

    /* read each line with POSIX getline */ 
    while ((nchr = getline (&line, &n, fp)) != -1) { 
     if (nchr && line[nchr - 1] == '\n') /* check trailing '\n' */ 
      line[--nchr] = 0;    /* overwrite with nul-char */ 
     char *buf = strdup (line);   /* allocate/copy line */ 
     if (!buf) {  /* strdup allocates, so validate */ 
      fprintf (stderr, "error: strdup allocation failed.\n"); 
      break; 
     } 
     lines[ndx++] = buf;  /* assign start address for buf to lines */ 
     if (ndx == nptrs) {  /* if pointer limit reached, realloc */ 
      /* always realloc to temporary pointer, to validate success */ 
      void *tmp = realloc (lines, sizeof *lines * nptrs * 2); 
      if (!tmp) {   /* if realloc fails, bail with lines intact */ 
       fprintf (stderr, "read_input: memory exhausted - realloc.\n"); 
       break; 
      } 
      lines = tmp;  /* assign reallocted block to lines */ 
      /* zero all new memory (optional) */ 
      memset (lines + nptrs, 0, nptrs * sizeof *lines); 
      nptrs *= 2;   /* increment number of allocated pointers */ 
     } 
    } 
    free (line);     /* free memory allocated by getline */ 

    if (fp != stdin) fclose (fp); /* close file if not stdin */ 

    for (size_t i = 0; i < ndx; i++) { 
     printf ("line[%3zu] : %s\n", i, lines[i]); 
     free (lines[i]);   /* free memory for each line */ 
    } 
    free (lines);     /* free pointers */ 

    return 0; 
} 

如果你沒有getline,或strdup這樣做,你可以很容易地實現每個。網站上有多個例子。如果你找不到,請告訴我。如果您還有其他問題,請讓我知道。

1

檢出GetString函數找到here

+0

完全不是答案,而是評論。 – zerkms

+0

他必須有20位代表發表評論,所以他得到了通過,但他知道他何時得到20位代表,評論爲答案並且不合適。 –