C語言簡介

C語言核心技術-常用基本資料型別及其案例分析

C是一種通用的程式語言,廣泛用於系統軟體與應用軟體的開發。於1969年至1973年間,為了移植與開發UNIX作業系統,由丹尼斯·裡奇與肯·湯普遜,以B語言為基礎,在貝爾實驗室設計、開發出來。

C語言具有高效、靈活、功能豐富、表達力強和較高的可移植性等特點,在程式設計師中備受青睞,成為最近25年使用最為廣泛的程式語言[2]。目前,C語言編譯器普遍存在於各種不同的作業系統中,例如Microsoft Windows, Mac OS X, Linux, Unix等。C語言的設計影響了眾多後來的程式語言,例如C++、Objective-C、Java、C#等。二十世紀八十年代,為了避免各開發廠商用的C語言語法產生差異,由美國國家標準局為C語言訂定了一套完整的國際標準語法,稱為ANSI C,作為C語言的標準。二十世紀八十年代至今的有關程式開發工具,一般都支援匹配ANSI C的語法。

C語言核心技術-常用基本資料型別及其案例

C語言核心技術-常用基本資料型別及其案例分析

整數

整數常量

C語言整數常量可以使用u字尾表示位無符號整數,使用l字尾表示long型別的整數,使用ll字尾表示為long long型別的整數

整數的三種進位制型別

C語言中的整型常量支援八進位制、十進位制和十六進位制三種進位制型別,不支援二進位制。

八進位制由0-7之間的八個整陣列成,八進位制的常量值是以0開頭。

十進位制由0-9之間的十個整陣列成。

十六進位制由0-9,a-f之間的十個整數加上6個字母組成。

printf()函式針對整數的三種進位制型別提供了對應的輸出格式,其中八進位制輸出使用%o表示,十進位制使用%d表示,十六進位制使用%f表示,#表示輸出進位制的完整格式,例如八進位制會在最左邊填充一個0,十六進位制會在最左邊填充0x。

不同進位制的輸出不會改變資料原來的值,底層依然是以二進位制儲存,只是輸出的表現形式變了。

跨平臺的整數

為了解決不同平臺,相同的型別佔據的大小不一致的問題,C語言標準委員會在C99標準中提出了跨平臺的整數,在標頭檔案中定義,意味著同樣的型別在不同的系統下的大小是一致的。

例如int64_t在所有實現C99標準的編譯器下佔據的都是8個位元組,int32_t在所有實現C99標準的編譯器下佔據的都是4個位元組。

整數的極限

整數按照佔據不同的位元組大小可以分為short,int,long和long long 四種類型,它們預設是有符號(signed)型別用於儲存正負數,而對應的無符號型別(unsigned)則用來儲存非負數的整數。

整數的極限定義在標頭檔案中定義,Visual Studio 2019中可以選中一個極限值常量,然後使用快捷鍵F12轉到定義,直接檢視常量值的表示範圍。

整數的注意事項和案例

在使用整數參與運算時,需要考慮到資料範圍對應的極限,否則會發生錯誤的結果

如果想要儲存身份證號等超大型別的整數資料,可以使用無符號的long long型別來儲存

根據給出的三角形三條邊,使用標頭檔案中的sqrt函式計算三角形的面積

浮點數

浮點型常量

浮點型即生活中使用的小數型別(例如3。14),例如賬戶的餘額,銀行的存款利率等等都是浮點型。

C語言中按照精度的不同分別使用float,double和long double表示,預設浮點型別是double,float佔據四個位元組,double佔據8個位元組,long double大於等於8個位元組,Windows 32位和64位系統long double都是8個位元組,Ubuntu18。04系統下long double是佔據16個位元組。

浮點數的常量可以使用十進位制的小數和科學計數法表示,科學計數法可以儲存特大或者特小的數字

浮點數變數

在初始化浮點數變數時,預設值建議為0。0或者0。0f,賦值時變數的值和變數的型別保持一致。

printf()函式輸出float型別的變數使用格式符%f,輸出double型別的變數使用%lf。

浮點數極限

