簡體   English   中英

fgetc():讀取和存儲未知長度的字符串

[英]fgetc(): Reading and storing a string of unknown length

我需要做的任務是:

  • 打開一個文件(使用fopen())
  • 讀取學生的名字(使用fgetc())
  • 將該名稱存儲在結構的某個部分中

我遇到的問題是我需要讀取一個任意長的字符串到名稱,我不知道如何存儲該字符串而不浪費內存(或寫入未分配的內存)。

編輯

我的第一個想法是分配一個1字節(字符)內存塊,然后調用realloc()如果需要更多字節,但這似乎不是很有效。 或者,如果數組已滿,我可以將數組加倍,然后在最后將字符復制到一個具有確切大小的新內存塊中。

不要擔心浪費100或1000字節,這可能對所有名稱都足夠長。 我可能只是將你正在閱讀的緩沖區放入堆棧中。

不要擔心寫在緩沖區的末尾。 即緩沖區溢出。 程序防止這種情況!

當您將名稱存儲到結構中時,可以使用malloc緩沖區來存儲名稱所需的確切長度(不要忘記為null終止符添加額外的字節)。

但如果你真的必須存儲任何長度的名字,那么你可以用realloc來做。 即分配一個大小為50字節的malloc的緩沖區。

然后當你需要更多空間時,使用realloc來增加它的長度。 增加50個字節塊的長度,並用int來跟蹤它的大小,以便您知道何時需要再次增長它。 在某些時候,您將不得不決定緩沖區的長度,因為它無法無限增長。

你可以逐個字符地讀取字符串,直到你找到結束,然后回到開頭,分配一個正確大小的緩沖區,並重新讀入它,但除非你在一個很小的嵌入式系統上,這可能是愚蠢的。 首先,fgetc,fread等函數無論如何都會在O / S中創建緩沖區。

你可以分配一個足夠大的臨時緩沖區,使用長度有限的讀取(為了安全),然后分配一個精確大小的緩沖區來復制它。 您可能希望在堆棧上而不是通過malloc分配臨時緩沖區,除非您認為它可能超出可用堆棧空間。

如果您正在為一個小型系統編寫單線程代碼,您可以在啟動時或靜態分配一個臨時緩沖區,並將其重新用於多種用途 - 但要非常小心,您的使用不能重疊!

考慮到大多數系統的實現復雜性,除非你真正研究事物是如何工作的,否則完全有可能編寫內存優化的代碼,實際上需要更多的內存而不是簡單的方法。 變量初始化可能是另一個令人驚訝的浪費。

我的建議是分配一個足夠大小的緩沖區:

char name_buffer [ 80 ];

通常,大多數名稱(至少是常用英文名稱)的大小將小於80個字符。 如果您覺得可能需要更多空間,請務必分配更多空間。

保留一個計數器變量,以便知道已經讀入緩沖區的字符數:

int chars_read = 0; /* most compilers will init to 0 for you, but always good to be explicit */

此時,使用fgetc()逐個字符地讀取,直到您點擊文件結束標記或讀取80個字符(實際上是79,因為您需要空終止符的空間)。 將您讀過的每個字符存儲到緩沖區中,遞增計數器變量。

while ( ( chars_read < 80 ) && ( !feof( stdin ) ) ) {
  name_buffer [ chars_read ] = fgetc ( stdin );
  chars_read++;
}
if ( chars_read < 80 )
  name_buffer [ chars_read ] = '\0'; /* terminating null character */

我在這里假設您正在從stdin閱讀。 更完整的示例還將檢查錯誤,驗證您從流中讀取的字符是否對某人的名稱有效(例如,沒有數字)等。如果您嘗試讀取的數據多於分配空間的數據,請打印向控制台發送錯誤消息。

我理解希望保持盡可能小的緩沖區並僅分配您需要的內容,但學習如何編程的一部分是理解代碼/數據大小,效率和代碼可讀性的權衡。 你可以使用mallocrealloc ,但是它使得代碼比必要的復雜得多,並且它引入了可能出現錯誤的地方 - 空指針,數組索引越界錯誤等。對於大多數實際情況,分配應該足夠的內容為您的數據要求加上少量的呼吸空間。 如果您發現在數據超出緩沖區大小的情況下遇到大量情況,請調整緩沖區以適應它 - 這就是調試和測試用例的用途。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM