C/簡單的輸入輸出
機器處理東西。我們將東西餵給機器,機器給我們吐出不同的東西。鋸子將樹木變為木板。內燃機將汽油轉化為轉動的能量。計算機也一樣。不過,計算機為我們處理的不是物質材料,而是信息。
我們把信息餵給計算機,告訴計算機如何處理這些信息,然後取得結果。那一部分我們輸入計算機的信息稱為輸入,而我們從計算機收到的信息則稱為輸出。任何地方都可以是輸入的來源。鍵盤擊打、網絡數據,抑或轉換到電信號的聲波都是輸入的例子。輸出也有眾多的形式,如顯示器上播放的視頻、終端上顯示的一段字符串,或存儲在硬碟上的數據。輸入的集合與輸出的產生統稱為輸入/輸出,或縮寫為I/O,是計算機的一項核心功能。
有趣的是,C語言並沒有內置的I/O功能,取而代之的是包含I/O函數的外部函數庫。我們能把這些函數編譯、連結到程序里。在章節開始時的示例「Hello, World!」中,我們已經用到一個輸出庫函數:printf()
。你可能會想起這個函數屬於stdio.h
函數庫文件。正如文件名所示,stdio.h
包含標準化的I/O函數,可用於給我們的程序增加加輸入/輸出能力。本章將帶你探索其中的一些函數。
使用printf()
輸出
編輯
現在回憶之前的演示程序:
#include <stdio.h>
int main(void)
{
printf("Hello, World!");
return 0;
}
如果你把它編譯運行,你就能看到下方的句子顯示在屏幕上:
Hello, World! |
這項令人驚喜的成就是由 printf()
函數實現的。一個函數就像一個「黑盒子」,它為你完成特定工作,而不顯示自身的內部結構。我們也可以藉助C語言寫自己的函數,但那就是後話了。
你已經看到用printf()
可以輸出括號中雙引號里的文本。我們稱包含在引號中的文本為字面字符串(簡稱字符串),那個字符串則是printf的一個參數。
在此澄清一下:有時為了方便起見,我們在一個函數名稱後寫一對圓括號,提醒我們這確實是一個函數。然而,在大家都知道討論的對象是函數時,這並不是必需的。
正如上文的例子所言,用printf()
就像打一段文字、兩端加雙引號一樣簡單(注意這是雙引號,而不是兩個單引號)。也就是說,你可以把任何字符串作為printf()
的參數列印出來:
printf("This sentence will print out exactly as you see it..."); |
而一旦它被包含在合適的main()
函數中,它將會顯示:
This sentence will print out exactly as you see it... |
列印數值和轉義字符
編輯占位符
編輯printf()
是一個強大的函數,很可能也是C程序中最常用的函數。
接下來我們用一個問題做例子。假如我們要計算:19 + 31。讓我們用C語言求出答案。
現在我們就開始寫
#include "stdio.h" // this is important, since printf
// can't be used without this header
int main(void)
{
printf("19+31 is");
但是卡在這裡了!printf()
只能列印字符串!幸好printf有輸出數值的方法。我們要做的就是在字符串中放一個占位格式控制符。這樣寫:
printf("19+31 is %d", 19+31);
顧名思義,占位符%d
給19與31相加得到的具體數值「占了位置」。
這些占位符稱為格式說明符。還有很多格式說明符可以與printf()
使用。如果我們有一個單精度浮點數,我們可以用%f
完整輸出。其他的格式說明符有:
%d
- 整型 (同%i)%ld
- 長整型 (同%li)%f
- 單精度浮點型%lf , %g
- 雙精度浮點型[1]%c
- 字符型%s
- 字符串型%x
- 十六進制型
維基百科上有printf()
全部格式說明符的列表。
Tabs和換行
編輯假使我們想輸出這樣的文本:
1905 312 + -----
printf()
不會在每個語句結尾輸出換行符:我們必須手動操作。可是怎樣做呢?
我們能做的是使用換行轉義字符。轉義字符是一種特殊字符,我們能寫出來,但它會在屏幕上做某些特殊的事情,如發出蜂鳴聲、寫一個tab字符等。要想寫一個換行符,可以使用\n
。所有轉義字符以反斜線開始。
因此,想要實現上述的輸出,應該這樣寫:
printf(" 1905\n312 +\n-----\n");
為了使代碼更清晰,我們將這個很長的printf語句分割成幾行。然後我們的程序會變成這樣:
#include <stdio.h>
int main(void)
{
printf(" 1905\n");
printf("312 +\n");
printf("-----\n");
printf("%d", 1905+312);
return 0;
}
此外還有很多其他轉義字符可用。另一個常見的做法是用\t
寫一個tab。你還可以用\a
讓電腦的蜂鳴器發出響聲,不過你不應該在自己的程序里過多地使用它,因為聲音的過度使用對用戶的感官不很友好。
其他輸出方式
編輯puts()
編輯
在不考慮任何占位符或變量時,puts()
函數是一種在屏幕上輸出字符串的非常簡單的方法。它和我們在"Hello, World!"這個例子裡看到的printf()
函數很是相像:
puts("Print this string.");
輸出到屏幕的是:
Print this string.
緊接著是一個換行符(前文已經說到過)。(puts
函數會在輸出的結尾加一個換行符。)
使用scanf()
輸入
編輯
scanf()
函數是與printf()
輸出函數等價的輸入方法——它簡單但強大。在最簡單的調用中,scanf的格式字符串包含一個占位符,表示用戶將要輸入值的類型。這些占位符大抵與printf()
函數相同——%d
表示整數,%f
表示單精度浮點數,%lf
表示雙精度浮點數。
然而,與printf()
相比,scanf()
有一點不同。scanf()
函數要求你將要存儲輸入值的變量內存地址。 雖然這裡可以使用指針(存儲內存地址的變量),這畢竟是一個之後才會涉及的概念。相反,較為簡單的技巧是使用取地址運算符,即&。在我們討論指針之前,現在我們最好先把它看作"魔法"。
下面是一個典型的用例:
#include "stdio.h"
int main(void)
{
int a;
printf("Please input an integer value: ");
scanf("%d", &a);
printf("You entered: %d\n", a);
return 0;
}
如果你要描述上面scanf()
函數產生的作用,它可以讀作:「讀取用戶輸入的整數並存儲到變量a所在的地址」。
假如你要用scanf輸入一個字符串,你不應該包含&運算符。下面的代碼會產生運行時錯誤,很可能導致程序崩潰。
scanf("%s", &a);
正確的用法應該是:
scanf("%s", a);
這是因為你在使用字符串(%s
)格式說明符時,你用來存儲值的變量是一個數組,數組名稱(在這個例子中是a)本身指向它的基地址,因此不需要取地址運算符。
注意,使用scanf()
從用戶鍵盤上獲取數據可能讓你的代碼易受緩衝區溢出攻擊,如果你不很謹慎,則可能導致其他不可預測的行為。考慮使用 fgets()
而不是scanf()
。
參考資料
編輯- ↑ 實際上
%f
也能輸出double
型數據,但輸入時%f
的使用則不同。更多細節請見維基百科上對C語言數據類型的介紹。