C語言在的標頭檔案中使用常量定義了float和double以及long double的極限值,我們可以使用sizeof()關鍵字求出float,double和long double的位元組數量以及使用。常量FLT_MAX,FLT_MIN求出float表示的最大值和最小值以及DBL_MAX,DBL_MIN求出double所能表示的最大值和最小值。在windows上double和long double是等價的,但是在Linux(例如Ubuntu 18。04上)long double是佔據16個位元組,這也就意味著long double的極限比double更大。浮點數儲存機制首先明確一點,無論是整型、浮點型還是字元等等資料型別在計算機底層都是以二進位制的方式儲存的。浮點數在記憶體中的儲存和整數不同,因為整數都可以轉換為一一對應的二進位制資料。而浮點數的儲存是由符號位(sign)+指數位(exponent)+小數位(fraction)組成。其中float是由1位符號位+8位指數+23位小陣列成,

而double是由1位符號位+11位指數位+52位小數位組成。

int和float同樣佔據四個位元組的記憶體,但是float所能表示的最大值比int大得多,其根本原因是浮點數在記憶體中是以指數的方式儲存。

我們都知道在記憶體中,一個float型別的實數變數是佔據32位,即32個二進位制的0或者1組成

四位元組浮點數 最左邊的第一位是最高位0000 0000 0000 0000 0000 0000 0000 0000從低位依次到高位叫第0位和第31位,這32位可以由三部分組成:符號位:第31位數表示符號位,如果為0表示整數,如果為1表示負數指數:第23位到第30位,這8個二進位制表示該實數轉化為規格化的二進位制實數後的指數與127(127即所謂的偏移量)之和所謂階碼,規格化的二進位制實數只能在-127-127之間。小數位:第0位到第22位,最多可以表示23位二進位制小數,否則超過了就會產生誤差。浮點數使用注意事項float佔據四個位元組,提供的有效位是6-7位,而double佔據八個位元組,提供的有效位數是15-16位,如果在使用float或者double表示實數時超過有效數字,若拿來進行關係運算(例如等於)的話,會得到一個錯誤的結果。

#define _CRT_SECURE_NO_WARNINGS

#include

#include

/*

浮點數相等性判斷

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

float flt1 = 1。00000000001;

float flt2 = 1。00000000000000000001;

//因為float的有效數字是6-7位 這裡超出有效數字 計算不準確

printf(“ flt1 == flt2 ? %d\\n”, (flt1 == flt2)); // 輸出結果1表示相等 0則表示不相等

//double精確的有效位數是15-16位,這裡也超出了有效數字,計算不夠正確

double db1 = 1。00000000000000000000000000000001;

double db2 = 1。000000000000000000000000000000000000000000000000000000000000000000000000000000001;

printf(“ db1 == db2 ? %d\\n”, (db1 == db2)); // 輸出結果1表示相等 0則表示不相等

system(“pause”);

return 0;

}

中美GDP計算

#define _CRT_SECURE_NO_WARNINGS

#include

#include

#include

/*

給出當前美國和中國的GDP以及增長率,使用math。h的pow函式實現計算出中國GDP超過美國GDP的年份

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

//當前中美GDP

double ch_current_gdp = 14。6;

double us_current_gdp = 20。5;

//當前中美GDP的增長率

double ch_rate = 1。06;

double us_rate = 1。04;

double ch_gdp = 0。0;

double us_gdp = 0。0;

int year = 2018;

for (int i = 1; i <= 100; i++) {

//使用pow函式計算中美每年增長後的GDP

ch_gdp = ch_current_gdp * pow(ch_rate, i);

us_gdp = us_current_gdp * pow(us_rate, i);

year++;

printf(“%d年中國的GDP是%f\\n”, year, ch_gdp);

printf(“%d年美國的GDP是%f\\n”, year, us_gdp);

if (ch_gdp > us_gdp) {

printf(“在%d年,中國的GDP超越了美國的GDP”, year);

break;

}

}

system(“pause”);

return 0;

}

字元

字元型常量

在日常開發應用中,字元是最常用的資料型別。因為生活中的許多資料都是透過字元表示,而不是數字表示,字元能表示更多的含義,最典型的就是網路協議,例如超文字傳輸協議HTTP協議。

C語言中字元使用一對單引號(‘’)表示,注意單引號只能作用域一個字元。

#define _CRT_SECURE_NO_WARNINGS

#include

#include

/*

字元常量

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

//輸出英文字元

printf(“輸出英文字元%c\\n”, ‘a’);

printf(“char佔據的位元組數量是%d\\n”, sizeof(char));

system(“pause”);

return 0;

}

C語言中的char只佔用1個位元組,因此不能儲存中文,如果想要儲存中文,需要使用wchar_t型別儲存,然後還要進行本地化的設定。

#define _CRT_SECURE_NO_WARNINGS

#include //引入本地化的標頭檔案

#include

#include

/*

C語言中文儲存

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

//設定本地化

setlocale(LC_ALL, “chs”);

wchar_t ch = L‘劉’;

//使用wprintf()函式輸出中文

wprintf(L“ch = %c \\n”, ch);

system(“pause”);

return 0;

}

除了使用prinf函式結合%c輸出字元以外,C語言還提供了putchar()函式來輸出字元

#define _CRT_SECURE_NO_WARNINGS

#include

#include

/*

輸出字元的幾種方式

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version

*/

