從興很好的答案後,我決定寫我的FULL簡單的程序,實現你的任務,並告訴一些關於我的解決辦法。我的程序逐行讀取一個文件,將其作爲輸入參數給出,並將下一行保存到緩衝區中。
代碼:
#include <assert.h>
#include <errno.h>
#define _WITH_GETLINE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define assert_msg(x) for (; !(x) ; assert(x))
int
main(int argc, char **argv)
{
FILE *file;
char *buf, *token;
size_t length, read, size;
assert(argc == 2);
file = fopen(argv[1], "r");
assert_msg(file != NULL) {
fprintf(stderr, "Error ocurred: %s\n", strerror(errno));
}
token = NULL;
length = read = size = 0;
while ((read = getline(&token, &length, file)) != -1) {
token[read - 1] = ' ';
size += read;
buf = realloc(buf, size);
assert(buf != NULL);
(void)strncat(buf, token, read);
}
printf("%s\n", buf);
fclose(file);
free(buf);
free(token);
return (EXIT_SUCCESS);
}
對於文件file.txt
:
that is a
text
which I
would like to
read
from file.
我得到了一個結果:
$ ./program file.txt
that is a text which I would like to read from file.
幾件事情,這是值得要說的解決方案:
- 而不是
fgets(3)
我使用getline(3)
函數,因爲有簡單的方法來獲得有關字符串長度的知識(read
變量)和自動內存分配得到的字符串(token
)。重要的是要記住free(3)
它。對於類Unix系統,默認情況下不提供getline(3)
以避免兼容性問題。因此,在<stdio.h>
標題前使用#define _WITH_GETLINE
宏以使該功能可用。
buf
僅包含保存字符串所需的必需空間量。在從文件buf
讀取一行後,所需的空間量由realloc(3)
擴展。這是多一點「普遍」的解決方案嗎?記住釋放堆中分配的對象是很重要的。
- 我也用
strncat(3)
它確保不多於read
字符(長度爲token
)將被保存到buf
。這也不是使用strncat(3)
的最佳方式,因爲我們也應該測試字符串截斷。但總的來說,它比簡單使用strcat(3)
要好,因爲惡意用戶可以通過緩衝區溢出攻擊任意改變正在運行的程序的功能。 strcat(3)
和strncat(3)
也增加了終止\0
。
- A
getline(3)
返回帶有換行符的標記,因此我決定將它從新行替換爲空格(在從文件中給出的單詞中創建句子的上下文中)。我也應該消除最後的空間,但我不想複雜的源代碼。
從不是強制性的東西,我還定義了我自己的宏assert_msg(x)
這是能夠運行assert(3)
功能,並顯示錯誤的文本消息。但它只是一個功能,但由於我們能夠在錯誤的嘗試打開文件時看到錯誤消息。
來源
2017-09-16 13:56:55
jrk
謝謝你的工作,但你能解釋爲什麼嗎? – Pantelis