天天看點

C/C++中的getline函數總結

原文位址為: 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函數總結