int main(int argc, char* argv[])

{

char c = ‘A’;

putchar(c);

printf(“\\n”);

printf(“c = %c \\n”, c);

system(“pause”);

return 0;

}

字元的本質由於計算機最底層只能識別二進位制的資料,但是字元不是二進位制的資料。如果將字元和特定的數值一一對應起來,這張對應表就是ASC||表。如果字元變數ch儲存的字元是‘z’,那麼實際上儲存的是字元z對應的ASC||值即整數122。即字元變數儲存的本質就是儲存的字元對應的ASC||值#define _CRT_SECURE_NO_WARNINGS

#include

#include

/*

字元與asc||碼錶

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

//宣告並初始化字元變數ch,初始化值為z

char ch = ‘z’;

printf(“char ch = %c \\n”, ch);

printf(“字元變數%c對應的整數是%d \\n”, ch, ch);

printf(“char佔據的位元組大小是 %u \\n”, sizeof(ch));

system(“pause”);

return 0;

}

日常開發中最常用的字元就是大小寫字母以及數字字元

我們可以藉助printf()函式的格式%c和%d實現輸出字元對應的ASC||值。

數字字元‘0’表示的整數是48,小寫字元‘a’表示的整數是97,大寫字元‘A’表示的整數時65。數字0表示空字元。

#define _CRT_SECURE_NO_WARNINGS

#include

#include

/*

字元的本質

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

char ch = ‘0’;

printf(“字元%c對應的整數是%d\\n”, ch, ch);

ch = ‘a’;

printf(“字元%c對應的整數是%d\\n”, ch, ch);

ch = ‘A’;

printf(“字元%c對應的整數是%d\\n”, ch, ch);

int number = 97;

printf(“數字%d對應的字元是%c\\n”, number, number);

number = 65;

printf(“數字%d對應的字元是%c\\n”, number, number);

number = 48;

printf(“數字%d對應的字元是%c\\n”, number, number);

system(“pause”);

return 0;

}

跳脫字元

一些特殊的符號無法直接顯示時,我們使用\\u7279殊字元來表示。

例如\\a表示發聲,無法在終端上直接顯示。

在日常開發中還會使用到各種常用的跳脫字元,例如\\t實現tab的效果。

跳脫字元\\n實現換行的效果,跳脫字元\\u5b9e現路徑轉義。

%%輸出百分號。

跳脫字元還可以使用八進位制和十六進位制表示,用於表示字元對應的ASC||碼值

#define _CRT_SECURE_NO_WARNINGS

#include

#include

/*

跳脫字元

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

//聲音無法輸出在螢幕上顯示,因此這裡使用轉字元\\a實現發聲

printf(“%c”, ‘\\a’);

//日常開發中常用的轉移字元 \\n實現換行

printf(“hello \\n”);

printf(“world \\n”);

// \\t 實現tab效果

printf(“C\\t語\\t言\\t核\\t心\\t編\\t程\\n”);

// \\r 實現游標移到行首 由於游標移到行首,最終只會輸出C語言核心程式設計

printf(“CPrimerPlus%cC語言核心程式設計\\n”, ‘\\r’);

//路徑轉義 \\\\u8868示路徑轉義

//使用system函式使用電腦上的微信,呼叫成功的前提條件是電腦上安裝了微信

system(“\\”C:\\\\Program Files (x86)\\\\Tencent\\\\WeChat\\\\WeChat。exe\\“”);

// %%實現輸出百分號

printf(“合格率為%%%d\\n”, 90);

//八進位制轉義和十六進位制轉義

//八進位制的62轉換為十進位制是50,50表示字元2

char ch = ‘\\62’;

printf(“八進位制的跳脫字元62轉換為字元的結果是%c \\n”, ch);//2

//十六進位制的62轉換為十進位制是98,98表示的字元是b

ch = ‘\\\\x62’;

printf(“十六進位制的跳脫字元62轉換為字元的結果是%c\\n”, ch); //b

system(“pause”);

return 0;

}

字元的應用

既然字元變數的本質儲存的ASC||值,即整數。因此字元也可以參與加減運算。

由於ASC||碼規定了小寫字母‘’a‘ 表示97,然後一次遞增,小寫字母’z‘表示122,而大寫字母’A‘表示65,然後依次遞增,大寫字母’Z‘表示90。因此根據這個規律可以透過加減運算實現大小寫字母轉換。

#define _CRT_SECURE_NO_WARNINGS

#include

#include

/*

字元的大小寫轉換

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

// 小寫轉大寫

char lower_ch = ’a‘;

// 0x20就是十進位制的32

char upper_ch = lower_ch - 0x20;

printf(“小寫字母%c轉換為大寫字母的結果是%c \\n”, lower_ch, upper_ch);

//大寫轉小寫

upper_ch = ’A‘;

lower_ch = upper_ch + 32;

printf(“大寫字母%c轉換為小寫字母的結果是%c \\n”, upper_ch, lower_ch);

system(“pause”);

return 0;

}

布林

bool型別只有兩個值,即true和fasle,它們在記憶體中分別使用1和0表示,這樣一個位元組便可以儲存bool型別的變數。

在C程式中使用bool型別的變數,需要引入標頭檔案stdbool。h,後續的各種邏輯、關係運算以及選擇結構if/else和while迴圈會大量使用bool型別的變數。

#define _CRT_SECURE_NO_WARNINGS

#include

#include

#include

/*

bool型別及其應用

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version

*/

