維系C世界框架的英雄
今天是關于C語言函式的故事,我相信很多人,學習C語言的第一段代碼就是:
#include <stdio.h>
int main()
{
printf("Hello World!\n");
return 0;
}
而從一開始,最重要的函式main(),就出現在了我們的世界,
函式是什么?
維基百科中對函式的定義:子程式
- 在計算機科學中,子程式(英語:Subroutine, procedure, function, routine, method,subprogram, callable unit),是一個大型程式中的某部分代碼, 由一個或多個陳述句塊組 成,它負責完成某項特定任務,而且相較于其他代碼,具備相對的獨立性,
- 一般會有輸入引數并有回傳值,提供對程序的封裝和細節的隱藏,這些代碼通常被集成為軟體庫,
函式的分類
- 庫函式
- 自定義函式
庫函式
- 庫函式(Library function)是將函式封裝入庫,供用戶使用的一種方式,方法是把一些常用到的函式編完放到一個檔案里,供不同的人進行呼叫,呼叫的時候把它所在的檔案名用#include<>加到里面就可以了,一般是放到lib檔案里的,
- 如我們用的輸入輸出函式(scanf,printf),拷貝字串的函式(strcpy),求x的y次冪函式(pow)等等,都是我們常用的庫函式,
庫函式大致分類(舉了下列函式類別含有的一些常見函式)
- IO函式:printf(輸出)、scanf(輸入)
- 字串操作函式:strcmp(字串比較)、strlen(計算字串長度)
- 字符操作函式:toupper(小寫轉大寫)
- 記憶體操作函式:memcpy(記憶體拷貝)、memset(記憶體初始化)
- 時間/日期函式:time(時間)
- 數學函式:sqrt(開平方)、pow(求x的y次冪)
- 其他函式
我們該怎樣學習庫函式呢?
- 在日常學習C語言的程序中,我們要學會積累庫函式
- 要學會并善于使用一些查詢工具,如http://zh.cppreference.com或者www.cplusplus.com
自定義函式
自定義函式和庫函式一樣,有函式名,回傳值和函式引數,是程式員根據需求自己定義的一種函式,
自定義函式的組成
return_type fun_name(para)
{
statement;
}
//return_type 回傳型別
//fun_name 函式名
//para 函式引數
//statement 陳述句項
例子1:(寫一個函式,求兩個數較大值)
#include <stdio.h>
//得到較大值函式的設計
int get_max(int x, int y)
{
return (x>y)?(x):(y);
}
int main()
{
int a = 10;
int b = 20;
//函式的呼叫
int max = get_max(a, b);
printf("max = %d\n", max);
return 0;
}
//rereturn_type: int
//fun_name: get_max
//para: int x,int y
//statement: return (x>y)?(x):(y);
- 該函式就像是你打球累了,你想去喝水,你就讓你(女)朋友去幫你買瓶飲料,(女)朋友買飲料就相當于函式名,而你告訴她,你要喝的飲料名字(還有給的錢),就相當于函式引數,你女朋友去買飲料的程序就相當于函式體的陳述句項,而她最后把飲料給你就相當于回傳型別的值,至于其他函式可能因為回傳值的不同,所以函式型別就是不同的,甚至還不需要回傳值,這時函式型別就是(void)
例子2:(寫一個函式,列印一個直角邊長為n的等腰直角三角形)
#include <stdio.h>
void print(int n)
{
int i=0;
for(i=0;i<n;i++)
{
int j=0;
for(j=0;j<=i;j++)
{
printf("* ");
}
printf("\n");
}
}
int main()
{
int n = 10;
print(n);
return 0;
}
//rereturn_type: void
//fun_name: print
//para: int n
//statement: {int i=0...for(...)}
- 該函式就是無回傳值的函式,故函式型別就用void,而如果你不寫函式型別的話,其實默認回傳型別就是int,但不建議這么做,
- 無回傳值的函式就相當于你寫作業一樣,哦豁,你不會,你找小青蛙幫你寫,但是你不要她教你方法,而是你要她幫你寫,答案她就直接幫你搞定了,而不需要你自己再動筆\ (~ 、~)/
函式的引數
- 函式的引數可以分為實際引數和形式引數
- 實參可以與形參命名一樣
- 不同函式形參的命名可以相同
實際引數(實參)
- 真實傳給函式的引數,叫實參,實參可以是:常量、變數、運算式、函式等,無論實參是何種型別的量,在進行函式呼叫時,它們都必須有確定的值,以便把這些值傳送給形參,
形式引數(形參)
- 形式引數是指函式名后括號中的變數,因為形式引數只有在函式被呼叫的程序中才實體化(分配記憶體單元),所以叫形式引數,形式引數當函式呼叫完成之后就自動銷毀了,因此形式引數只在該函式中有效,
例子3:思考下面函式是否可行(交換兩個整形變數a,b的值)
#include <stdio.h>
void Swap(int x,int y)
{
int tmp;
tmp=x;
x=y;
y=tmp;
}
int main()
{
int a=10;
int b=20;
Swap(a,b);
printf("%d %d",a,b);
return 0;
}
- 其中main()函式中Swap(a,b)的a,b就是實際引數
- void Swap(int x, int y)中的x,y就是形式引數
- 按思路,我們將a,b的值分別傳給x,y,再通過變數tmp將x,y的值交換,這樣子我們就將x,y的值交換了,對吧,然后a,b的值好像完全沒做改變!!!感覺跟他沒有任何的關系呀!!!所以不能傳值
通過比較引數的地址我們追尋原因(通過除錯——視窗——監視,找到引數地址)

