C語言-第33課 - 認清函數的真面目
第33課 - 認清函數的真面目
一.概念
- 函數的由來
程序 = 數據 + 算法
C程序 = 數據 + 函數
我們下面分析一下匯編語言,匯編語言是從上到下順序執行的,匯編為了循環執行,就有了跳轉指令。通過來回的跳轉,就存在了不同的功能模塊,這也就是我們C語言中的函數的原型。
- 函數的意義
模塊化程序設計:
C語言中的模塊化:
- 面向過程的程序化設計
(1) 面向過程是一種以過程為中心的編程思想。
(2) 首先將復雜的問題分解為一個個容易解決的問題。
(3) 分解過後的問題可以按照步驟一步步完成。
(4) 函數是面向過程在C語言中的體現。
(5) 解決問題的每個步驟可以用函數來實現。
二. (函數)聲明和(函數)定義
首先聲明和定義是不同的。
程序中的聲明可以理解為預先高旭編譯器實體的存在,如:變量,函數,等等。
程序中的定義明確指示編譯器實體的意義。
例如:
// global.c
// int g_var = 0; 定義
#include <stdio.h>
extern int g_var; //聲明
void f(int i, int j); /*聲明,提前聲明,下面的使用就是合法的,否則提前使用不合法。*/
int main()
{
int g(int x);
g_var = 10;
f(1, 2);
printf("%d\n", g(3));
return 0;
}
void f(int i, int j)
{
printf("i + j = %d\n", i + j);
}
int g(int x)
{
return 2 * x + g_var;
}
三. 函數
- 函數的參數
l 函數參數在本質上與局部變量相同,都是在棧上分配空間。
l 函數參數的初始值是函數調用時的實參值。
例:
#include <stdio.h>
int f(int i, int j)
{
printf("%d, %d\n", i, j);
}
int main()
{
int k = 1;
f(k, k++);
printf("%d\n", k);
return 0;
}
在windows的c++環境中運行的結果是:
1,1
2
在linux的gcc編譯器中,運行結果是:
2,1
2
- 盲點
函數參數的求職順序依賴於編譯器的實現。
C語言中大多數運算符對其操作數求值的順序都依賴於編譯器的實現的。
我們看下面一段程序:
int i = f() * g();
到底是f還是g先調用,我們不能確定,在不同的編譯器中會有不同的效果。
- 程序中的順序點
(1) 程序中存在一定的順序點。
(2) 順序點指的是執行過程中修改變量的最晚時刻。
(3) 在程序達到順序點的時候,之前所做的一切操作必須反映到後續的訪問中。
- 如何找順序點
(1) 每個完整表達式結束時。
(2) &&,||,?:,以及都哈表達式的每個運算對象之後。
(3) 函數調用中對所有實際參數的求值完成之後(進入函數體之前)。
下面看一個例子:
#include <stdio.h>
int main()
{
int k = 2;
int a = 1;
k = k++ + k++;
printf("k = %d\n", k);
if( a-- && a ) //左邊的是1,右邊的是0。
{
printf("a = %d\n", a);
}
return 0;
}
運行結果:6
分析:k = k++ + k++;中分號才是數據點,k++操作是在2的基礎上自增,但是這個結果不會瞬間反映到k的值上(因為是後置)。第二個k++也是在2的基礎上自增1。在到達數據點之前,k的值會是4。到達分號的時候,我們再完成之前的兩次自增的操作,加了兩次1,k的值變成6。
改成k = k++ + ++k;或者 k = ++k + k++; 運行結果是7。
改成k = ++k + ++k; 運行結果是8。
- 函數的缺省認定
C語言會默認沒有類型的函數的參數為int。
f(i,j)
{
return i+j;
}
等價於:
f(int i, int j)
{
return i+j;
}
小結:
l C語言是一種面向過程的語言。
l 函數可以理解為解決問題的步驟。
l 函數的實參並沒有固定的計算次序。
l 順序點是C語言中變量改變的最晚時機。
l 函數定義時函數和返回值的缺省類型為int。
C語言-第33課 - 認清函數的真面目