C Primer Plus 第11章 字符串和字符串函數 11.2 字符串輸入

11.2.1  建立存儲空間編程

要作的第一件事是創建一個空間以存放讀入的字符串。數組

最簡單的辦法就是在聲明中明確指出數組的大小:函數

char name[81] ;工具

如今的name是一個已經分配81字節存儲塊的地址。另外一個方法是使用C庫裏分配存儲空間的函數,這一點會在第12章討論。設計

爲字符串預留空間後,就能夠讀取字符串了。C庫提供了三個讀取字符串的函數:scanf( )、gets( )和fgets( )。咱們先討論最經常使用的gets( )。指針

11.2.2  gets( ) 函數code

它從系統的標準輸入設備(一般是鍵盤)獲取一個字符串。由於字符串沒有預約的長度,因此gets( )須要知道什麼時候結束。解決辦法是讀字符串直到遇到一個換行字符(\n),按回車鍵能夠產生這個字符。它讀取換行符(不包括換行符)以前的全部字符,在這些字符後添加一個空字符(\o),而後把這個字符串交給調用它的程序。它將讀取換行符並將其丟棄,這樣下一次讀取就會在新一行開始。對象

程序清單11.4  name1.c程序內存

/*name1.c  讀取一個名字*/
#include<stdio.h>
#define MAX 81
int main(void)
{
    char name[MAX];  /*分配空間*/
    printf("Hi,what's your name?\n");
    gets(name);  /*把字符串放進name數組*/
    printf("Nice name ,%s.\n",name);
    return 0;
}

程序清單11.4接受並存儲最多80個字符(包括空格)的任何名字(記住爲數組裏的\o預留空間)。注意到但願gets( )改變調用函數中的某個變量(name),也就是說應當使用一個地址做爲參數;固然,數組名正是一個地址。字符串

get( )函數的使用能夠比前的例子更爲複雜,請參見程序清單11.5.

程序清單11.5 name2.c程序

/*name1.c  讀取一個名字*/
#include<stdio.h>
#define MAX 81
int main(void)
{
    char name[MAX];  /*分配空間*/
    char * ptr;

    printf("Hi,what's your name?\n");
    ptr=gets(name);  /*把字符串放進name數組*/
    printf("Nice name, %s.\n",ptr);

    return 0;
}

get( )函數經過兩種方式獲取輸入:

**它使用一個地址,把字符串賦給name;

**gets( )的代碼使用return關鍵字返回字符串的地址,程序把這個地址分配給ptr。注意到ptr是一個char的指針,這意味着gets必須返回一個指向char的指針值。

ANSI C要求stdio.h頭文件包括gets( )的函數原型。您不須要親自聲明這個函數,只須記住包含這個頭文件便可。gets( )函數的構造以下:

char *gets(char *s)
{
    ...
    return (s);
}

這個函數頭說明gets( )返回一個指向char的指針。請注意,gets( )返回的指針與傳遞給它的是同一個指針。輸入字符串只有一個備份,它放在做爲函數參數傳遞過來的地址,所以程序清單11.5中的ptr最後也指向name。gets( )函數實際的構造更復雜一點,由於它有兩個可能的返回值:若是一切都順利,它返回的是讀入字符串的地址,正如上面所說的。若是出錯或gets( )遇到文件結尾,它就返回一個空(0)地址。這個空地址被稱爲空指針,並用stdio.h中定義的常量NULL來表示。所以,gets( )中還加入了一些錯誤檢測,這使它能夠很方便的使用以下形式使用:

while (gets(name)!=NULL)

這個的指令使您便可以檢查是否到了文件的結尾,又能夠讀取一個值。若是遇到了文件的結尾,name中什麼也不會讀入。這種一箭雙鵰的方法就比getchar( )函數所採用的方法簡潔的多,getchar( )只返回一個值而沒有參數。

while ((ch=getchar())!=EOF)

附帶提一下,不要混淆空指針和空字符。空指針是一個地址,而空字符是一個char類型的數據對象,其值爲0.數值上二者均可以用0表示,可是它們的概念不一樣:NULL是一個指針,而0是一個char類型的常量。

11.2.3  fgets( )函數

gets( )的一個不足是它不檢查預留存儲區是否可以容納實際輸入的數據。多出來的字符簡單地溢出到相鄰的內存區。fgets( )函數改進了這個問題,它讓您指定最大讀入字符數。因爲fgets( )是爲文件I/O設計的,在處理鍵盤輸入時就不如gets()那麼方便。fgets()和gets()有三方面不一樣:

一、它須要第二個參數來講明最大讀入字符數。若是這個參數值爲n,那麼fgets( )就會讀取最多n-1個字符或者讀完一個換行符爲止,由這兩者中最早知足的那個來結束輸入。

二、若是fgets( )讀取到換行符,就會把它存放在字符串裏,而不是像gets()那樣丟棄;

三、它還須要第三個參數來講明讀哪一個文件。從鍵盤上讀取輸入時,可使用stdin做爲該參數,這個標識符在stdio.h中定義。

程序清單11.6使用了fgets( )代替了11.5裏的gets( )。

程序清單11.6 name3.c 程序

/*name1.c  讀取一個名字*/
#include<stdio.h>
#define MAX 81
int main(void)
{
    char name[MAX];  /*分配空間*/
    char * ptr;

    printf("Hi,what's your name?\n");
    ptr=fgets(name,MAX,stdin);  /*把字符串放進name數組*/
    printf("Nice name, %s.\n",ptr);

    return 0;
}

問題在於fgets( )把換行符存儲到字符串裏,這樣每次顯示字符串時就會顯示換行符。本章後面「其餘字符串函數」小節的結尾會介紹如何用strchr( )來定位和刪除換行符。

對於重要的編程,應當使用fgets( )而不是gets( )。

11.2.4  scanf( )函數

scanf( ) 和get( )的主要差異在於它們如何決定字符串什麼時候結束。

scanf()更基於如何獲取單詞(get word)而不是獲取字符串(get string);而gets( )函數,正如您所看到的,會讀取全部字符,直到遇到第一個換行符爲止。

scanf( )使用兩種方法來決定輸入結束。不管哪一種方法,字符串都是以遇到第一個非空白字符開始。若是使用%s格式,字符串讀到下一個空白字符(但不包括)(好比空格、製表符和換行符)。若是指定了字段的寬度,好比%10s,scanf( )就會讀入10個字符或直到遇到第一個空白字符,由兩者中最早知足的那一個終止輸入。

程序清單11.7舉例說明了指定字段寬度時scanf( )的工做狀況。

/*scan_str.c  使用scanf()*/
#include<stdio.h>
int main(void)
{
    char name1[11],name2[11];  /*分配空間*/
    int count;

    printf("Please inter 2 names.\n");
    count=scanf("%5s %10s",name1,name2);
    printf("I read the %d names %s and %s.\n",
           count,name1,name2);

    return 0;
}

第三個例子輸出:

Please enter 2 names .
portensia callowit 
I read 2 names Porte and nsia.

portensia的後4個字母被讀到name2中,這是由於第二次調用scanf( )時,它在第一個調用 結束的地方繼續開始讀取輸入數據。

根據所需輸入的特色,用gets()從鍵盤讀取文本可能要更好。scanf()主要用於以某種標準形式輸入的混合類型數據的讀取和轉換。例如,每個輸入行都包括一種工具名稱、庫存數量和單價,您就可使用scanf();不然您必須在函數中本身處理輸入錯誤的檢測。若是但願一次只輸入一個單詞,最好使用scanf( )。

相關文章
相關標籤/搜索