- 通過上圖我們知道,a,b與x,y的值沒有任何聯系,因為他們每個本身的地址都是不相同的,
- 但卻可以將a,b的值傳遞給x,y,故我們可以認為:形參實體化之后其實相當于實參的一份臨時拷貝,
至于我們怎樣去將例3的代碼修改正確呢,首先我們要們要知道什么是傳值呼叫,什么是傳址呼叫
函式的呼叫
- 計算機編譯或運行時,使用某個函式來完成相關命令,對無參函式呼叫時則無實際引數表,實際引數表中的引數可以是常數、變數或其它構造型別資料及運算式,各實參之間用逗號分隔,
- 函式呼叫分為:傳址呼叫和傳址呼叫
- 函式可以實行嵌套呼叫,但不能嵌套定義
傳值呼叫
- 把引數的實際值復制給函式的形式引數,在這種情況下,修改函式內的形式引數不會影響實際引數
- 函式的形參和實參分別占有不同記憶體塊
大家可以參考例1,例2,以及錯誤的例3來理解
傳址呼叫
- 傳址呼叫是把函式外部創建變數的記憶體地址傳遞給函式引數的一種呼叫函式的方式,
- 這種傳參方式可以讓函式和函式外邊的變數建立起正真的聯系,也就是函式內部可以直接操作函式外部的變數
顯而易見,例3是通過傳值呼叫,故形參不能去改變形參的值,接下來,通過傳址呼叫,修改例3
#include <stdio.h>
void Swap(int* x,int* y)
{
int tmp;
tmp=*x;
*x=*y;
*y=tmp;
}
int main()
{
int a=10;
int b=20;
Swap(&a,&b);
printf("%d %d",a,b);
return 0;
}
- 改變1:將Swap中a,b的值,改成其地址,即是將地址傳給形參
- 改變2:函式形參改用指標來接收實參傳來的地址
- 改變3:函式體的陳述句通過指標來將*x , *y的值交換
我們繼續通過地址追尋這其中的不同 (通過除錯——視窗——監視,找到引數地址)

因為指標變數x,y分別存放著a,b的地址,故解參考時,其實是將指標變數x,y地址存放的值互相交換,雖然a,b變數的地址沒有改變,但是其地址存放的值發生了交換,故a,b發生交換,
函式的故事還為結束,下一章將了解函式的嵌套呼叫和鏈式訪問等其他內容,如果你喜歡我講的故事,可以點贊,收藏,關注我哦!!!
to be continued…
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/277709.html
標籤:其他
