C語言入門經典——基礎知識(資料型別)
一、讀取資料的格式說明符
操作 | 需要的控制字串 |
---|---|
讀取short型別的資料 sizeof(short) = 2 sizeof(unsigned short) = 2 | %hd |
讀取int型別的資料 sizeof(int) = 4 sizeof(unsigned char) = 4 | %d |
讀取long型別的資料 sizeof(long) = 4 sizeof(unsigned long) = 4 | %ld |
讀取float型別的資料 sizeof(float) = 4 | %f 或者 %e |
讀取double型別的資料 sizeof(double) = 8 | %lf 或者 %le |
除此之外: sizeof(char) = 1 sizeof(long long) = 8 sizeof(long double) = 12
sizeof(unsigned char) = 1 sizeof(unsigned long long) = 8
sizeof運算子可以確定給定的型別佔據的位元組數。在C語言中sizeof是一個關鍵字。其結果是一個無符號的整數,可以用%u說明符輸出它。其可以確定某個基本的型別的值所佔用的記憶體空間。例如:sizeof(int)會得到int型別的變數所佔的位元組數,所得的是一個size_t型別的整數。
注意:我們希望把sizeof運算子應用於一個型別,則該型別名就必須放在括號中,例如:sizeof(long double) 。將sizeof運算子應用於表示式時,括號就是可選的。
二、極限值
%u 輸出無符號整數值。
%e 輸出浮點數的極限值,表示這個數值是指數形式。
%f 說明符表示沒有指數的數值,它對於非常大或非常小的數來說相當不方便。
型別 | 下限 | 上限 |
---|---|---|
char %d unsigned char %u | CHAR_MIN -128 0 | CHAR_MAX 127 UCHAR_MAX 255 |
short %d unsigned short %u | SHRT_MIN -32768 0 | SHRT_MAX 32767 USHRT_MAX 65535 |
int %d unsigned int %u | INT_MIN -2147483648 0 | INT_MAX 2147483647 UINT_MAX 4294967295 |
long %ld unsigned long %lu | LONG_MIN -2147483648 0 | LONG_MAX 2147483647 ULONG_MAX 4294967295 |
long long %lld unsigned long long %llu | LLONG_MIN -9223372036854775808 0 | LLONG_MAX 9223372036854775807 ULLONG_MAX 18446744073709551615 |
型別 | 下限 | 上限 |
---|---|---|
float %e | FLT_MIN 1.175e-38 | FLT_MAX 3.402823e+38 |
double %e | DBL_MIN 2.225e-308 | DBL_MAX 1.797693e+308 |
long double %Le | LDBL_MIN 3.362e-4932 | LDBL_MAX 1.189731e+4932 |
#include<stdio.h>
#include<limits.h>
#include<float.h>
int main(void)
{
printf("char stor values from %d to %d\n",CHAR_MIN,CHAR_MAX);
printf("float stor values from %.3e to %e\n",FLT_MIN,FLT_MAX);
printf("long stor values from %ld to %ld\n",LONG_MIN,LONG_MAX);
printf("unsigined long long stor values from 0 to %llu\n",ULLONG_MAX);
printf("double stor values from %.3e to %e \n",DBL_MIN,DBL_MAX);
printf("double stor values from %.3Le to %Le \n",LDBL_MIN,LDBL_MAX);
return 0;
}
一系列的printf()函式呼叫中,輸出<limits.h><float.h>標頭檔案中定義的符號的值。計算機中的數值總是受限於該機器可以儲存的值域,這些符號的值表示每種數值型別的極限值。
三、型別轉換
#include<stdio.h>
int main(void)
{
const float Revenue_Per_150 = 4.5f;//每銷售150個產品的收入
short JanSold = 23500; //一月份的銷售額
short FebSold = 19300;
short MarSold = 21600;
float RevQuarter = 0.0f; //每個季度的總收入
short QuarterSold = JanSold + FebSold + MarSold;//一個季度總銷售額
printf("Stock sold in \nJan:%d\nFeb:%d\nMar:%d\n",JanSold,FebSold,MarSold);
printf("Total stock sold in first quarter:%d\n",QuarterSold);
RevQuarter = QuarterSold/150*Revenue_Per_150;
printf("Sales revenue this quarter is:$%.2f\n",RevQuarter);//這個季度的銷售收入
return 0;
}
輸出的結果如下所示:顯然輸出的結果是錯誤的,不應該是得到的負值。
Stock sold in
Jan:23500
Feb:19300
Mar:21600
Total stock sold in first quarter:-1136
Sales revenue this quarter is:$-31.50
錯誤1:QuarterSold變數宣告為short型別,其初始值定義為3個月的銷售總額,總和是64400,而對於short型別而言,其最大值是32767。現在問題來了,我們試圖在變數中儲存對short型別而言過大的數字,計算機不能正確解釋QuarterSold的值,所以輸出了負數。
解決辦法:給QuarterSold變數使用unsigned long型別。來儲存非常大的數字,還可以把每月銷售量的變數指定為無符號型別。
錯誤2:RevQuarter = QuarterSold/150*Revenue_Per_150; 由於乘除的優先順序相同,先回計算64400/150=429.333 最終會捨棄.333。在下一步計算過程中會有出入。
解決辦法:方案1:語句改為RevQuarter = QuarterSold*Revenue_Per_150/150;
方案2:語句改為RevQuarter = QuarterSold/150.0*Revenue_Per_150;
方案3:語句改為RevQuarter = (float)QuarterSold/150*Revenue_Per_150;
//最終正確的格式如下:
#include<stdio.h>
int main(void)
{
const float Revenue_Per_150 = 4.5f;//每銷售150個產品的收入
unsigned short JanSold = 23500; //一月份的銷售額
unsigned short FebSold = 19300;
unsigned short MarSold = 21600;
float RevQuarter = 0.0f; //每個季度的總收入
unsigned long QuarterSold = JanSold + FebSold + MarSold;//一個季度總銷售額
printf("Stock sold in \nJan:%u\nFeb:%u\nMar:%u\n",JanSold,FebSold,MarSold);
printf("Total stock sold in first quarter:%d\n",QuarterSold);//-->>Total stock sold in first quarter:64400
RevQuarter =(float) QuarterSold/150*Revenue_Per_150;
printf("Sales revenue this quarter is:$%.2f\n",RevQuarter);//這個季度的銷售收入 //-->>Sales revenue this quarter is:$1932.00
return 0;
}
強制型別轉換:一種型別顯示轉化為另一種型別的過程。
把變數從一種型別轉換為另一種型別,應該把目標型別放在變數前面的括號中。例如:RevQuarter =(float) QuarterSold/150*Revenue_Per_150;
把表示式從一種型別強制轉換為另一種型別。此時,應該把表示式放在括號中。例如:result = (fouble)(a*a + b*b);
隱式型別轉換:在二元算數運算中使用不同型別的運算元,編譯器就會把其中一個值域較小的運算元型別轉化為另一個運算元的型別。 例如:RevQuarter = QuarterSold/150*Revenue_Per_150;計算為64400(int)/150(int),結果是429(int) , 再將429(int轉換為float)乘以4.5(float),得到1930.5(float)。因為Int型別的值域小於float型別。
//隱式型別轉換的規則
(1)如果一個運算元的型別是long double,就把另一個運算元轉換為long double型別。
(2)否則,如果一個運算元的型別是double,就把另一個運算元轉換為double型別。
(3)否則,如果一個運算元的型別是float,就把另一個運算元轉換為float型別。
(4)否則,如果兩個運算元的型別都是帶符號的整數或者無符號的整數,就把級別較低的運算元換位另一個運算元型別。無符號整數型別的級別從低到高為:
signed char ,short ,int ,long ,long long
每個無符號的整數型別的級別都與對應的帶符號整數型別相同,所以unsigned int型別的級別與int型別的相同。
(5)否則,如果帶符號整數型別的運算元級別低於無符號整數型別的級別,就把帶符號整數型別的運算元轉換為無符號整數型別。
(6)否則,如果帶符號的整數型別的值域包含了無符號整數型別所表示的值,就把無符號的整數型別轉換為帶符號的整數型別。
(7)否則,兩個運算元都轉換為帶符號的整數型別對應的無符號的整數型別。
//賦值語句中的隱式型別轉換
例如: long double tital_cost = double cost;
當運算元的型別不同時候,賦值操作總是要把右運算元的結果轉換為做運算元的型別。所以上述操作的結果會轉化為long double型別。編譯器不會發出警告,因為double型別的所有值都可以表示為long double.
四、列舉
在程式設計時候,常常希望儲存一組可能值中的一個 。例如:一個變數儲存表示當前月份的值。這個值應該只儲存12個可能值中的一個,分別對應於1~12月。
4.1 列舉型別的定義
enum Weekday{Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday};
enum Weekday today = Thursday;
只要希望變數有限定數量的可能值,就可以使用列舉。
第一個語句定義了列舉型別Weekday,這個型別的變數可以有括號中的7個值得任意一個。
第二個語句定義了Weekday型別的一個變數,把它初始化為Thursday,其對應的值是3。
1>格式為: enum 列舉的標記 {列舉器/列舉常量};,知Weekday是一個識別符號,可有可無;
2>列舉常量的名稱必須是唯一的;列舉器有預設值,編譯器會把int型別的整數值賦予給每個名稱;名稱間用逗號,隔開;其數量是可以任意的;列舉器的值不要求是唯一的,除非有特殊原因讓某些列舉器的值相同,否則應確保這些值也是唯一的;
3>列舉是一個整數型別, 每個列舉常量對應不同的整數值;
4>第一個列舉成員的預設值為整型的0,後續列舉成員的值在前一個成員上加1。
5> 可以人為設定列舉成員的值,從而自定義某個範圍內的整數。
6> 列舉型是預處理指令#define的替代。
7> 型別定義以分號;結束。
4.2 使用列舉型別對變數進行宣告
新的資料型別定義完成後,它就可以使用了。我們已經見過最基本的資料型別,如:整型int, 單精度浮點型float, 雙精度浮點型double, 字元型char, 短整型short等等。用這些基本資料型別宣告變數通常是這樣:
char a; //變數a的型別均為字元型charchar letter;int x,
y,
z; //變數x,y和z的型別均為整型intint number;
double m, n;
double result; //變數result的型別為雙精度浮點型double
既然列舉也是一種資料型別,那麼它和基本資料型別一樣也可以對變數進行宣告。
方法一:列舉型別的定義和變數的宣告分開
enum DAY{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};enum DAY yesterday;
enum DAY today;
enum DAY tomorrow; //變數tomorrow的型別為列舉型enum DAYenum DAY good_day, bad_day; //變數good_day和bad_day的型別均為列舉型enum DAY
方法二:型別定義與變數宣告同時進行:
//未命名的列舉型別,
//在建立列舉型別的變數時,可以不指定標記,這樣就沒有列舉型別了。其可能的列舉器從saturday到friday//該語句還生命了未命名型別的變數workday;可以用通常的方式給其賦值。
//侷限性:只要限制是,必須在定義該型別的語句中宣告它的所有變數。由於沒有型別名,無法在程式碼的後面定義該型別的其他的變數
enum//跟第一個定義不同的是,此處的標號DAY省略,這是允許的。{
saturday,
sunday =0,
monday,
tuesday,
wednesday,
thursday,
friday
} workday; //變數workday的型別為列舉型enum DAYenum week { Mon=1, Tue, Wed, Thu, Fri Sat, Sun} days; //變數days的型別為列舉型enum weekenum BOOLEAN { false, true } end_flag, match_flag; //定義列舉型別並聲明瞭兩個列舉型變數
方法三:用typedef關鍵字將列舉型別定義成別名,並利用該別名進行變數宣告:
typedef enum workday{
saturday,
sunday =0,
monday,
tuesday,
wednesday,
thursday,
friday
} workday; //此處的workday為列舉型enum workday的別名workday today, tomorrow; //變數today和tomorrow的型別為列舉型workday,也即enum workday
enum workday中的workday可以省略:
typedef enum{
saturday,
sunday =0,
monday,
tuesday,
wednesday,
thursday,
friday
} workday; //此處的workday為列舉型enum workday的別名
workday today, tomorrow; //變數today和tomorrow的型別為列舉型workday,也即enum workday
也可以用這種方式:
typedef enum workday{
saturday,
sunday =0,
monday,
tuesday,
wednesday,
thursday,
friday
};
workday today, tomorrow; //變數today和tomorrow的型別為列舉型workday,也即enum workday
注意:同一個程式中不能定義同名的列舉型別,不同的列舉型別中也不能存在同名的命名常量。錯誤示例如下所示:
錯誤宣告一:存在同名的列舉型別
typedef enum{
wednesday,
thursday,
friday
} workday;
typedef enum WEEK
{
saturday,
sunday =0,
monday,
} workday;
錯誤宣告二:存在同名的列舉成員
typedef enum{
wednesday,
thursday,
friday
} workday_1;
typedef enum WEEK
{
wednesday,
sunday =0,
monday,
} workday_2;
4.3 使用列舉型別的變數
4.3.1 對列舉型的變數賦值。
例項將列舉型別的賦值與基本資料型別的賦值進行了對比:
方法一:先宣告變數,再對變數賦值
#include<stdio.h>/* 定義列舉型別 */enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };void main()
{
/* 使用基本資料型別宣告變數,然後對變數賦值 */int x, y, z;
x =10;
y =20;
z =30;
/* 使用列舉型別宣告變數,再對列舉型變數賦值 */enum DAY yesterday, today, tomorrow;
yesterday = MON;
today = TUE;
tomorrow = WED;
printf("%d %d %d \n", yesterday, today, tomorrow);
}
方法二:宣告變數的同時賦初值
#include <stdio.h>/* 定義列舉型別 */enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };void main()
{
/* 使用基本資料型別宣告變數同時對變數賦初值 */int x=10, y=20, z=30;
/* 使用列舉型別宣告變數同時對列舉型變數賦初值 */enum DAY yesterday = MON,
today = TUE,
tomorrow = WED;
printf("%d %d %d \n", yesterday, today, tomorrow);
}
方法三:定義型別的同時宣告變數,然後對變數賦值。
#include <stdio.h>/* 定義列舉型別,同時宣告該型別的三個變數,它們都為全域性變數 */enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN } yesterday, today, tomorrow;/* 定義三個具有基本資料型別的變數,它們都為全域性變數 */int x, y, z;
void main()
{
/* 對基本資料型別的變數賦值 */
x =10; y =20; z =30;
/* 對列舉型的變數賦值 */
yesterday = MON;
today = TUE;
tomorrow = WED;
printf("%d %d %d \n", x, y, z); //輸出:10 20 30 printf("%d %d %d \n", yesterday, today, tomorrow); //輸出:1 2 3}
方法四:型別定義,變數宣告,賦初值同時進行。
#include <stdio.h>/* 定義列舉型別,同時宣告該型別的三個變數,並賦初值。它們都為全域性變數 */enum DAY{
MON=1,
TUE,
WED,
THU,
FRI,
SAT,
SUN
}
yesterday = MON, today = TUE, tomorrow = WED;
/* 定義三個具有基本資料型別的變數,並賦初值。它們都為全域性變數 */int x =10, y =20, z =30;
void main()
{
printf("%d %d %d \n", x, y, z); //輸出:10 20 30 printf("%d %d %d \n", yesterday, today, tomorrow); //輸出:1 2 3}
4.3.2 對列舉型的變數賦整數值時,需要進行型別轉換。
#include <stdio.h>enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };void main()
{
enum DAY yesterday, today, tomorrow;
yesterday = TUE;
today = (enum DAY) (yesterday +1); //型別轉換 tomorrow = (enum DAY) 30; //型別轉換
//tomorrow = 3; //錯誤
printf("%d %d %d \n", yesterday, today, tomorrow); //輸出:2 3 30}
4.3.3 使用列舉型變數
#include<stdio.h>enum{
BELL ='\a',
BACKSPACE ='\b',
HTAB ='\t',
RETURN ='\r',
NEWLINE ='\n',
VTAB ='\v',
SPACE =''
};
enum BOOLEAN { FALSE =0, TRUE } match_flag;
void main()
{
int index =0;
int count_of_letter =0;
int count_of_space =0;
char str[] ="I'm Ely efod";
match_flag = FALSE;
for(; str[index] !='\0'; index++)
if( SPACE != str[index] )
count_of_letter++;
else
{
match_flag = (enum BOOLEAN) 1;
count_of_space++;
}
printf("%s %d times %c", match_flag ?"match" : "not match", count_of_space, NEWLINE);
printf("count of letters: %d %c%c", count_of_letter, NEWLINE, RETURN);
}
輸出:
match 2 times
count of letters: 10
Press any key to continue
4.4