?? 歡迎大家來到貝蒂大講堂??
????養(yǎng)成好習(xí)慣,先贊后看哦~????
所屬專欄:C語言學(xué)習(xí)
貝蒂的主頁:Betty‘s blog
1. 函數(shù)的概念
在數(shù)學(xué)中我們就知道了函數(shù)這個(gè)概念,而C語言同樣引入了函數(shù)這個(gè)概念,那C語言的函數(shù)到底是什么樣的呢?
在C語言中,函數(shù)也叫子程序,它是一段可以重復(fù)使用的代碼,用來獨(dú)立地完成某個(gè)功能,它可以接收用戶傳遞的數(shù)據(jù),也可以不接收。
2. 函數(shù)的分類
C語?的程序其實(shí)是由?數(shù)個(gè)?的函數(shù)組合?成的,也可以說:?個(gè)?的計(jì)算任務(wù)可以分解成若?個(gè)較?的函數(shù)(對應(yīng)較?的任務(wù))完成。同時(shí)?個(gè)函數(shù)如果能完成某項(xiàng)特定任務(wù)的話,這個(gè)函數(shù)也是可以復(fù)?的,提升了開發(fā)軟件的效率。而C語言函數(shù)大致可以分為兩類:庫函數(shù)與自定義函數(shù)
2.1 庫函數(shù)
C語?標(biāo)準(zhǔn)中規(guī)定了C語?的各種語法規(guī)則,但是C語?并不提供庫函數(shù);C語?的國際標(biāo)準(zhǔn)ANSIC規(guī)定了?些常?的函數(shù)的標(biāo)準(zhǔn),被稱為標(biāo)準(zhǔn)庫,那不同的編譯器?商根據(jù)ANSI提供的C語?標(biāo)準(zhǔn)就給出了?系列函數(shù)的實(shí)現(xiàn)。這些函數(shù)就被稱為庫函數(shù)。
比如說我們前面學(xué)習(xí)的printf和scanf都是庫函數(shù),它的頭文件時(shí)<stdio.h>。但是我們今天的主題不是講解庫函數(shù),如果大家想學(xué)習(xí)其他庫函數(shù),可以去C/C++官方學(xué)習(xí)
2.2 自定義函數(shù)
自定義函數(shù)是由程序員自主設(shè)計(jì)的函數(shù),和庫函數(shù)一樣有函數(shù)名、返回類型、形式參數(shù)等,今天我們的目標(biāo)就是學(xué)習(xí)如何寫自定義函數(shù)。
3. 自定義函數(shù)
3.1 語法
dataType functionName(形式參數(shù))
{
//body
}
- dataType 是返回值類型,它可以是C語言中的任意數(shù)據(jù)類型,例如 int、float、char 等。
- functionName 是函數(shù)名,它是標(biāo)識符的一種,命名規(guī)則和標(biāo)識符相同。函數(shù)名后面的括號
( )
不能少。 - body 是函數(shù)體,它是函數(shù)需要執(zhí)行的代碼,是函數(shù)的主體部分。即使只有一個(gè)語句,函數(shù)體也要由
{ }
包圍。 - 如果有返回值,在函數(shù)體中使用 return 語句返回。return 出來的數(shù)據(jù)的類型要和 dataType 一樣。
3.2 實(shí)例
通過函數(shù)的定義我們可以寫一個(gè)簡單的加法函數(shù):
#include<stdio.h>
int Add(int x, int y)
//函數(shù)名Add
//兩個(gè)形式參數(shù)x,y,類型都是int
//返回類型也是int
{
int c = 0;
c = x + y;
return c;//返回x+y的和
}
int main()
{
int a, b;
scanf("%d%d", &a, &b);
int ret = Add(a, b);//加法函數(shù)
printf("兩個(gè)數(shù)和為%d\n", ret);
return 0;
}
當(dāng)然我們也可以優(yōu)化一下
int Add(int x, int y)
{
return x + y;//直接返回
}
- 通過函數(shù)我們就可以節(jié)省大量時(shí)間,每次調(diào)用這個(gè)功能只需復(fù)用該函數(shù)即可。
3.3 作用域與生命周期
作用域和生命周期是C語言中一個(gè)特別重要的概念,清楚理解這個(gè)概念能幫助我們寫出更好的程序,減少bug的產(chǎn)生。
作?域(scope)是程序設(shè)計(jì)概念,通常來說,?段程序代碼中所?到的名字并不總是有效(可?的,?限定這個(gè)名字的可?性的代碼范圍就是這個(gè)名字的作?域。
- 局部變量的作?域是變量所在的局部范圍。
- 全局變量的作?域是整個(gè)?程(項(xiàng)?)。
- 以上面加法函數(shù)以列,x,y的作用域就是加法函數(shù)。當(dāng)加法函數(shù)執(zhí)行結(jié)束,它就會(huì)被銷毀。
?命周期指的是變量的創(chuàng)建(申請內(nèi)存)到變量的銷毀(收回內(nèi)存)之間的?個(gè)時(shí)間段。
局部變量的?命周期是:進(jìn)?作?域變量創(chuàng)建,?命周期開始,出作?域?命周期結(jié)束。
全局變量的?命周期是:整個(gè)程序的?命周期。
- 以上面加法函數(shù)以列,x,y的生命周期就是其進(jìn)入函數(shù)創(chuàng)建到變量銷毀的時(shí)間段。
4. 函數(shù)的參數(shù)
在函數(shù)使?的過程中,把函數(shù)的參數(shù)分為,實(shí)際參數(shù)和形式參數(shù)。下面我仍將以加法函數(shù)舉例:
#include<stdio.h>
int Add(int x, int y)
//函數(shù)名Add
//兩個(gè)形式參數(shù)x,y,類型都是int
//返回類型也是int
{
int c = 0;
c = x + y;
return c;//返回x+y的和
}
int main()
{
int a, b;
scanf("%d%d", &a, &b);
int ret = Add(a, b);//加法函數(shù)
printf("兩個(gè)數(shù)和為%d\n", ret);
return 0;
}
4.1 實(shí)際參數(shù)
顧名思義,實(shí)際參數(shù)就是實(shí)際存在的參數(shù),也就是主函數(shù)main調(diào)用函數(shù)時(shí)傳給它的參數(shù),也就是上面主函數(shù)中的a,b。
4.2 形式參數(shù)
同理,形式參數(shù)其實(shí)就是形式上的參數(shù),也就是上面加法函數(shù)Add中的x,y。它并不是實(shí)際存在的,在未使用時(shí)并不會(huì)向內(nèi)存申請空間,形式參數(shù)只有在函數(shù)被調(diào)?的過程中為了存放實(shí)參傳遞過來的值,才向內(nèi)存申請空間,這個(gè)過程就是形式的實(shí)例化。
4.3 實(shí)參與形參的關(guān)系
在介紹實(shí)參和形參關(guān)系時(shí),我們先看看下面這段代碼
#include<stdio.h>
void swap(int x, int y)//返回類型為void表示不返回值
{
int temp = 0;//定義一個(gè)臨時(shí)變量
temp = x;//把x的值賦給temp
x = y;//把y的值賦給x
y = temp;//把temp的值賦給y,完成交換操作
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
printf("交換前:a=%d,b=%d\n", a, b);
swap(a, b);//交換函數(shù)
printf("交換后:a=%d,b=%d\n", a, b);
return 0;
}
那么交換后的輸出是多少呢~
為什么交換的值還是不變呢,我們可以通過調(diào)試來觀察一下
通過調(diào)試,我們發(fā)現(xiàn)a與x,b與y只是在數(shù)值上相同,他們地址是完全不同的,他們在兩個(gè)獨(dú)立的內(nèi)存空間互不影響,對x,y交換根本不會(huì)改變a,b的值。并且函數(shù)在調(diào)用完成之后,函數(shù)所申請的內(nèi)存空間會(huì)歸還系統(tǒng)~
所以我們總結(jié)實(shí)參與形參的關(guān)系是:形參只是實(shí)參的?份臨時(shí)拷?,對形參改變根本不會(huì)影響實(shí)參
4.4 數(shù)組做參數(shù)
我們前面學(xué)過的數(shù)組自然是也能作為函數(shù)的參數(shù)來使用,下面是一個(gè)具體實(shí)例:
void print_arr(int arr[], int sz)//打印數(shù)組
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
- 其中arr是整個(gè)數(shù)組,sz是數(shù)組元素的個(gè)數(shù)
5. 嵌套調(diào)用和鏈?zhǔn)皆L問
5.1 函數(shù)的嵌套調(diào)用
我們在前面已經(jīng)學(xué)習(xí)了選擇結(jié)構(gòu)和循環(huán)結(jié)構(gòu)的嵌套使用,那函數(shù)嵌套調(diào)用又是怎樣的呢。其實(shí),簡單來說,就是函數(shù)中也可以調(diào)用函數(shù)
舉個(gè)例子,讓我們看看下面這段代碼
void print2()
{
printf("hello world\n");
}
void print1()
{
print2();//調(diào)用print2函數(shù)
}
int main()
{
print1();//調(diào)用print1函數(shù)
return 0;
}
- C語言函數(shù)支持嵌套調(diào)用,但是不支持嵌套定義。
5.2 函數(shù)的鏈?zhǔn)皆L問
鏈?zhǔn)皆L問簡單來說就是將?個(gè)函數(shù)的返回值作為另外?個(gè)函數(shù)的參數(shù),像鏈條?樣將函數(shù)串起來就是函數(shù)的鏈?zhǔn)皆L問。
舉例:
這是strlen的函數(shù)聲明:size_t strlen(const char *str)
#include <stdio.h>
int main()
{
printf("%d\n", strlen("abcdef"));
//根據(jù)strlen的返回值,我們就可以直接將其作為printf的參數(shù)
//這就是一種簡單的鏈?zhǔn)皆L問
return 0;
}
6.函數(shù)的定義與聲明
6.1 函數(shù)的定義
函數(shù)的定義就是指函數(shù)具體的實(shí)現(xiàn)過程,交代函數(shù)具體功能的實(shí)現(xiàn)
比如我們前面寫的加法函數(shù)具體實(shí)現(xiàn)的過程就是函數(shù)的定義
int Add(int a, int b)
{
return a + b;//直接返回
}
但是特別注意函數(shù)不能嵌套定義
int add(int x, int y)//加法函數(shù)
{
return x + y;
void print()
{
....;//嵌套定義error
}
}
6.2 函數(shù)的聲明
不知道大家注意到一個(gè)細(xì)節(jié)沒有,就是貝蒂在寫函數(shù)時(shí)候,會(huì)把函數(shù)放在主函數(shù)之前,那如果放在主函數(shù)之后會(huì)怎么樣呢,讓我們實(shí)驗(yàn)一下吧
int main()
{
int a, b;
scanf("%d%d",&a,&b);
int ret = Add(a, b);
printf("%d", ret);
return 0;
}
int Add(int x, int y)
{
return x + y;
}
一運(yùn)行就會(huì)報(bào)這個(gè)警告,這個(gè)警告的意思就是說Add函數(shù)未定義,那為什么說Add未定義呢,原來是程序從上往下進(jìn)行的,在遇到Add函數(shù)之前,會(huì)先執(zhí)行主函數(shù)中的Add,此時(shí)程序根本不知道Add的含義,所以會(huì)報(bào)警告。
那如何消除這個(gè)警告呢,其實(shí)我只需要加一個(gè)聲明,讓程序提前知道有這個(gè)函數(shù)。
int Add(int x, int y);//函數(shù)聲明
int main()
{
int a, b;
scanf("%d%d",&a,&b);
int ret = Add(a, b);
printf("%d", ret);
return 0;
}
int Add(int x, int y)
{
return x + y;
}
int Add(int , int );//聲明寫出這樣也是可以的
- 函數(shù)的調(diào)??定要滿足,先聲明后使?是,而函數(shù)的定義也是?種特殊的聲明,所以如果函數(shù)定義放在調(diào)?之前也是可以的。
7. 函數(shù)的迭代與遞歸
7.1 函數(shù)的迭代
「迭代 iteration」是一種重復(fù)執(zhí)行某個(gè)任務(wù)的控制結(jié)構(gòu)。在迭代中,程序會(huì)在滿足一定的條件下重復(fù)執(zhí)行某段代碼,直到這個(gè)條件不再滿足。我們學(xué)習(xí)過的while,for,do-while循環(huán)結(jié)構(gòu)就是一種迭代。
7.2 函數(shù)的遞歸
「遞歸 recursion」是一種算法策略,通過函數(shù)調(diào)用自身來解決問題。它主要包含兩個(gè)階段。
- 遞:程序不斷深入地調(diào)用自身,通常傳入更小或更簡化的參數(shù),直到達(dá)到“終止條件”。
- 歸:觸發(fā)“終止條件”后,程序從最深層的遞歸函數(shù)開始逐層返回,匯聚每一層的結(jié)果。
遞歸的三個(gè)要素:
終止條件:用于決定什么時(shí)候由“遞”轉(zhuǎn)“歸”。
遞歸調(diào)用:對應(yīng)“遞”,函數(shù)調(diào)用自身,通常輸入更小或更簡化的參數(shù)。
返回結(jié)果:對應(yīng)“歸”,將當(dāng)前遞歸層級的結(jié)果返回至上一層。
7.3 遞歸問題
(1) 問題一
利用遞歸計(jì)算1+2+3+4+....+n
int recur(int n)
{
// 終止條件
if (n == 1)
{
return 1;
}
// 遞:遞歸調(diào)用
return n + recur(n - 1);
}
(2) 問題二
輸??個(gè)整數(shù)m,打印這個(gè)按照順序打印整數(shù)的每?位。
?如:
輸?:1234 輸出:1 2 3 4
輸?:520 輸出:5 2 0文章來源:http://www.zghlxwxcb.cn/news/detail-837847.html
#include <stdio.h>
void print(int n)
{
if (n > 9)
{
print(n / 10);
}
printf("%d ", n % 10);
}
int main()
{
int n = 0;
scanf("%d", &n);
print(n);
return 0;
}
代碼分析:文章來源地址http://www.zghlxwxcb.cn/news/detail-837847.html
void print(int n)//輸入1234
{
if (n > 9)//1234大于9
{
print(n / 10);//將123傳入下個(gè)遞歸
}
printf("%d ", n % 10);//歸的第四步,輸出4
}
void print(int n)//傳入123
{
if (n > 9)//123大于9
{
print(n / 10);//將12傳入下個(gè)遞歸
}
printf("%d ", n % 10);//歸的第二步,輸出3
}
void print(int n)//傳入12
{
if (n > 9)//12大于9
{
print(n / 10);//將1傳入下個(gè)遞歸
}
printf("%d ", n % 10);//歸的第一步,輸出2
}
void print(int n)//傳入1
{
if (n > 9)//1不大于9
{
print(n / 10);
}
printf("%d ", n % 10);//輸出1,開始‘歸’
}
到了這里,關(guān)于函數(shù)探秘:深入理解C語言函數(shù),實(shí)現(xiàn)高效模塊化編程的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!