變量與常量
為了能夠更加方便的使用數據,程序員會將在程序運行期間會改變或賦值的數據使用變量進行保存。常量則是預先定義好,在程序運行期間不會改變的固定值
變量和常量就好像是一個盒子,可以用來裝東西(數據)。在計算機中,數據是存放在內存中的,存放數據的內存空間程序員為了方便以後的使用,都會起一個好記的名字。這個名稱也由字母、數字和下劃線組成,必須要以字母和下劃線開頭。由於C語言是對大小寫敏感的,所以大寫字母和小寫字母是不同的,也就是變量名abc和Abc是兩個不同的變量。
數據類型
不同的數據類型有不同的含義,有的數據類型表示整數,有的表示字符,有的表示浮點數。常量可以是任何的數據類型,通過常量的值識別(100是整數,123.45是浮點數)。而變量則需要指定數據類型。在C語言中有很多種數據類型,從最初的K&R給出的7個數據類型關鍵字,再到C90添加的2個新的關鍵字,到最後的C99添加的3個關鍵字
| 最初K&R給出的關鍵字 | C90標準添加的關鍵字 | C99標準添加的關鍵字 |
|---|---|---|
| int | signed | _Bool |
| long | void | _Complex |
| short | _Imaginary | |
| unsigned | ||
| char | ||
| float | ||
| double |
int、long、short、unsigned和C90新添加的signed關鍵字用於表示整數類型,unsigned表示無符號數,signed則表示有符號數,整數類型的例子:unsigned short int 和 long long int
char關鍵字用於存放字母和其他字符(如:$、%等),char也可以用來表示較小的整數
float、double和long double表示浮點數
_Bool表示布爾類型(true或false)
_Complex和_Imaginary分別表示複數和虛數
存儲大小
不同的數據類型可以存放的數據大小是不同的,能夠存放的數據越多,值越大。
| 數據類型 | 存儲大小 |
|---|---|
| char | 1字節 |
| int | 2或4字節() |
| short | 2字節 |
| long | 4字節 |
| float | 4字節 |
| double | 8字節 |
| long double | 16字節 |
在C語言中,可以通過sizeof運算符查看數據類型存儲字節的大小
#include<stdio.h>
int main()
{
printf("char 的存儲大小: %d\n", sizeof(char));
printf("short 的存儲大小: %d\n", sizeof(short));
printf("int 的存儲大小: %d\n", sizeof(int));
printf("long 的存儲大小: %d\n", sizeof(long));
printf("float 的存儲大小: %d\n", sizeof(float));
printf("double 的存儲大小: %d\n", sizeof(double));
printf("long double 的存儲大小: %d\n", sizeof(long double));
return 0;
}
運行結果:
這裏使用到的printf()函數,後面會進行講解,目前只需要知道printf()是用來打印內容到屏幕上的就可以了。
變量的定義
C語言提供了很多種數據類型,在定義變量時需要指定變量的數據類型,如整數可以使用int類型,小數可以使用float類型等,下面將開始介紹如何定義變量。
定義變量
定義變量的語法:數據類型 變量名;
舉個例子,下面的程序用於計算兩個整數的和
#include<stdio.h>
int main()
{
int num1; //定義一個變量num1,用於存放第一個數
int num2; //定義一個變量num2,用於存放第二個數
int sum; //定義一個變量sum,用於存放兩個數的和
num1 = 100; //將整數100賦值給變量num1
num2 = 200;
sum = num1 + num2; //計算num1與num2相加,並將值賦值給sum變量
printf("num1 + num2 = %d\n", sum); // 將sum的值打印到屏幕
return 0;
}
運行結果:
在聲明num1和num2變量時,並沒有給它們提供初始值。num1和num2是通過後面的 num1 = 100; 和 num2 = 200; 獲取到值的,這種行為稱為初始化。初始化就是給變量一個初始值。
定義變量時初始化
在上面的例子中,定義變量與給初始化變量是分成兩步的,也可以將這兩步合併在一起,將程序修改後如下:
#include<stdio.h>
int main()
{
int num1 = 100; //定義變量num1並將100賦值給num1
int num2 = 200;
int sum = num1 + num2; //num1與num2相加後的結果賦值給sum變量
printf("num1 + num2 = %d\n", sum); // 將sum的值打印到屏幕
return 0;
}
連續定義多個變量
修改後的程序比之前的簡潔了,接着我們發現num1和num2的數據類型是相同的,都是int類型,那麼這兩個變量就可以一起定義,還是上面的例子,修改後如下:
#include<stdio.h>
int main()
{
int num1 = 100, num2 = 200; //同時聲明num1和num2並賦值
int sum = num1 + num2; //num1與num2相加後的結果賦值給sum變量
printf("num1 + num2 = %d\n", sum); // 將sum的值打印到屏幕
return 0;
}
需要注意的是,為了不讓人誤會在同時定義多個變量時,有的變量不需要初始化,而有的變量需要進行初始化。那麼不建議寫在一起,建議分開定義,如int num1, num2= 200; 這樣寫很容易讓人誤以為num1和num2的值都是200,所以不建議這麼寫,當然這麼寫是不會報錯的。
常量的定義
通過一個例子開始講解常量的使用,下面的程序的作用是計算圓的周長和麪積:
#include<stdio.h>
int main(void)
{
float pi = 3.14159; //圓周率
int r = 5; //圓的半徑
float area = pi * r * r; //計算圓的面積
float circum = 2 * pi * r; //計算圓的周長
printf("半徑為 %d 的圓面積是: %.2f, 周長是: %.2f", r, area, circum);
return 0;
}
通過上面的例子可以知道變量也可以當做常量來使用,但是在實際使用的時候不建議這麼使用,因為在程序運行過程中有可能會將定義的變量改變,變量並非不可改變的。那有沒有更好的定義常量的方法呢?有,這就需要使用預處理語句定義一個常量,這樣定義的常量也被稱為符號常量。語法是:#define NAME value
使用預處理語句,修改上面的例子:
#include<stdio.h>
#define PI 3.14159 //使用預處理語句定義圓周率
int main(void)
{
int r = 5; //圓的半徑
float area = PI * r * r; //計算圓的面積
float circum = 2 * PI * r; //計算圓的周長
printf("半徑為 %d 的圓面積是: %.2f, 周長是: %.2f", r, area, circum);
return 0;
}
預處理語句的作用是在編譯的時候將PI替換為3.14159,這樣就達到了常量的作用了。預處理語句一定要寫在頂部,並且PI和3.14159之間是沒有等號和結束時也沒有分號的。前面也説了預處理語句是在編譯時替換掉值,如果有了等號和分號,那麼等號和分號也會變成要替換的值了。
還有一種方法是使用限定符 const 將變量限定為只讀,修改上面的例子如下:
#include<stdio.h>
int main(void)
{
const float pi = 3.14159; //使用限定符const,定義常量圓周率
int r = 5; //圓的半徑
float area = pi * r * r; //計算圓的面積
float circum = 2 * pi * r; //計算圓的周長
printf("半徑為 %d 的圓面積是: %.2f, 周長是: %.2f", r, area, circum);
return 0;
}
使用 const 限定符定義的變量pi可以使用,可以使用 printf() 打印值,但就是無法修改值。另外需要注意的是使用 const 限定符定義的是變量,不是常量。
輸入輸出
輸出
在C語言中,通過printf()將內容輸出到屏幕上,printf()也被稱為格式化輸出,可以讓變量以某種格式輸出到屏幕上,如 %d為以整數的形式顯示,%f以浮點數的形式顯示,下表列出了一些轉換説明和各自對應的輸出類型:
| 轉換説明 | 輸出 |
|---|---|
| %a | 浮點數、十六進制和p記數法 |
| %A | 浮點數、十六進制和p記數法 |
| %c | 單個字符 |
| %d | 有符號十進制整數 |
| %e | 浮點數,e記數法 |
| %E | 浮點數,e記數法 |
| %f | 浮點數,十進制記數法 |
| %g | 根據值的不同,自動選擇%f或%e。%e格式用於指數小於-4或者大於或等於精度時 |
| %G | 根據值的不同,自動選擇%f或%E。%E格式用於指數小於-4或者大於或等於精度時 |
| %i | 有符號十進制整數(與%d相同) |
| %o | 無符號八進制整數 |
| %p | 指針 |
| %s | 字符串 |
| %u | 無符號十進制整數 |
| %x | 無符號十六進制整數,使用十六進制數0f |
| %X | 無符號十六進制整數,使用十六進制數0F |
| %% | 打印一個百分號 |
一開始不需要全部都記住,只需要記住幾個常用的(如:%d,%f,%c)即可,其他的用到在看就可以了,用的多了就記住了。下面的例子是將一個整數以八進制和十六進制的形式顯示:
#include<stdio.h>
int main(void)
{
int num = 100;
printf("100 的八進制為 %o\n", num); //顯示num的八進制
printf("100 的八進制為 %#o\n", num); //顯示num的八進制時,並在前面加上前綴
printf("100 的十六進制為 %x\n", num); //顯示num的十六進制
printf("100 的十六進制為 %#x\n", num); //顯示num的十六進制,並在前面加上前綴
return 0;
}
運行結果:
可以通過printf()函數配合%o和%x打印出數值的八進制形式和十六進制形式。#只是為了顯示前綴,八進制以0開頭,十六進制以0x開頭
有的讀者可能不太瞭解什麼是八進制和十六進制,那就簡單的介紹一下。我們日常説的10,100,123等數字,都是十進制,可以發現這些數字都是逢十進一,而八進制和十六進制同理,八進制就是逢八進一,十六進制是逢十六進一。有的讀者就會問了,逢十六進一?那要怎麼表示十以上的數呀?十六進制由1到9和a到f(也可以是A到F)組成,沒錯,a到f分別表示10到15。
參數與陷阱
在使用printf() 和 scanf() 時需要確保轉換説明的數量、類型與後面的參數數量、類型匹配。由於 printf() 和 scanf() 的參數是可變的,所以無法檢查出參數的個數和類型是否正確。
那如果參數個數不匹配會怎樣呢?
#include<stdio.h>
int main(void)
{
int num1 = 1;
float num2 = 1.23;
printf("%d %d %d\n", num1, num1, num1, num1); //參數太多
printf("%d %d %d\n", num1); //參數太少
printf("%d\n", num2); //類型不匹配
return 0;
}
運行結果:
當使用%d打印一個浮點數時,不會將這個浮點數轉換為int類型。在不同的平台下,缺少參數或參數類型不匹配導致的結果會不相同。
輸入
在前面的兩個數相加的例子中,兩個相加的數是預先就設置好的,當要計算其他整數相加時,需要修改源文件並生成新的可執行文件,這就很麻煩,這是就可以讓用户輸入要進行計算的兩個整數。
要想獲取用户的輸入可以使用scanf()進行接收,使用的方法與printf()相似,%d表示要接收整數,%f表示要接收一個浮點數。
修改程序:
#include<stdio.h>
int main(void)
{
int num1, num2; //同時聲明num1和num2
scanf("%d %d", &num1, &num2); //獲取用户輸入的num1和num2的值
int sum = num1 + num2; //num1與num2相加後的結果賦值給sum變量
printf("num1 + num2 = %d\n", sum); // 將sum的值打印到屏幕
return 0;
}
運行結果:
運行完程序,應該可以發現如果這是給程序員自己使用,那當然沒有任何問題,但是給其他人使用,會出現不知道要幹嘛的情況。所以應該在程序接收用户輸入之前,告訴用户要做什麼,再次修改程序:
#include<stdio.h>
int main(void)
{
int num1, num2; //同時聲明num1和num2
printf("請輸入兩個需要相加的整數(例:12 34):"); //提示用户輸入兩個整數
scanf("%d %d", &num1, &num2); //獲取用户輸入的num1和num2的值
int sum = num1 + num2; //num1與num2相加後的結果賦值給sum變量
printf("num1 + num2 = %d\n", sum); // 將sum的值打印到屏幕
return 0;
}
運行結果:
細心的讀者會發現在num1和num2的前面有一個&符號,那這個&符號表示的是什麼意思呢?&符號表示獲取地址,整個語句就是將獲取到的整數放入到num1和num2的地址中。
當讀取的是基本的數據類型的值時需要使用&符號,而讀取的是字符串時,不要使用&符號。
整數溢出
當一個整數類型超出了它能表示的最大值會出現溢出,通過一個例子觀察溢出後的結果
#include<stdio.h>
int main(void)
{
int i = 2147483647; //定義一個有符號整數類型的變量i並初始化為最大值
unsigned int j = 4294967295; //定義一個無符號整數類型的變量j並初始化為最大值
printf("%d %d %d\n", i, i+1, i+2);
printf("%u %u %u\n", j, j+1, j+2);
return 0;
}
運行結果:
通過觀察可以發現當一個數超過自身能夠表示的最大值時,會從最小值開始。當發生溢出時系統沒有告訴用户,所以在編程時需要注意。
char類型
char類型用於存放字符(如:字母或標點符號),但char其實是整數類型,因為char實際上保存的是整數,而不是字符。有的讀者就會有疑問了,存儲整數,那要怎麼知道是哪個字符呢?在計算機中使用數字編碼處理字符,即使用整數表示字符,在ASCII編碼中65表示大寫字母"A",標準的ASCII的範圍是0~127,完全可以使用char類型進行存儲
聲明char類型變量
char類型的變量在賦值時,值需要使用單引號括起來,如:char ch = 'A'; ,而不能是 char ch = A; 。如果沒有被單引號括起來,此時A表示一個變量名,而不是字符A。
char類型也可以直接保存整數,如 char ch = 65; ,但是不建議這樣使用,這樣使用需要系統支持ASCII碼,最好還是使用 ‘A’ 替換 65。
舉個例子
用户輸入一個字符,將這個字符對應的ASCII碼打印在屏幕上:
#include<stdio.h>
int main(void)
{
char ch; //定義變量ch,用於接收用户輸入
printf("請輸入一個字符(如:A):");
scanf("%c", &ch); //接收用户輸入的字符
printf("%c 對應的整數為 %d\n", ch, ch);
return 0;
}
運行結果:
轉義字符
使用特殊的符號序列表示一些特殊的字符,這些符號序列就叫做轉義序列,下表列出了轉義序列及其含義
| 轉義序列 | 含義 |
|---|---|
| \a | 警報(ANSI C) |
| \b | 退格 |
| \f | 換頁 |
| \n | 換行 |
| \r | 回車 |
| \t | 水平製表符(相當於tab鍵) |
| \v | 垂直製表符 |
| \\ | 反斜槓() |
| \' | 單引號 |
| \" | 雙引號 |
| ? | 問號 |
| \0oo | 八進制值(oo必須是有效八進制數) |
| \xhh | 十六進制值(hh必須是有效十六進制數) |
通過一個例子更好的理解轉義字符:
#include<stdio.h>
int main(void)
{
float salary;
printf("\aEnter your desired monthly salary:");
printf(" $_______\b\b\b\b\b\b\b");
scanf("%f", &salary);
printf("\n\t$%.2f a month is $%.2f a year.", salary, salary * 12.0);
printf("\rGee!\n");
return 0;
}
運行結果:
解析:
在程序的第7行 printf("\aEnter your desired monthly salary:"); 中的 \a 會發出警報的聲音(能否發出警報取決於硬件,有可能不會發出警報)
接着第8行的 printf(" $_______\b\b\b\b\b\b\b"); 先將$_______打印出來呢,接着使用 \b 移動光標,使光標緊跟$符
在第10行的 printf("\n\t$%.2f a month is $%.2f a year.", salary, salary * 12.0); 首先是 \n 進行換行,接着是製表符 \t 使後面的內容縮進。光標停留在最後的點那裏(.),如下圖:
在第11行的 printf("\rGee!\n"); \r 將光標移動到當前行是起始位置,再打印內容,最後的 \n 換行
reference
《C Primer Plus》(第六版)
大話C語言變量和數據類型---C語言中文網
C語言轉義字符---C語言中文網
C 數據類型---菜鳥教程
C 變量---菜鳥教程
C 常量---菜鳥教程