涉及到的知識(shí)點(diǎn)有:
1、C語言庫函數(shù)戒良、字符輸入函數(shù):gets和fgets体捏、字符輸出函數(shù):puts和fputs、
? ? 求字符串長度函數(shù)strlen糯崎、字符串追加函數(shù)strcat几缭、字符串有限追加函數(shù)strncat、字符串比較函數(shù)strcmp沃呢、
? ? ? ? 字符串有限比較函數(shù)strcmp年栓、字符串拷貝函數(shù)strcpy、字符串有限拷貝函數(shù)strncpy薄霜、
? ? ? ? 格式化字符串函數(shù)sprintf(輸出)某抓、格式化字符串函數(shù)sscanf(讀取輸入)、解析一個(gè)字符串惰瓜、
? ? ? ?字符串查找字符函數(shù)strchr否副、字符串查找子串函數(shù)strstr、字符串分割函數(shù)strtok崎坊、
? ? ? ?atoi函數(shù)备禀、atof函數(shù)、atol函數(shù)、解析一個(gè)字符串的高級應(yīng)用曲尸。
2赋续、函數(shù)的定義和聲明、函數(shù)的形式參數(shù)(形參)與實(shí)際參數(shù)(實(shí)參)另患、函數(shù)的返回值類型和返回值纽乱、
? ? ?return函數(shù)與exit函數(shù)(exit更猛,不受位置限制)柴淘、自定義一個(gè)函數(shù)迫淹,實(shí)現(xiàn)大小寫字母的互相轉(zhuǎn)換功能秘通、
? ? ?自定義一個(gè)函數(shù)为严,實(shí)現(xiàn)atoi的功能。
3肺稀、函數(shù)的遞歸第股、遞歸例子:有n個(gè)人排成一隊(duì)、遞歸例子:將10進(jìn)制數(shù)轉(zhuǎn)化為二進(jìn)制數(shù)话原、
? ? ?遞歸例子:將10進(jìn)制數(shù)轉(zhuǎn)化為16進(jìn)制夕吻、遞歸例子:菲波那切數(shù)列、遞歸的優(yōu)點(diǎn)與缺點(diǎn)繁仁。
4涉馅、多個(gè)源代碼文件程序如何編譯、頭文件的使用黄虱、解決預(yù)編譯時(shí)會(huì)出現(xiàn)多次函數(shù)聲明問題稚矿。
“我是一名從事了10年開發(fā)的老程序員,最近我花了一些時(shí)間整理關(guān)于C語言捻浦、C++晤揣,自己有做的材料的整合,一個(gè)完整的學(xué)習(xí)C語言朱灿、C++的路線昧识,學(xué)習(xí)材料和工具。C/C++盗扒、編程愛好者的聚集地就在我這里 <進(jìn)入我的專欄就能看到>跪楞!歡迎初學(xué)和進(jìn)階中的小伙伴。希望你也能憑自己的努力侣灶,成為下一個(gè)優(yōu)秀的程序員甸祭。工作需要、感興趣炫隶、為了入行淋叶、轉(zhuǎn)行需要學(xué)習(xí)C/C++的伙伴可以跟我一起學(xué)習(xí)!”
===========================================================
C語言庫函數(shù)
1、字符串處理函數(shù):字符輸入函數(shù)和字符輸出函數(shù)
字符輸入函數(shù):gets和fgets
通過scanf輸入的時(shí)候煞檩,最后按的是一個(gè)什么鍵处嫌?答:回車鍵,scanf會(huì)把回車鍵認(rèn)為是輸入完成斟湃,而不是字符串的內(nèi)容熏迹。
而且scanf認(rèn)為回車和空格都代表輸入完成哦。
當(dāng)字符數(shù)組的成員數(shù)量小于用戶在鍵盤輸入字符的數(shù)量之后凝赛,scanf并不會(huì)自動(dòng)處理注暗,而是把用戶輸入的所有字符都放入了數(shù)組,導(dǎo)致了數(shù)組溢出了墓猎,內(nèi)存出錯(cuò)捆昏,程序崩潰。
-----------------------------------------------------------------------------
gets認(rèn)為只有回車代表輸入完成毙沾,空格只是字符串中的一部分而已骗卜。
gets和scanf一樣有緩沖區(qū)溢出的危險(xiǎn)。
-----------------------------------------------------------------------------
字符數(shù)組 的英文名字是 char []
gets()函數(shù)的基本用法為:
char *gets(char *s);?
該函數(shù)的參數(shù)是一個(gè)字符數(shù)組左胞,該函數(shù)的返回值也是一個(gè)字符數(shù)組寇仓。
linux下示例代碼如下:
1 #include
2?
3 int main()
4 {
5 char a[100] = { 0 };
6 gets(a);
7 ? printf("%s\n", a);
8 return 0;
9 }
-----------------------------------------------------------------------------
編譯時(shí)會(huì)出現(xiàn)一個(gè)warning,建議我們不要使用gets函數(shù)了烤宙。我們暫時(shí)不管他遍烦,先直接運(yùn)行看結(jié)果。
--------------------------------------
警告如下:
a2.c:6:5: warning: implicit declaration of function ‘gets’ [-Wimplicit-function-declaration]
gets(a);
^
/tmp/cceyMQ7u.o: In function `main':
a2.c:(.text+0x41): warning: the `gets' function is dangerous and should not be used.
--------------------------------------
原因:
問題出在程序中使用了 gets是非常不安全的躺枕。這是對程序產(chǎn)生BUG服猪,出現(xiàn)不可靠性的一個(gè)描述,
有些函數(shù)在某些意外情況會(huì)導(dǎo)致程序陷入不可控狀態(tài)屯远,僅僅是PC上運(yùn)行最多也就是退出而已蔓姚,
但是如果是運(yùn)行在飛機(jī)等系統(tǒng)里的話,就會(huì)有大麻煩慨丐,說危險(xiǎn)也不為過坡脐。因?yàn)橛⑽奈墨I(xiàn)里描述為dangerous,所以也就翻譯為危險(xiǎn)房揭。
函數(shù)執(zhí)行需要一個(gè)棻赶校空間,但這個(gè)椡北空間容量是有限的恬砂,而且棧里存放了函數(shù)返回的地址。
gets()函數(shù)在獲取輸入時(shí)蓬痒,如果無限輸入會(huì)造成椥褐瑁空間溢出,在程序返回時(shí),不能正常的找到返回地址狱掂,程序?qū)l(fā)生不可預(yù)測行為演痒。
--------------------------------------
解決:
解決辦法是使用 fgets,但由于fgets函數(shù)是為讀取文件設(shè)計(jì)的趋惨,所以讀取鍵盤是沒有g(shù)ets那么方便鸟顺。
fgets(char *s, int size, FILE *stream);
第一個(gè)參數(shù)是:字符類型的數(shù)組,第二個(gè)參數(shù)是:標(biāo)明這個(gè)數(shù)組的大小器虾,第三個(gè)參數(shù)是:如果總是通過鍵盤輸入的話讯嫂,可以固定寫為stdin。
fgets()函數(shù)的基本用法為:
-------------------------------------
示例程序:
/*代碼實(shí)現(xiàn)01_使用fputs函數(shù)打印輸出*/
#include <stdio.h>
int main ( )?
{
char name[20] = { 0 };
fgets(name, sizeof(name), stdin);//stdin 意思是鍵盤輸入
fputs(name, stdout); //stdout 意思是通過打印設(shè)備輸出
return 0;
}
--------------------------------------
/*代碼實(shí)現(xiàn)02_使用printf函數(shù)打印輸出*/
#include
int main ( )?
{
char name[20] = { 0 };
fgets(name, sizeof(name), stdin);//stdin 意思是鍵盤輸入
printf("%s", name);//這邊輸出不需要 \n 了兆沙,實(shí)際操作時(shí)欧芽,fgets會(huì)認(rèn)為用戶輸入的回車也是字符串的一部分內(nèi)容。即輸出的內(nèi)容中間接地帶了 \n 了挤悉。
return 0;
}
-----------------------------------------------------------------------------
fgets會(huì)認(rèn)為用戶輸入的回車也是字符串的一部分內(nèi)容渐裸。
fgets是安全的巫湘,不會(huì)因?yàn)橛脩魫阂獾妮斎脒^長的字符串導(dǎo)致溢出装悲。因?yàn)樗唤邮芩艽娴淖畲蟮淖址麛?shù),其余的舍掉尚氛!
=============================================================================
字符輸出函數(shù):puts和fputs
puts函數(shù)打印字符串時(shí)诀诊,與printf不同,puts會(huì)在最后自動(dòng)增加一個(gè)換行字符 '\n'阅嘶。
puts不支持各種轉(zhuǎn)義字符属瓣,如%d,%s都不支持讯柔,puts只能簡單直接地輸出一個(gè)字符串抡蛙,而不能輸出char類型(字符類型)、int類型(整型)魂迄、double類型(雙精度浮點(diǎn)類型)等其他類型粗截。
linux下示例代碼如下:
1 #include
2?
3 int main()
4 {
5 char a[] = "hello world";
6 puts(a);
7 return 0;
8 }
--------------------------------------
puts函數(shù)內(nèi)部可能是如下這樣實(shí)現(xiàn)的:
int puts(const char *s)
{
int index = 0;
while(s[index])
{
putchar(s[index]);
index++;
}
putchar('\n');
return index;
}
putchar函數(shù)的作用:向終端輸出一個(gè)字符。
(1)putchar函數(shù)只能用于單個(gè)字符的輸出捣炬,且一次只能輸出一個(gè)字符熊昌。
(2)在程序中使用putchar函數(shù),務(wù)必牢記:在程序(或文件)的開頭加上編譯預(yù)處理命令(也稱包含命令)湿酸,即:#include "stdio.h"婿屹。
//思考
用putchar就可以實(shí)現(xiàn)puts,printf等輸出函數(shù)推溃。
用getchar就可以實(shí)現(xiàn)scanf昂利,gets等輸入函數(shù)。
-----------------------------------------------------------------------------
fputs函數(shù)是puts函數(shù)的文件操作版本。
int fputs(const char *s, FILE *stream); //注意:const用來修飾char *s, *s的內(nèi)容不可變蜂奸。
第一個(gè)參數(shù)是一個(gè)char的數(shù)組梯捕;第二個(gè)參數(shù)是:如果總是通過屏幕進(jìn)行輸出的話,可以固定寫為stdout窝撵。
fputs并不會(huì)像puts那樣輸出的時(shí)候自動(dòng)結(jié)尾加 \n 傀顾。
linux下示例代碼如下:
1 #include
2?
3 int main()
4 {
5 char a[] = "hello world";?
6 //puts(a); ? //hello world
//root@iZ2zeeailqvwws5dcuivdbZ:~/1/01#
7 //printf(a); ? ? ? //hello worldroot@iZ2zeeailqvwws5dcuivdbZ:~/1/01# 編譯有警告哦
8 ?fputs(a, stdout); //hello worldroot@iZ2zeeailqvwws5dcuivdbZ:~/1/01#
9 return 0;
10 }
--------------------------------------
1 #include
2?
3 int main()
4 {
5 char a[] = "hello world\n";?
6 //puts(a);?
7 //printf(a);
8 ? fputs(a, stdout); //hello world
9 ? return 0; ? ?//root@iZ2zeeailqvwws5dcuivdbZ:~/1/01#
10 }
=============================================================================
求字符串長度函數(shù)strlen
使用這個(gè)庫函數(shù)時(shí)需要包含頭文件<string.h>
"abc",注意:用strlen時(shí)返回的結(jié)果是3,而不是4碌奉。
strlen函數(shù)的基本用法為:
size_t strlen(const char *s);?
參數(shù)是:一個(gè)字符數(shù)組短曾。
返回值是:不包含字符串結(jié)尾'\0'的字符串的長度(注意:是字符串字節(jié)的總數(shù)哦!不同的系統(tǒng)下是不同的)赐劣。
linux下示例代碼如下:
1 #include
2 #include
3?
4 int main()
5 {
6 char a[] = "hello";//char a[] = "hello傳智";
7 unsigned int index = 0;
8 /*
9 while (a[index])
10 {
11 index++;
12 }
13 */
14 index = strlen(a);
15 ? ?printf("%u\n",index);//5 //11
16 return 0;
17 }
=============================================================================
字符串追加函數(shù)strcat
strcat函數(shù)的基本用法為:
char *strcat(char *dest, const char *src);
參數(shù)是:第一個(gè)參數(shù)是一個(gè)字符數(shù)組嫉拐,第二個(gè)參數(shù)是靜態(tài)的字符數(shù)組。
返回值是:一個(gè)字符數(shù)組魁兼。
用strcat的時(shí)候要注意婉徘,第一個(gè)字符串一定要有足夠的空間容納第二個(gè)字符串。
linux下示例代碼如下:
1 #include
2 #include
3?
4 int main()
5 {
6 char a[100] = "abc"; ? //a不是空串時(shí)
7 char b[100] = "hello";
8 ? strcat(a,b); //將a和b合并為一個(gè)字符串咐汞,合并的結(jié)果放入a盖呼。
9 ? printf("%s\n", a); //abchello
10 ?return 0;
11 }
--------------------------------------
1 #include
2 #include
3?
4 int main()
5 {
6 char a[100] = { 0 };//a為空串時(shí) 或者 char a[100] = "";
7 char b[100] = "hello";
8 strcat(a, b);
9 printf("%s\n", a);//hello
10 ? return 0;
11 }
-----------------------------------------------------------------------------
字符串有限追加函數(shù)strncat
strncat函數(shù)的基本用法為:
char *strncat(char *dest, const char *src, size_t n);
參數(shù)是:第一個(gè)參數(shù)是一個(gè)字符數(shù)組,第二個(gè)參數(shù)是靜態(tài)的字符數(shù)組化撕,第三個(gè)參數(shù)代表最多追加幾個(gè)字符几晤。
返回值是:一個(gè)字符數(shù)組。
linux下示例代碼如下:
1 #include
2 #include
3?
4 int main()
5 {
6 char a[100] = "abc";
7 char b[100] = "hello123456789";
8 strncat(a, b, 5);?
9 printf("%s\n", a); //abchello
10 ? return 0;
11 }
=============================================================================
字符串比較函數(shù)strcmp
strcmp函數(shù)的基本用法為:
int strcmp(const char *s1, const char *s2);//比較兩個(gè)字符串是否相等
參數(shù)是:第一個(gè)參數(shù)是一個(gè)靜態(tài)的字符數(shù)組植阴,第二個(gè)參數(shù)是靜態(tài)的字符數(shù)組蟹瘾。
返回值是:int。相等返回0掠手;不相等返回非0.
linux下示例代碼如下:
1 #include
2 #include
3?
4 int main()
5 {
6 char a[100] = "abc";
7 char b[100] = "hel";
8 ? if (strcmp(a, b) == 0)
9 ? {
10 printf("相同\n");
11 }
12 else
13 ? {
14 printf("不相同\n");
15 }
16 ?return 0;
17 }
--------------------------------------
strcmp函數(shù)內(nèi)部可能是如下這樣實(shí)現(xiàn)的:
char a[100] = "abc";
char b[100] = "abc123";
int status = 0;//0代表這兩個(gè)字符串相等憾朴;
//代碼先加一個(gè)判斷,兩個(gè)字符串如果長度不一樣喷鸽,直接設(shè)置status等于1众雷。
int index = 0;
while(a[index])
{
if (a[index] != b[index])
{
status = 1;
break;
}
index++;
}
//這樣就可以通過status的值來判斷兩個(gè)字符串是否相等了。
-----------------------------------------------------------------------------
字符串有限比較函數(shù)strcmp
strncmp函數(shù)的基本用法為:
int strncmp(const char *s1, const char *s2, size_t n);
參數(shù)是:第一個(gè)參數(shù)是一個(gè)靜態(tài)的字符數(shù)組魁衙,第二個(gè)參數(shù)是靜態(tài)的字符數(shù)組报腔,第三個(gè)參數(shù)代表比較幾個(gè)字符。
返回值是:int剖淀。相等返回0纯蛾;不相等返回非0.
linux下示例代碼如下:
1 #include
2 #include
3?
4 int main()
5 {
6 char a[100] = "abc";
7 char b[100] = "hel";
8 if (strncmp(a, b, 2) == 0)
9 {
10 printf("相同\n");
11 ?}
12 ?else
13 ?{
14 ? ?printf("不相同\n");
15 }
16 ?return 0;
17 }
=============================================================================
字符串拷貝函數(shù)strcpy
strcpy函數(shù)的基本用法為:
char *strcpy(char *dest, const char *src);
參數(shù)是:第一個(gè)參數(shù)是一個(gè)字符數(shù)組,第二個(gè)參數(shù)是靜態(tài)的字符數(shù)組纵隔。
返回值是:一個(gè)字符數(shù)組翻诉。
linux下示例代碼如下:
1 #include
2 #include
3?
4 int main()
5 {
6 char a[100] = "abc";
7 char b[100] = "1234";
8 /*
9 //把b的內(nèi)容拷貝到a里面,不使用庫函數(shù)
10 int index = 0;
11 ? while (b[index])
12 {?
13 a[index] = b[index];
14 index++;
15 }
16 */
17 //把b的內(nèi)容拷貝到a里面,使用庫函數(shù)
18 strcpy(a, b);
19 printf("%s\n", a);//1234
20 ?return 0;
21 }
-----------------------------------------------------------------------------
字符串有限拷貝函數(shù)strncpy
strncpy函數(shù)的基本用法為:
char *strncpy(char *dest, const char *src, size_t n);
參數(shù)是:第一個(gè)參數(shù)是一個(gè)靜態(tài)的字符數(shù)組炮姨,第二個(gè)參數(shù)是靜態(tài)的字符數(shù)組,第三個(gè)參數(shù)代表比較幾個(gè)字符碰煌。
返回值是:一個(gè)字符數(shù)組舒岸。
linux下示例代碼如下:
1 #include
2 #include
3?
4 int main()
5 {
6 char a[100] = "abc";
7 char b[100] = "1234";
8 //把b的有限內(nèi)容拷貝到a里面,使用庫函數(shù)
9 strncpy(a, b, 2);//strncpy(a, b, sizeof(a) - 1);
10 ?printf("%s\n", a);//12c//123
11 ?return 0;
12 }
=============================================================================
格式化字符串函數(shù)sprintf(輸出)
printf是向標(biāo)準(zhǔn)輸出設(shè)備輸出一個(gè)字符串。
sprintf向一個(gè)char的數(shù)組輸出一個(gè)字符串芦圾。
超級特別注意:可以使用sprintf將一個(gè)int或者其他類型轉(zhuǎn)化為一個(gè)字符串蛾派。
和printf函數(shù)功能類似,printf函數(shù)格式化結(jié)果輸出到屏幕(或標(biāo)準(zhǔn)輸出設(shè)備)个少,
sprintf將格式化結(jié)果輸出到字符串洪乍,并不會(huì)將結(jié)果打印到標(biāo)準(zhǔn)輸出設(shè)備上去。
sprintf使用方法與printf類似夜焦,唯一的區(qū)別是多了第一個(gè)參數(shù)壳澳,第一個(gè)參數(shù)是一個(gè)char的數(shù)組。
sprintf的使用方法和printf基本一致茫经,
特別注意:所有printf的轉(zhuǎn)義符對于sprintf是一樣的巷波。
linux下示例代碼如下:
1 #include
2?
3 int main()
4 {
5 char a[100] = { 0 };
6 ? ?sprintf(a, "%s\n", "hello"); //不加下一句printf,屏幕上什么也不會(huì)輸出卸伞。
7 printf("%s", a);//hello
8 return 0;
9 }?
-----------------------------------------------------------------------------
格式化字符串函數(shù)sscanf(讀取輸入)
scanf從鍵盤讀取用戶輸入數(shù)據(jù)抹镊,sscanf從指定格式化字符串讀取輸入。
即sscanf從某一個(gè)格式化字符串中讀取到我們想要的東西瞪慧,找到后通過轉(zhuǎn)義的方式取出來髓考,取出來后我們就可以繼續(xù)進(jìn)行想要的處理了。
sscanf函數(shù)類似于scanf函數(shù)弃酌,唯一的區(qū)別是多了第一個(gè)參數(shù),第一個(gè)參數(shù)是一個(gè)char的數(shù)組儡炼。
linux下示例代碼如下:
1 #include
2?
3 int main()
4 {
5 char a[100] = "56+72";
6 int i;
7 int j;
8 sscanf(a, "%d+%d", &i, &j); //sscanf從某一個(gè)格式化字符串中讀取到我們想要的東西妓湘,找到后通過轉(zhuǎn)義的方式取出來。
9 printf("%d+%d=%d\n", i, j, i + j); ?//取出來后我們就可以繼續(xù)進(jìn)行想要的處理了乌询。
10 return 0;
11 }
=============================================================================
課堂小練習(xí):解析一個(gè)字符串
例如:
有一個(gè)字符數(shù)組榜贴,char a[100] = "43+56="; 整數(shù)是任意的,中間可能是 + - * / 任意一個(gè)妹田。
現(xiàn)在寫一個(gè)程序唬党,將計(jì)算的結(jié)果追加到字符串a(chǎn)的后面。也即:程序執(zhí)行完成后a的值是"43+56=99"鬼佣。
linux下示例代碼如下:
1 #include
2?
3 int main()
4 {
5 char a[100] = "56+72=";
6 int i;
7 int j;
8 char c;
9 //printf("%d, %c, %d\n",i, c, j);//打印看看結(jié)果
10 ? sscanf(a, "%d%c%d", &i, &c, &j);//從字符串里面把想要的字符提取出來驶拱。
11?
12 ? int res = 0;
13 switch(c)
14 {
15 case '+':
16 res = i + j;
17 break;
18 case '-':
19 res = i - j;
20 break;
21 case '*':
22 res = i * j;
23 break;
24 case '/':
25 res = i / j;
26 ? ?break;
27 default:
28 res = 0;
29 }
30 sprintf(a, "%d%c%d=%d", i, c, j, res);
31 printf("%s\n", a);
32 return 0;
33 }
=============================================================================
字符串查找字符函數(shù)strchr
strchr函數(shù)的基本用法為:
char *strchr(const char *s, int c); //功能:在指定的字符串里面找指定的相關(guān)字符的子串。
參數(shù)是:第一個(gè)參數(shù)是一個(gè)靜態(tài)的字符數(shù)組晶衷,第二個(gè)參數(shù)是int(其實(shí)是一個(gè)字符的ASCII)蓝纲。
返回值是:一個(gè)字符數(shù)組阴孟。
linux下示例代碼如下:
1 #include
2 #include
3?
4 int main()
5 {
6 char a[100] = "hello world";
7 char *s;//定義了一個(gè)char類型的指針變量
8 s = strchr(a, 'l');//注意是一個(gè)字符
9?
10 ?if (s != NULL)
11 ? {
12 printf("%s\n", s); //llo world
13 }?
14 return 0;
15 }
-----------------------------------------------------------------------------
字符串查找子串函數(shù)strstr
strstr函數(shù)的基本用法為:
char *strstr(const char *haystack, const char *needle);
參數(shù)是:第一個(gè)參數(shù)是一個(gè)靜態(tài)的字符數(shù)組,第二個(gè)參數(shù)也是靜態(tài)的字符數(shù)組(其實(shí)是一個(gè)字符串)税迷。
返回值是:一個(gè)字符數(shù)組永丝。
linux下示例代碼如下:
1 #include
2 #include
3?
4 int main()
5 {
6 char a[100] = "hello world";
7 char *s;//定義了一個(gè)char類型的指針變量
8 s = strstr(a, "wo");//注意是一個(gè)字符串
9?
10 if (s != NULL)
11 {
12 printf("%s\n", s);//world
13 }
14 return 0;
15 }
strchr與strstr如果找不到,返回NULL(空指針)箭养。
=============================================================================
字符串分割函數(shù)strtok
strtok函數(shù)的基本用法為:
char *strtok(char *str, const char *delim);
參數(shù)是:第一個(gè)參數(shù)是一個(gè)字符數(shù)組慕嚷;第二個(gè)參數(shù)也是一個(gè)靜態(tài)的字符數(shù)組(其實(shí)是一個(gè)字符串)。
返回值是:一個(gè)字符數(shù)組毕泌。
注意:
linux下示例代碼如下:
1 #include
2 #include
3?
4 int main()
5 {
6 char a[100] = "abc_565656_asadsd";
7 char *s; //定義一個(gè)char的指針變量
8 s = strtok(a, "_");
9 printf("%s\n", s);//abc
10?
11 ?s = strtok(NULL, "_"); //注意:在第二次至以后調(diào)用strtok函數(shù)時(shí)闯冷,第一個(gè)參數(shù)寫NULL。
12 ?printf("%s\n", s);//565656
13?
14 ?s = strtok(NULL, "_");
15 ?printf("%s\n", s);//asadsd
16?
17 ?s = strtok(NULL, "_");
18 ?printf("%s\n", s); //Segmentation fault(分段故障)
19 ? ? ? return 0;
20?
21 }
如果要分割的字符串已經(jīng)到了字符串結(jié)尾懈词,若繼續(xù)調(diào)用strtok則返回Segmentation fault(分段故障)蛇耀。
-----------------------------------------------------------------------------
上面代碼的簡化代碼如下:
linux下示例代碼如下:
1 #include
2 #include
3?
4 int main()
5 {
6 char a[100] = "abc_565656_asadsd";
7 char *s;//定義一個(gè)char的指針變量
8 s = strtok(a, "_");
9?
10 ?while (s) //當(dāng)s = NULL時(shí),就是0,0就是假坎弯。
11 ? ? ?{
12 printf("%s\n", s);
13 s = strtok(NULL, "_");
14 ?}
15 return 0;
16?
17 }
=============================================================================
atoi函數(shù)
atoi函數(shù)的功能是:把一個(gè)char的數(shù)組轉(zhuǎn)化為一個(gè)int纺涤,需要頭文件stdlib.h。
int atoi(const char *nptr);
linux下示例代碼如下:
1 #include
2 #include
3?
4 int main()
5 {
6 char a[100] = "123"; //如何把一個(gè)字符串轉(zhuǎn)化為一個(gè)整數(shù)抠忘?
7 char b[100] = "500";
8?
9 int i = 0;
10 ?i = atoi(a) + atoi(b);
11 printf("%d\n", i);//623
12 return 0;
13 }
-----------------------------------------------------------------------------
atof函數(shù)
atof函數(shù)的功能是:把一個(gè)小數(shù)形式的字符轉(zhuǎn)化為一個(gè)浮點(diǎn)數(shù)撩炊。
double atof(const char *nptr);
linux下示例代碼如下:
1 #include
2 #include
3?
4 int main()
5 {
6 char a[100] = "123.5";
7 char b[100] = "500.489";
8?
9 double i = 0;
10 ? i = atof(a) + atof(b);
11 ?printf("%f\n", i);
12 ?return 0;
13 }
-----------------------------------------------------------------------------
atol函數(shù)
atol函數(shù)的功能是:把一個(gè)字符串轉(zhuǎn)化為long類型。
long atol(const char *nptr);
long long atoll(const char *nptr);
-----------------------------------------------------------------------------
在c語言里面提供了把字符串轉(zhuǎn)化為整數(shù)的函數(shù)崎脉,但并沒有提供把整數(shù)轉(zhuǎn)化為字符串的函數(shù)拧咳,
即:atoi是標(biāo)準(zhǔn)的c語言庫函數(shù),itoa不是c語言標(biāo)準(zhǔn)的庫函數(shù)囚灼。(itoa可以在vs2017下編譯骆膝,但在其他系統(tǒng)下就未知了。)
所以不要嘗試使用itoa這種函數(shù)灶体,可以使用sprintf將一個(gè)int或者其他類型轉(zhuǎn)化為一個(gè)字符串阅签。
即:sprintf可以實(shí)現(xiàn)將數(shù)字轉(zhuǎn)化為字符串的功能。
linux下示例代碼如下:
1 #include
2 #include
3?
4 int main()
5 {
6 char a[100] = "1234";
7 char b[100] = "abc";
8 int c = 45;
9 sprintf(a, "%d", c); //a[100] = "45";
10 ?strcat(b, a);
11 ?printf("%s\n", b); //abc45
12 ?return 0;
13 }
=============================================================================
課堂小練習(xí):解析一個(gè)字符串的高級應(yīng)用
例如:
有一個(gè)字符數(shù)組 char a[100] = "12+5=;45-2=;34*2=;54/3=";
這個(gè)字符數(shù)組到底有多少分號(hào)是不確定的蝎抽,
寫個(gè)程序政钟,執(zhí)行后"="號(hào)后面自動(dòng)添加計(jì)算結(jié)果。如下:
“12+5=17;45-2=43;34*2=68;54/3=18”
linux下示例代碼如下:
1 #include
2 #include
3 #include
4?
5 int main()
6 {
7 char a[100] = "12+5=;45-2=;34*2=;54/3=";
8 char b[100] = { 0 };//注意:b是空串罢两帷Q弧!瓢宦!
9 char *s = strtok(a, ";");
10 while (s)
11 {
12 //printf("%s\n", s);
13 int i, j;
14 char c;
15 sscanf(s, "%d%c%d=", &i, &c, &j);
16?
17 int res = 0;
18 ?switch (c)
19 {
20 case '+':
21 res = i + j;
22 break;
23 case '-':
24 res = i - j;
25 break;
26 case '*':
27 res = i * j;
28 break;
29 case '/':
30 res = i / j;
31 break;
32 defalut:
33 res = 0;
34 }
35 //printf("%s%d\n", s, res);
36 //printf("%s%d", s, res);
37 char tmp[10] = { 0 };
38 sprintf(tmp, "%s%d;", s, res);
39 strcat(b, tmp);
40 ? s =strtok(NULL, ";");
41 }
42 strcpy(a, b);
43 printf("%s\n", a);
44 return 0;
45 }
=============================================================================
函數(shù)的定義和聲明
前幾節(jié)學(xué)習(xí)c語言庫函數(shù)的使用碎连,而實(shí)際呢?我們有必要去自己寫函數(shù)刁笙,因?yàn)閏語言庫函數(shù)并不能滿足我們所有的應(yīng)用。即自定義函數(shù)。
在使用函數(shù)前必須要定義或者聲明函數(shù)或者就把整個(gè)函數(shù)寫在main函數(shù)的上面嫌套。
特備注意:自己定義的函數(shù)有兩種聲明有兩種格式。
linux下示例代碼如下:
1 #include
2?
3 //調(diào)用函數(shù)的聲明前鹅。
4 void test1();?
5?
6 //這是一個(gè)自定義的函數(shù),函數(shù)名叫add峭梳,返回值類型是int類型舰绘,函數(shù)有兩個(gè)參數(shù),分別是a和b葱椭。
7 int add(int a, int b)
8 {?
9 return a + b;
10 }
11?
12 //這是一個(gè)自定義的函數(shù)捂寿,函數(shù)名叫test,沒有返回值孵运,沒有參數(shù)秦陋。
13 void test()
14 {?
15 printf("test\n");
16 }
17?
18 void test2(int a) //a是形參。
19 {?
20 printf("a = %d\n", a);
21 }
22?
23 int main()
24 {?
25 int i = 2;
26 int j = 5;
27 int c = add(i, j); //調(diào)用一個(gè)有參數(shù)治笨,有返回值的函數(shù)驳概。
28 printf("%d\n", c);
29 test(); //調(diào)用一個(gè)沒有參數(shù),沒有返回值的函數(shù)旷赖。
30 test1(); //調(diào)用一個(gè)沒有參數(shù)顺又,沒有返回值的函數(shù)。注意這種調(diào)用方式需要在前面進(jìn)行聲明等孵。
31 test2(j); //j是實(shí)參稚照。 //test2(8); //test2(20 + 4); //test(i + j);
32 return 0;
33 }
-----------------------------------------------------------------------------
函數(shù)的形式參數(shù)(形參)與實(shí)際參數(shù)(實(shí)參)
在調(diào)用函數(shù)的時(shí)候俯萌,函數(shù)大多數(shù)都有參數(shù)果录,主調(diào)函數(shù)和被調(diào)函數(shù)之間需要傳遞數(shù)據(jù)。
在定義函數(shù)時(shí)函數(shù)名后面括弧中的變量名稱為“形式參數(shù)”绳瘟,簡稱形參雕憔。
在調(diào)用函數(shù)時(shí),函數(shù)名后面的括弧中的變量或者表達(dá)式稱為“實(shí)際參數(shù)”糖声,簡稱實(shí)參。
注意幾點(diǎn):
1分瘦、形參在未出現(xiàn)函數(shù)調(diào)用的時(shí)蘸泻,他們并不占用內(nèi)存單元,只有在發(fā)生函數(shù)調(diào)用的時(shí)候形參才被分配內(nèi)存嘲玫,函數(shù)調(diào)用完成后悦施,形參所占用的內(nèi)存被釋放。
2去团、實(shí)參可以使變量抡诞、常量或者表達(dá)式穷蛹。
3、在定義函數(shù)時(shí)昼汗,一定要指定形參的數(shù)據(jù)類型肴熏。
4、形參與實(shí)參的數(shù)據(jù)類型一定可兼容顷窒。
5蛙吏、在c語言中,實(shí)參與形參的數(shù)據(jù)傳遞是“值的傳遞”鞋吉,即單向傳遞鸦做,即只由實(shí)參傳遞給形參,而不能有形參傳遞給實(shí)參谓着。
即:
實(shí)參的值單向的給形參泼诱,但形參的值不會(huì)傳遞給實(shí)參。
形參的值來自于實(shí)參赊锚,但形參的值改變后并不會(huì)改變實(shí)參的值治筒。
linux下示例代碼如下:
1 #include
2?
3 void test2(int a)
4 {
5 ++a;
6 printf("a = %d\n", a);
7 }
8?
9 int main()
10 {
11 int i = 5;
12 test2(i);
13 printf("i = %d\n", i);//輸出:a = 6 i = 5
14 return 0;
15 }
-------------------------------------
小知識(shí)復(fù)習(xí):
b = a++; //先計(jì)算表達(dá)式的值,即先把a(bǔ)賦值給了b改抡;然后a再自加1矢炼。
b = ++a; //先a自加1后阿纤;然后把a(bǔ)自加后得到的賦值給b句灌。
小結(jié):誰在前面先計(jì)算誰!G肥啊胰锌!
-------------------------------------
-----------------------------------------------------------------------------
函數(shù)的返回值類型和返回值
1、函數(shù)的返回值通過函數(shù)中的return獲得的藐窄,如果函數(shù)的返回值為void资昧,則不需要return語句。
2荆忍、函數(shù)ruturn語句中的返回值數(shù)據(jù)類型應(yīng)該與定義函數(shù)時(shí)相同格带。
3、如果函數(shù)中沒有return語句刹枉,那么函數(shù)將返回一個(gè)不確定的值叽唱。
-----------------------------------------------------------------------------
return函數(shù)與exit函數(shù)(exit更猛,不受位置限制)
exit是c語言的庫函數(shù)微宝,有一個(gè)整型的參數(shù)棺亭,代表進(jìn)程終止。使用這個(gè)函數(shù)需要stdlib.h這個(gè)頭文件蟋软。
在函數(shù)中寫return只是代表函數(shù)終止了镶摘,但不管在程序的任何位置調(diào)用exit嗽桩,那么整個(gè)程序馬上終止了。
在main函數(shù)中執(zhí)行return語句凄敢,程序終止碌冶,但在子函數(shù)中執(zhí)行return只是子函數(shù)終止了,但main依舊運(yùn)行贡未。
在main函數(shù)中執(zhí)行return或者調(diào)用exit結(jié)果是一樣的种樱。
=============================================================================
課堂小練習(xí):
自定義一個(gè)函數(shù),實(shí)現(xiàn)大小寫字母的互相轉(zhuǎn)換功能俊卤。
例如:小寫的a的ASCII是97嫩挤,大寫的A的ASCII是65。
其實(shí)大小寫字母的ASCII相差是32哦消恍,但空格的ASCII是32岂昭。
linux下示例代碼如下:
1 #include
2?
3 char trans(char c)
4 {
5 if (c >= 'a' && c <= 'z')
6 {
7 return c - ' ';
8 }
9 if (c >= 'A' && c <= 'Z')
10 {
11 return c + ' ';
12 }
13 }?
14?
15 int main()
16 {
17 char a = 'r';
18 printf("%c\n", trans(a));
19 return 0;
20 }
-----------------------------------------------------------------------------
c語言有個(gè)庫函數(shù),名字叫atoi狠怨,將一個(gè)字符串轉(zhuǎn)化為整數(shù)约啊。
自定義一個(gè)函數(shù),實(shí)現(xiàn)atoi的功能佣赖,要求是不能使用任何c語言已有的庫函數(shù)恰矩。
"123"
'1' '2''3' '\0'
步驟:
0、首先知道這個(gè)字符串有多長憎蛤。(如果字符串是3位長外傅,那么第一位 * 10 2次方。)
1俩檬、遍歷這個(gè)字符串萎胰。
2、將第一個(gè)'1'取出來棚辽,然后把'1'轉(zhuǎn)化為整數(shù)1技竟,把1 * 100。
將'2'取出來屈藐,轉(zhuǎn)化為2榔组,2 * 10。
將'3'取出來联逻,轉(zhuǎn)化為3瓷患。
3、1 * 100 + 2 * 10 + 3 = 123遣妥;
注意:'0'的ASCII的值是48,'1'的ASCII的值是49攀细,'2'的ASCII的值是50等等箫踩。
所以字符1('1')轉(zhuǎn)換為數(shù)字1(1)就是讓字符1減去字符0可得爱态,
即?
0 = '0' - '0',
1 = '1' - '0'境钟,
2 = '2' - '0'锦担,
......
linux下示例代碼如下:
1 #include
2?
3 //得到一個(gè)字符串長度的函數(shù)
4 int my_strlen(const char *s)
5 {
6 int len = 0;
7 while (s[len])
8 {
9 len++;
10 }
11 return len;
12 }
13?
14 //得到10的n次方的函數(shù)
15 int my_pow10(int n)
16 {
17 if (n == 0) //10的0次方
18 return 1;
19 if (n == 1) //10的1次方
20 return 10;
21?
22 int base = 10;
23 int i;
24 for (i = 1; i < n; i++)
25 {
26 base *= 10;
27 }
28 return base;
29 }
30?
31 //把一個(gè)字符轉(zhuǎn)換為一個(gè)0到9整數(shù)的函數(shù)
32 int my_chartoint(char c)
33 {
34 return c - '0';
35 }
36?
37 //把一個(gè)字符串轉(zhuǎn)化為整數(shù)的函數(shù)
38 int my_atoi(const char *nptr)
39 {
40 int len = my_strlen(nptr);
41?
42 int value = 0;
43 int i;
44 for (i = 0; i < len; i++)
45 {
46 value += my_chartoint(nptr[i]) * my_pow10(len - 1 - i);
47 }
48 return value;
49?}
50?
51 int main()
52 {
53 char a[] = "123";
54 int i = my_atoi(a);
55 printf("%d\n", i);
56 ? return 0;
57 }
=============================================================================
函數(shù)的遞歸
函數(shù)可以自己調(diào)用自己,這就叫函數(shù)的遞歸慨削。
linux下示例代碼如下:
典型的遞歸代碼:
1 #include
2?
3 void test(int n)
4 {
5 printf("n = %d\n", n);
6 if (n < 3)
7 {
8 test(n + 1);
9 }
10 }
11?
12 int main()
13 {
14 int a = 0;
15 test(a);
16 return 0;
17 }
輸出
n = 0
n = 1
n = 2
n = 3
-----------------------------------------------------------------------------
1 #include
2?
3 void test(int n)
4 {
5 //printf("n = %d\n", n);
6 if (n < 3)
7 {
8 test(n + 1);
9 }
10 ? printf("n = %d\n", n);
11 }
12?
13 int main()
14 {?
15 int a = 0;
16 test(a);
17 return 0;
18 }
輸出
n = 3
n = 2
n = 1
n = 0
-----------------------------------------------------------------------------
即:
test(0)
{
test(1)
{
test(2)
{
test(3)
{
不符合條件退出if判斷語句了洞渔。
printf("n = %d\n", n);//第一次輸出:n = 3
}
printf("n = %d\n", n);//第二次輸出:n = 2
}
printf("n = %d\n", n);//第三次輸出:n = 1
}
printf("n = %d\n", n);//第四次輸出:n = 0
}
-----------------------------------------------------------------------------
1 #include
2?
3 void test(int n)
4 {
5 printf("n = %d\n", n);//把代碼放到遞歸的前面,叫做先序遞歸缚态。
6 if (n < 3)//遞歸一定要有個(gè)終止條件磁椒。
7 {
8 test(n + 1);
9 ? }
10 ?printf("n = %d\n", n);//把代碼放到遞歸的后面,叫做后序遞歸玫芦。
11 }
12?
13 int main()
14 {?
15 int a = 0;
16 test(a);
17 return 0;
18 }
輸出
n = 0
n = 1
n = 2
n = 3
n = 3
n = 2
n = 1
n = 0
-----------------------------------------------------------------------------
遞歸例子:
有n個(gè)人排成一隊(duì)浆熔,
問第n個(gè)人多少歲,他回答比前面一個(gè)人大2歲桥帆,
再問前面一個(gè)人多少歲医增,他回答比前面一個(gè)人大2歲,
一直問到最后面的一個(gè)人老虫,他回答他是10歲叶骨。
linux下示例代碼如下:
1 #include
2?
3 int age(int n)
4 {
5 if (n == 1) //終止條件
6 {
7 return 10;
8 }
9 else
10 ?{
11 return age(n - 1) + 2;
12 ?}
13 }
14?
15 int main()
16 {
17 int a = 5;
18 printf("%d\n", age(a));//18
19 }
-----------------------------------------------------------------------------
遞歸例子:
將10進(jìn)制數(shù)轉(zhuǎn)化為二進(jìn)制數(shù)。
例如:求十進(jìn)制數(shù)13的二進(jìn)制數(shù)祈匙。
2 13?
6 1
3 0
1 1
0 1
商數(shù) 余數(shù)
倒過來看余數(shù)得:
(13)10 = (1101)2
linux下示例代碼如下:
1 #include
2?
3 void to_bin(unsigned int n)
4 {
5 int i = n % 2;//得到余數(shù)
6 ? ? ? ?//printf("%d\n", i);//看一下忽刽,輸出的余數(shù)。發(fā)現(xiàn)是先序遞歸菊卷。而我們需要的二進(jìn)制需要倒過來缔恳,該如何呢?用后序遞歸洁闰。
7?
8 if (n > 2)
9 {
10 to_bin(n / 2);
11 }
12?
13 printf("%d", i);
14?
15 }
16?
17 int main()
18 {
19 int a = 1300;
20 scanf("%d", &a);
21 to_bin(a);
22 printf("\n");
23 return 0;
24 }
-----------------------------------------------------------------------------
遞歸例子:
寫一個(gè)函數(shù)歉甚,將10進(jìn)制數(shù)轉(zhuǎn)化為16進(jìn)制,不能使用c語言庫函數(shù)扑眉。
不能如下這樣爸叫埂:
void to_hex(int n)
{
printf("%x", n);
}
例如:求十進(jìn)制數(shù)130的十六進(jìn)制數(shù)。
16 130?
8 2
0 8
商數(shù) ? 余數(shù)
倒過來看余數(shù)得:
(130)10 = (82)16
linux下示例代碼如下:
1 #include
2?
3 char hex_char(unsigned int n)
4 {
5 switch (n)
6 {
7 case 0:
8 return '0';
9 case 1:
10 ? return '1';
11 case 2:
12 ? return '2';
13 case 3:
14 ? return '3';
15 case 4:
16 return '4';
17 case 5:
18 return '5';
19 case 6:
20 return '6';
21 case 7:
22 return '7';
23 case 8:
24 return '8';
25 case 9:
26 return '9';
27 case 10:
28 ?return 'a';
29 ? case 11:
30 ? return 'b';
31 case 12:
32 ? return 'c';
33 case 13:
34 ? ?return 'd';
35 case 14:
36 return 'e';
37 case 15:
38 return 'f';
39 }
40 return '0';
41 }
42?
43 void to_hex(unsigned int n)
44 {
45 int i = n % 16;//得到余數(shù)
46 //printf("%d\n", i);//看一下腰素,輸出的余數(shù)聘裁。發(fā)現(xiàn)是先序遞歸。而我們需要的二進(jìn)制需要倒過來弓千,該如何呢衡便?用后序遞歸。
47?
48 if (n > 16)
49 {
50 to_hex(n / 16);
51 }
52?
53 printf("%c",hex_char(i));
54?
55 }
56?
57 int main()
58 {
59 int a = 1300;
60 scanf("%d", &a);
61 to_hex(a);
62 printf("\n");
63 return 0;
64 }
-----------------------------------------------------------------------------
遞歸例子:
菲波那切數(shù)列:
0,1镣陕,1谴餐,2,3呆抑,5岂嗓,8,13鹊碍,21厌殉,34,55侈咕,89公罕,144,......
第零項(xiàng)是0乎完;
第一項(xiàng)是1熏兄;
第二項(xiàng)是1;
第三項(xiàng)是2树姨;
第四項(xiàng)是3摩桶;
......
該數(shù)列從第二項(xiàng)開始,每一項(xiàng)等于前兩項(xiàng)之和帽揪。
linux下示例代碼如下:
1 #include
2?
3 int fib(int n)
4 {
5 if (n == 0)
6 return 0;
7 if (n == 1)
8 return 1;
9 if (n > 1)
10 return fib(n - 1) + fib(n - 2);
11 }
12?
13 int main()
14 {
15 int i;
16 for (i = 0; i < 20; i++)
17 {
18 printf("%d\n", fib(i));
19 }
20 return 0;
21 }
-----------------------------------------------------------------------------
遞歸的優(yōu)點(diǎn):
遞歸給某些編程問題提供了簡單的方法硝清。
遞歸缺點(diǎn):
一個(gè)有缺陷的遞歸會(huì)很快耗盡計(jì)算機(jī)的資源,遞歸的程序難以理解和維護(hù)转晰。
筆試的時(shí)候很可能考遞歸哦芦拿!考驗(yàn)的是智力和思維的能力。
因?yàn)樗哪莻€(gè)圖想起來很費(fèi)勁查邢!需要多加訓(xùn)練蔗崎。
聯(lián)想到我們小時(shí)候聽說的一個(gè)故事:從前有座山,山里有座廟......
或者是畫中畫的放大與縮小的效應(yīng)扰藕。
=============================================================================
多個(gè)源代碼文件程序如何編譯缓苛?
1、頭文件的使用
如何把我們的代碼分解為多個(gè)函數(shù)邓深,如何把函數(shù)放進(jìn)不同的文件里面未桥。
因?yàn)閷?shí)際中我們的函數(shù)是散落在多個(gè)文件里面的。
-----------------------------------------------------------------------------
方法一:
如果把main函數(shù)放在第一個(gè)文件中芥备,而把自定義的函數(shù)放在第二個(gè)文件中冬耿,
那么調(diào)用第二個(gè)文件中的自定義函數(shù)時(shí)就要在第一個(gè)文件中聲明該函數(shù)原型。
方法二:
如果把很多個(gè)函數(shù)原型包含在一個(gè)頭文件里萌壳,那么就不必每次使用自定義的函數(shù)的時(shí)候去聲明函數(shù)原型了亦镶。
把函數(shù)聲明放入頭文件是個(gè)很好的習(xí)慣H赵隆!染乌!
-----------------------------------------------------------------------------
方法一:
如果把main函數(shù)放在第一個(gè)文件中山孔,而把自定義的函數(shù)放在第二個(gè)文件中,
那么調(diào)用第二個(gè)文件中的自定義函數(shù)時(shí)就要在第一個(gè)文件中聲明該函數(shù)原型荷憋。
(即自定義函數(shù)的申明放在有main函數(shù)的第一個(gè)文件中,自定義函數(shù)的定義放在第二個(gè)文件中)
需要在編譯的時(shí)候?qū)Χ哌M(jìn)行一起編譯才行哦褐望!
------------------------------------
例如:
第一個(gè)文件func9.c:
#include
int max(int a, int b);
int add(int a, int b);
int main()
{
int a = 10;
int b = 20;
printf("%d\n", max(a, b));
printf("%d\n", add(a, b));
return 0;
}
------------------------------------
第二個(gè)文件aa.c:
int max(int a, int b)
{
return (a > b) ? a : b;
}
int add(int a, int b)
{
return a + b;
}
一起進(jìn)行編譯:gcc -o f9 func9.c aa.c
-----------------------------------------------------------------------------
上面方法一在主函數(shù)里面聲明函數(shù)原型比較啰嗦勒庄,我們一般不這么做!我們一般用方法二:
方法二:
如果把很多個(gè)函數(shù)聲明原型包含在一個(gè)頭文件里瘫里,那么就不必每次使用自定義的函數(shù)的時(shí)候去聲明函數(shù)原型了实蔽。
把函數(shù)聲明放入頭文件是個(gè)很好的習(xí)慣!=鞫痢局装!
------------------------------------
第一個(gè)文件func9.c:
#include
#include "aa.h"http://雙引號(hào)表示在當(dāng)前目錄下
int main()
{
int a = 10;
int b = 20;
printf("%d\n", max(a, b));
printf("%d\n", add(a, b));
return 0;
}
------------------------------------
第二個(gè)文件aa.c:
#include
int max(int a, int b)
{
return (a > b) ? a : b;
}
int add(int a, int b)
{
return a + b;
}
------------------------------------
第三個(gè)文件aa.h:
int max(int a, int b);
int add(int a, int b);
一起進(jìn)行編譯:gcc -o f9 func9.c aa.c
-----------------------------------------------------------------------------
其實(shí)方法二也有些問題!
如果第一個(gè)文件func9.c中多次出現(xiàn)include劳殖,如下這一句:
#include "a.h"
#include "a.h"
#include "a.h"
進(jìn)行預(yù)編譯:gcc -o ff func9.c -E
則預(yù)編譯時(shí)會(huì)出現(xiàn)多次函數(shù)聲明铐尚!那么如何避免多次出現(xiàn)include呢?
(問題如下圖)
-----------------------------------------------------------------------------
#include 是預(yù)編譯指令哆姻,代表頭文件包含宣增。
#define 定義一個(gè)宏常量。
學(xué)習(xí) #ifdef 與 #ifndef矛缨。
#ifdef 是個(gè)預(yù)編譯指令爹脾,代表只要定義了一個(gè)宏常量,那么就預(yù)編譯下面的代碼箕昭。
#ifndef 是個(gè)預(yù)編譯指令灵妨,代表只要沒有定義了一個(gè)宏常量,那么就預(yù)編譯下面的代碼落竹。
格式如下:
#define 宏
#ifdef 宏
代碼
#endif
演示如下圖:
還有另一種寫法哦泌霍,這里不再贅述!
------------------------------------
鑒于此筋量,我們對aa.h進(jìn)行改造烹吵。
#ifndef _A_H
#define _A_H
int max(int a, int b);
int add(int a, int b);
#endif
//這樣寫的效果是:不管這個(gè)頭文件被包含多少次,只有一次生效桨武。
//這是c語言大多數(shù)的頭文件都會(huì)寫成這個(gè)樣子肋拔,這樣會(huì)避免被多次預(yù)編譯。
.c文件里面放的是函數(shù)的定義呀酸。
.h文件里面放的是函數(shù)的聲明凉蜂。
=============================================================================
“我是一名從事了10年開發(fā)的老程序員,最近我花了一些時(shí)間整理關(guān)于C語言、C++窿吩,自己有做的材料的整合茎杂,一個(gè)完整的學(xué)習(xí)C語言、C++的路線纫雁,學(xué)習(xí)材料和工具煌往。C/C++、編程愛好者的聚集地就在我這里 <進(jìn)入下方專欄就能看到及領(lǐng)取>轧邪!歡迎初學(xué)和進(jìn)階中的小伙伴刽脖。希望你也能憑自己的努力,成為下一個(gè)優(yōu)秀的程序員忌愚。工作需要曲管、感興趣、為了入行硕糊、轉(zhuǎn)行需要學(xué)習(xí)C/C++的伙伴可以跟我一起學(xué)習(xí)院水!”
關(guān)注我的專欄,帶你遨游代碼世界简十!C語言/C++進(jìn)階之路 - 專題 - 簡書
最后分享一張C/C++學(xué)習(xí)路線圖給愛學(xué)習(xí)的小伙伴們