當你有一個情況下,你都做了多的東西(就像讀2個文件),它使一個很大的意義,未雨綢繆。使用讀取2個文本文件所需的全部代碼,而不是將main
的主體弄糊塗,創建一個爲您讀取文本文件的函數,並讓它返回包含文件行的數組。這真的可以幫助你專注於你的代碼需要處理的線路的邏輯,而不是在首先獲得線路時填充空間。現在沒有什麼問題了,但是從可讀性,維護和程序結構的角度來看,這一切都變得更加困難。
如果您很好地構建了讀取功能,則可以將main
降低到以下值。這同時讀取文本文件轉換成字符數組,並提供了共4條線讀取的行數(加檢查,以確保您提供的兩個文件名來讀取):
int main (int argc, char **argv) {
if (argc < 3) {
fprintf (stderr, "error: insufficient input, usage: %s <filename1> <filename2>\n", argv[0]);
return 1;
}
size_t file1_size = 0; /* placeholders to be filled by readtxtfile */
size_t file2_size = 0; /* for general use, not needed to iterate */
/* read each file into an array of strings,
number of lines read, returned in file_size */
char **file1 = readtxtfile (argv[1], &file1_size);
char **file2 = readtxtfile (argv[2], &file2_size);
return 0;
}
在這一點上你把所有的數據,你可以處理你的關鍵字代碼。從文本文件中讀取是一件非常簡單的事情。你只需要熟悉可用的工具。當讀取文本的行時,首選的方法是使用行輸入一次將整行讀入緩衝區。然後解析以緩衝以獲得您需要的內容。行輸入工具是fgets
和getline
。一旦閱讀完該行後,您就可以使用像strtok
,strsep
或sscanf
這樣的工具來分隔您想要的行。作爲輸入的一部分,fgets
和getline
均在每行的末尾讀取newline
,因此您可能需要刪除newline
以滿足您的需求。
存儲每行讀取通常是通過聲明一個指向char *指針數組的指針來完成的。 (例如char **file1;
)然後,您可以爲某些初始指針數分配內存。 (在以下示例中爲NMAX
)然後,您訪問文件中的單個行爲file1_array[n]
,此時n
是該文件的行索引0 - lastline
。如果你有一個大文件並且超過你最初分配的指針數量,你只需要用realloc
重新分配你的數組的指針。 (您可以將NMAX
設置爲1,以使每行發生這種情況)
用來分配內存以及如何重新分配內存可以影響如何在程序中使用數組。仔細選擇calloc
來初始分配陣列,然後在使用memset
重新分配將所有未使用的指針設置爲0
(null)時,真的可以節省您的時間和頭痛嗎?爲什麼?因爲,你的陣列迭代,所有你需要做的是:
n = 0;
while (file1[n]) {
<do something with file1[n]>;
n++;
}
當你到達第一個未使用指針(即第一file1[n]
即0
),循環停止。
閱讀文本文件時另一個非常有用的功能是strdup (char *line)
。 strdup
將自動爲line
分配空間,使用malloc
,將line
複製到新分配的內存,並返回指向新內存塊的指針。這意味着,所有你需要做的,每個指針分配空間,並通過getline
複製準備行到你的數組是:
file1[n] = strdup (line);
這幾乎是它。您已經讀取了您的文件並填充了您的數組,並知道如何遍歷數組中的每一行。剩下的就是清理並釋放分配的內存,當你不再需要它時。通過確保您的未使用的指針是0
,這也是一個快速。您只需重複遍歷您的file1[n]
指針,隨時隨地釋放它們,然後在末尾處使用free (file1)
。你做完了。
這有很多事情要做,而且還有其他一些事情要做。在文件的初始讀取,你是否注意到,我們還聲明file1_size = 0;
變量,並將其地址傳遞給讀取功能:
char **file1 = readtxtfile (argv[1], &file1_size);
在readtxtfile
,在file1_size
地址的值是由每個1
遞增一次讀取一行。當readtxtfile
返回時,file1_size
包含讀取的行數。如圖所示,遍歷file1
數組並不需要這樣做,但您經常需要知道您讀過多少行。
爲了把它放在一起,我創建了一個簡短的函數示例來讀取兩個文本文件,打印兩行文本並釋放與文件數組關聯的內存。這個解釋最終比我預想的要長。因此,花點時間瞭解它的工作原理,並且您將更輕鬆地處理文本文件。下面的代碼將2名作爲參數(如./progname file1 file2
)類似於gcc -Wall -Wextra -o progname srcfilename.c
東西編譯:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NMAX 256
char **readtxtfile (char *fn, size_t *idx);
char **realloc_char (char **p, size_t *n);
void prn_chararray (char **ca);
void free_chararray (char **ca);
int main (int argc, char **argv) {
if (argc < 3) {
fprintf (stderr, "error: insufficient input, usage: %s <filename1> <filename2>\n", argv[0]);
return 1;
}
size_t file1_size = 0; /* placeholders to be filled by readtxtfile */
size_t file2_size = 0; /* for general use, not needed to iterate */
/* read each file into an array of strings,
number of lines read, returned in file_size */
char **file1 = readtxtfile (argv[1], &file1_size);
char **file2 = readtxtfile (argv[2], &file2_size);
/* simple print function */
if (file1) prn_chararray (file1);
if (file2) prn_chararray (file2);
/* simple free memory function */
if (file1) free_chararray (file1);
if (file2) free_chararray (file2);
return 0;
}
char** readtxtfile (char *fn, size_t *idx)
{
if (!fn) return NULL; /* validate filename provided */
char *ln = NULL; /* NULL forces getline to allocate */
size_t n = 0; /* max chars to read (0 - no limit) */
ssize_t nchr = 0; /* number of chars actually read */
size_t nmax = NMAX; /* check for reallocation */
char **array = NULL; /* array to hold lines read */
FILE *fp = NULL; /* file pointer to open file fn */
/* open/validate file */
if (!(fp = fopen (fn, "r"))) {
fprintf (stderr, "%s() error: file open failed '%s'.", __func__, fn);
return NULL;
}
/* allocate NMAX pointers to char* */
if (!(array = calloc (NMAX, sizeof *array))) {
fprintf (stderr, "%s() error: memory allocation failed.", __func__);
return NULL;
}
/* read each line from fp - dynamicallly allocated */
while ((nchr = getline (&ln, &n, fp)) != -1)
{
/* strip newline or carriage rtn */
while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r'))
ln[--nchr] = 0;
array[*idx] = strdup (ln); /* allocate/copy ln to array */
(*idx)++; /* increment value at index */
if (*idx == nmax) /* if lines exceed nmax, reallocate */
array = realloc_char (array, &nmax);
}
if (ln) free (ln); /* free memory allocated by getline */
if (fp) fclose (fp); /* close open file descriptor */
return array;
}
/* print an array of character pointers. */
void prn_chararray (char **ca)
{
register size_t n = 0;
while (ca[n])
{
printf (" arr[%3zu] %s\n", n, ca[n]);
n++;
}
}
/* free array of char* */
void free_chararray (char **ca)
{
if (!ca) return;
register size_t n = 0;
while (ca[n])
free (ca[n++]);
free (ca);
}
/* 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 **p, size_t *n)
{
char **tmp = realloc (p, 2 * *n * sizeof *p);
if (!tmp) {
fprintf (stderr, "%s() error: reallocation failure.\n", __func__);
// return NULL;
exit (EXIT_FAILURE);
}
p = tmp;
memset (p + *n, 0, *n * sizeof *p); /* memset new ptrs 0 */
*n *= 2;
return p;
}
Valgrind的 - 不要忘記檢查泄漏
最後,任何時候你分配內存在你的代碼中,確保你使用了一個內存檢查器,例如valgrind
來確認你沒有內存錯誤,並確認你沒有內存泄漏(即已經忘記釋放或者已經無法訪問的已分配塊)。 valgrind
使用簡單,只需valgrind ./progname [any arguments]
。它可以提供豐富的信息。例如,在此閱讀例如:
$ valgrind ./bin/getline_readfile_fn voidstruct.c wii-u.txt
==14690== Memcheck, a memory error detector
==14690== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==14690== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==14690== Command: ./bin/getline_readfile_fn voidstruct.c wii-u.txt
==14690==
<snip - program output>
==14690==
==14690== HEAP SUMMARY:
==14690== in use at exit: 0 bytes in 0 blocks
==14690== total heap usage: 61 allocs, 61 frees, 6,450 bytes allocated
==14690==
==14690== All heap blocks were freed -- no leaks are possible
==14690==
==14690== For counts of detected and suppressed errors, rerun with: -v
==14690== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
要特別注意線路:
==14690== All heap blocks were freed -- no leaks are possible
和
==14690== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
可以忽略(suppressed: 2 from 2)
剛剛表明我沒有爲libc安裝的開發文件。
那麼,你已經想出瞭如何打開文件。也許下一步應該實際上是從打開的文件中讀取某些內容... – twalberg 2015-04-03 19:39:27
是的,我已經取得了一些進展@twalberg我會將其添加到問題 – Jude 2015-04-03 19:43:51
您可以做一個哈希表:從一個文件中讀取所有單詞並將它們存儲作爲散列表的鍵。然後,對於這些值,您可以通過第二個文件並從該文件中提取單詞,並將它們與哈希表中的鍵進行比較,如果匹配,則只需向該值添加一個。或者,如果這太困難了,你可以嘗試使用一個鏈表或一個數組,並基本上做同樣的事情。 – 2015-04-03 19:50:20