int main(int argc, char* argv[])

{

bool flag = true;

//佔據的位元組數量為1

printf(“bool佔據的位元組數量是%d\\n”, sizeof(flag));

//成立的結果為1

printf(“bool = %d\\n”, flag);

flag = false;

//不成立的結果為0

printf(“bool = %d\\n”, flag);

//bool在if/else結構和關係運算的使用

int age = 20;

bool isAdult = age > 18;

if (isAdult == 1) {

printf(“你成年了\\n”);

}

else {

printf(“你沒有成年\\n”);

}

system(“pause”);

return 0;

}

資料型別轉換

資料自動型別轉換當多種資料型別(整數、浮點數、字元)同時參與運算時,會發生自動型別轉換,容量小的資料型別的變數與容量大的大資料型別的變數做運算時,結果自動提升為容量大的資料型別,防止運算時超過極限值,防止運算結果的精度丟失。此時容量大小指的是,資料型別表示數的範圍大小,而不是佔用記憶體大小,比如float容量大於long的容量。

自動型別轉換的規則如下

char,short->int->long->float->double->long double

其中對應的有符號型別還會自動轉換為無符號型別,char和char運算,short和short運算也會轉換為int。

char和int,double的自動型別轉換

#define _CRT_SECURE_NO_WARNINGS

#include

#include

