原文位址為: C/C++中的getline函數總結
getline函數是一個比較常見的函數。根據它的名字我們就可以知道這個函數是來完成讀入一行資料的。現在對getline函數進行一個總結。
在标準C語言中,getline函數是不存在的。
下面是一個簡單的實作方式:
int getline_( char s[], int lim){
int c,i;
i= 0;
while((c=getchar())!=EOF&&c!= ' \n '&&i<lim- 1)
s[i++]=c;
s[i]= ' \0 ';
return i;
}
下面是一個簡單的測試程式:
int test1(){
char s[ 100];
int len;
while((len=getline_(s, 100))> 0)
printf( " %s\n ",s);
return 0;
}
但是這個實作是有問題的,就是遇到空行的時候也會停止的。
為了解決這個問題,我們需要重新考慮while循環的判斷條件。
在上面的實作中,我們是遇到EOF和換行'\n'的時候都停止 ,然後通過判斷所讀到的字元串的長度是否大于0來判斷是否結束。
為了能讀入空行,我們需要判斷一下是否讀入的是結尾EOF,如果不是就繼續讀取就可以了。
還有一點,EOF是什麼?
EOF是C語言中為了區分有效資料和輸入結束符的。
C語言采用的解決辦法是:在沒有輸入時getchar函數将傳回一個特殊值,這個特殊值與任何實際字元都不同。這個值成為EOF(end of file ,檔案結束)。我們在聲明變量c 的時候,必須讓它大到足以存放getchar函數傳回的任何值。之是以不把c聲明成char類型,是因為它必須足夠大,除了能存儲任何可能的字元外還要能存儲檔案結束符EOF。
EOF的輸入由系統鎖定。windows下是ctrl+z,linux/unix下是ctrl+d。
下面是給出的修改後的getline函數
int getline2_( char s[], int lim){
int c,i;
i= 0;
while((c=getchar())!=EOF&&c!= ' \n '&&i<lim- 1)
s[i++]=c;
if(c==EOF&&i== 0)
return - 1;
s[i]= ' \0 ';
return i;
}
如果是檔案結尾(c==EOF&&i==0)的話,我們就傳回-1,通過判斷傳回值是否為-1來決定是否繼續入輸入:
int test1(){
char s[ 100];
int len;
while((len=getline2_(s, 100))!=- 1)
printf( " %s\n ",s);
return 0;
}
這樣話就可以正确讀入所有的輸入了。
在gcc編譯器中,對标準庫進行了擴充,加入了一個getline函數。該函數的定義如下:
#include <stdio.h>
ssize_t getline( char **lineptr, size_t *n, FILE *stream);
其中*lineptr指向一個動态配置設定的記憶體區域。*n是所配置設定記憶體的長度。如果*lineptr是NULL的話,getline函數會自動進行動态記憶體的配置設定(忽略*n的大小),是以使用這個函數非常注意的就使用要注意自己進行記憶體的釋放。
如果*lineptr配置設定了記憶體,但在使用過程中發現所配置設定的記憶體不足的話,getline函數會調用realloc函數來重新進行記憶體的配置設定,同時更新*lineptr和*n。
注意*lineptr指向的是一個動态配置設定的記憶體,由malloc,calloc或realloc配置設定的,不能是靜态配置設定的數組。
下面是使用這個函數情況,事先配置設定了動态記憶體。
void test2(){
int read;
int len= 100;
char *line=NULL;
if((line=malloc((len+ 1)))==NULL){
printf( " Can't get memory\n ");
exit(- 1);
}
while((read=getline(&line,&len,stdin))!=- 1)
printf( " %s\n ",line);
free(line);
}
下面是一個沒有提前進行記憶體配置設定的情況:
void test3(){
int read;
int len= 0;
char *line=NULL;
while((read=getline(&line,&len,stdin))!=- 1)
printf( " %s\n ",line);
free(line);
}
同樣最後要進行記憶體的釋放。
這兒還要注意一個問題就是,getline函數讀入的一行是包括最後的換行符的。之前我們寫的函數是不包括這個的。下面我們進行修改一下,也讀入換行符。
int getline3_( char s[], int lim){
int c,i;
i= 0;
while((c=getchar())!=EOF&&c!= ' \n '&&i<lim- 1)
s[i++]=c;
if(c==EOF&&i== 0)
return - 1;
if(c== ' \n ')
s[i++]=c;
s[i]= ' \0 ';
return i;
}
這樣也讀入了換行符。這樣的話,這個getline函數就不錯了。
在C++中為了使用的友善,C++在标準庫中添加了getline函數。
其實在C++中對不同的輸入流對象都定義了一個getline函數,即:
std::fstream::getline
std::istream::getline
std::ifstream::getline
std::iostream::getline
std::wfstream::getline
std::wistream::getline
std::wifstream::getline
std::wiostream::getline
std::stringstream::getline
std::basic_fstream::getline
std::basic_istream::getline
std::istringstream::getline
std::wstringstream::getline
std::basic_ifstream::getline
std::basic_iostream::getline
std::wistringstream::getline
std::basic_stringstream::getline
std::basic_istringstream::getline
這兒我們讨論标準輸入對象的getline函數,其他的對象的情都是類似的。
在頭檔案<iostream>中聲明了getline函數:
istream::getline
istream& getline (char* s, streamsize n );
istream& getline (char* s, streamsize n, char delim );
函數是C類型的數組。因為C++中允許對函數進行重載,是以可以有多個同名函數。delim參數是指定分隔符。如果不指定的話,預設使用'\n'
下面是一個例子:
void test1(){
char line[ 100];
while(cin.getline(line, 100))
cout<<line<<endl;
}
注意這兒的getline是要讀入空白符。但是不包括最後的換行符。
C++中還定義了一個在std名字空間的全局函數,因為這個getline函數的參數使用了string字元串,是以聲明在了<string>頭檔案中了。
聲明如下:
istream& getline ( istream& is, string& str, char delim );
istream& getline ( istream& is, string& str );
簡單的示例如下:
void test2(){
string line;
while(getline(cin,line))
cout<<line<<endl;
}
注意此處也是不讀入換行符的。
是以在C++中讀取一行的函數是不讀入換行符的,而GCC中getline函數是讀入換行符的。可以了解為,一般情況下不讀入,特别的是GCC的讀入。
轉載請注明本文位址: C/C++中的getline函數總結