/*

資料型別自動轉換

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

char ch = ’A‘;

printf(“1。0佔據的位元組數量是%d\\n”, sizeof(1。0));

//ch+1自動轉換為int型別,因此佔據四個位元組

printf(“字元變數ch+1的位元組數量是%d\\n”, sizeof(ch + 1));

printf(“字元變數ch+1。0的位元組數量是%d\\n”, sizeof(ch + 1。0));

system(“pause”);

return 0;

}

int和unsigned int的自動型別轉換

#define _CRT_SECURE_NO_WARNINGS

#include

#include

/*

自動型別轉換 有符號型別int轉換為無符號型別int

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

int number1 = -10;

unsigned int number2 = 5;

//有符號數和無符號數參與運算時,先將有符號數轉換為無符號數

printf(“number1按照無符號輸出結果為%u\\n”, number1);

int result = number1 + number2;

//使用三目運算和算術運算輸出表達式number1+number2大於0還是小於0

//因為number1按照無符號的結果是4294967286 因此結果是大於0

number1 + number2 > 0 ? printf(“number1 + number2 > 0 \\n”) : printf(“number1 + number2 < 0 \\n”);

printf(“按照有符號整數輸出 result = %d \\n”, result);

printf(“按照無符號整數輸出 result = %u \\n”, result);

system(“pause”);

return 0;

}

char、short的自動型別轉換:由於char,short佔據的記憶體空間過小,編譯器規定,只要是char,short參與運算,都會自動轉換為int型別。

#define _CRT_SECURE_NO_WARNINGS

#include

#include

/*

char、short的自動型別轉換:由於char,short佔據的記憶體空間過小,編譯器規定,只要是char,short參與運算,都會自動轉換為int型別。

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

char x = 10;

int target = x + x;

short s = 20;

int short2 = s + s;

int result = x + s;

system(“pause”);

return 0;

}

資料強制型別轉換

強制型別轉換就是在待轉換的表示式的左邊使用強轉符(目標型別)實現

#define _CRT_SECURE_NO_WARNINGS

#include

#include

/*

資料強制型別轉換

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

float fl = 10。8;

float flt = 10。3;

int num = (int)fl + flt; //20。3 先把fl強制轉換為int型別,然後再和flt相加,再轉換為int,因為賦值會進行自動型別轉換

printf(“num =%d\\n”, num);

num = (int)(fl + flt);//21 先把fl和flt相加後,強制轉換為int

printf(“num =%d\\n”, num);

system(“pause”);

return 0;

}

強制型別轉換隻是臨時改變變數的值

#define _CRT_SECURE_NO_WARNINGS

#include

#include

/*

強制型別轉換的特性

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

float flt = 3。14f;

int number = 0;

//強制型別轉換隻是臨時改變變數flt的值,其本質是讀取flt的值,然後強制轉換為int型別的值

number = (float)flt;

//number =3

printf(“number = %d”, number);

// flt=3。14

printf(“flt = %f”, flt);

system(“pause”);

return 0;

}

在使用printf函式列印輸出變數值時,不會進行自動型別轉換,如果想要獲取預期的結果,需要使用強制型別轉換實現。

#define _CRT_SECURE_NO_WARNINGS

#include

#include

/*

printf()函式與強制型別轉換

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

//因為printf函式不會進行型別轉換,所以這裡得到一個錯誤的結果

printf(“%d\\n”, 12。1);

//12。1為浮點型別,這裡使用強制型別轉換實現轉換為整數

printf(“%d\\n”, (int)12。1);

printf(“%f\\n”, 10); //整數按照浮點數解析,得到的結果就是0。000000

printf(“%f\\n”, (float)10); //強制型別轉換

system(“pause”);

return 0;

}

資料型別轉換案例

型別轉換案例:實現對小數點後三位實現四捨五入

#define _CRT_SECURE_NO_WARNINGS

#include

#include

/*

實現對小數點後三位實現四捨五入

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

printf(“請輸入四捨五入的三位小數\\n”);

double input = 0。0;

scanf(“%lf”, &input);

double val = 1。235;

//1。234*100=123。4 123。4+0。5=123 123/100。0=1。23

// 1。235*100=123。5 123。5+0。5=124 124/100=1。24

// 1。24>1。235

// 1。24-1。235=0。05

//1。235+0。05=1。24

double result = (int)(input * 100 + 0。5) / 100。0;

printf(“result =%。2f”, result);

system(“pause”);

return 0;

}

型別轉換案例:賬戶餘額的分大於4分就偷錢

#define _CRT_SECURE_NO_WARNINGS

#include

#include

/*

賬戶餘額的分大於4分就偷錢

@author liuguanglei ittimelinedotnet@gmail。com

@website

http://

ittimeline。net

@version 2019/11/05

*/

int main(int argc, char* argv[])

{

printf(“請輸入你的賬戶餘額\\n”);

double balance = 0。0;

scanf(“%lf”, &balance);

// 12。34*10=123。4 123。4+0。6=124 124/10。0=12。4 12。4>12。34

double rest = (int)((balance * 10) + 0。6) / 10。0;

printf(“rest = %f”, rest);

if (rest < balance) {

//

printf(“可以偷錢%。2f元”, balance - rest);

}

system(“pause”);

return 0;

}