文章目錄
- 7.嵌套調?和鏈式訪問
- 7.1 嵌套調?
- 7.2 鏈式訪問
- 8.函數的聲明和定義
- 8.1 單個?件
- 8.2 多個?件
- 8.3 static 和 extern
- 8.3.1 static 修飾局部變量
- 8.3.2 static 修飾全局變量
- 8.3.3 static 修飾函數
7.嵌套調?和鏈式訪問
7.1 嵌套調?
嵌套調用就是函數之間的互相調用。
#include <stdio.h>void arr(){}void menu() {arr();
}int main() {menu();return 0;
}
這里 main 函數調用 menu函數。menu 函數調用 arr 函數。
函數可以嵌套調用,但是不能嵌套定義。
7.2 鏈式訪問
所謂鏈式訪問就是將一個函數的返回值作為另外一個函數的參數,像鏈條一樣將函數串起來就是函數的鏈式訪問。
#include <stdio.h>
int main()
{printf("%d\n", strlen("abcdef"));//鏈式訪問 return 0;
}
把strlen的返回值直接作為printf函數的參數,鏈式訪問 。
這個代碼執行的結果是什么?
#include <stdio.h>
int main()
{printf("%d", printf("%d", printf("%d", 43)));return 0;
}
打印:
4321
printf 函數的返回int printf ( const char * format, ... );
,也就是說printf函數返回的是打印在屏幕上的字符的個數。
printf("%d", 43)
這個打印43,在屏幕上打印2個字符,再返回2。
然后printf("%d", printf("%d", 43))
打印2,在屏幕上打印1個字符,再返回1。
printf("%d", printf("%d", printf("%d", 43)));
打印1。
所以屏幕上最終打印:4321
8.函數的聲明和定義
8.1 單個?件
C語言編譯器對源代碼進行編譯的時候,從第一行往下掃描的,所以函數調用之前先聲明一下調用的函數。
#include <stdio.h>void menu() {}int main() {menu();return 0;
}
3-5行是函數menu的定義,第8行是函數的調用。
#include <stdio.h>int main() {menu();return 0;
}void menu() {}
如果把函數定義放在函數調用的后面就會報錯。
#include <stdio.h>void menu();int main() {menu();return 0;
}void menu() {}
這里的函數定義放在了函數調用的后面,但是第3行是函數聲明,所以就不會報錯。
函數的調用一定要滿足,先聲明后使用;
函數的定義也是一種特殊的聲明,所以如果函數定義放在調用之前也是可以的。
8.2 多個?件
一般在企業中我們寫代碼時候,代碼可能比較多,不會將所有的代碼都放在一個文件中;我們往往會根據程序的功能,將代碼拆分放在多個文件中。
一般情況下,函數的聲明、類型的聲明放在頭文件(.h)中,函數的實現是放在源文件(.c)文件中。
add.c
//函數的定義
int Add(int x, int y)
{return x+y;
}
add.h
//函數的聲明
int Add(int x, int y);
test.c
#include <stdio.h>
#include "add.h"
int main()
{int a = 10;int b = 20;//函數調用int c = Add(a, b);printf("%d\n", c);return 0;
}
運行結果:
8.3 static 和 extern
作用域和生命周期:
作用域是限定這個名字的可用性的代碼范圍。
-
局部變量的作用域是變量所在的局部范圍。
-
全局變量的作用域是整個工程(項目)。
生命周期指的是變量的創建(申請內存)到變量的銷毀(收回內存)之間的一個時間段。
-
局部變量的生命周期是:進入作用域變量創建,生命周期開始,出作用域生命周期結束。
-
全局變量的生命周期是:整個程序的生命周期。
static 和 extern 都是C語言中的關鍵字:
static 是 靜態的 的意思,可以用來:
-
修飾局部變量
-
修飾全局變量
-
修飾函數
extern 是用來聲明外部符號的。
8.3.1 static 修飾局部變量
#include <stdio.h>
void test()
{//static修飾局部變量static int i = 0;i++;printf("%d ", i);
}
int main()
{int i = 0;for(i=0; i<5; i++){test();}return 0;
}
打印:
1 2 3 4 5
如果把第五行的static去掉的話,就會打印:1 1 1 1 1
我們從輸出結果來看,i的值有累加的效果,這是因為 static修飾局部變量改變了變量的生命周期。
生命周期改變的本質是改變了變量的存儲類型,本來一個局部變量是存儲在內存的棧區的,但是被 static 修飾后存儲到了靜態區。存儲在靜態區的變量和全局變量是一樣的,生命周期就和程序的生命周期一樣了,只有程序結束,變量才銷毀,內存才回收。但是作用域不變的。
使用建議:未來一個變量出了函數后,我們還想保留值,等下次進入函數繼續使用,就可以使用static修飾。
8.3.2 static 修飾全局變量
代碼1:
add.c
int g_val = 2018;
test.c
#include <stdio.h>
extern int g_val;
int main(){printf("%d\n", g_val);return 0;
}
代碼2:
add.c
static int g_val = 2018;
test.c
#include <stdio.h>
extern int g_val;
int main(){printf("%d\n", g_val);return 0;
}
extern 是用來聲明外部符號的,如果一個全局的符號在A文件中定義的,在B文件中想使用,就可以使用 extern 進行聲明,然后使用。
結果:代碼1正常,代碼2在編譯的時候會出現鏈接性錯誤。
解釋:
一個全局變量被static修飾,使得這個全局變量只能在本源文件內使用,不能在其他源文件內使用。
本質原因是全局變量默認是具有外部鏈接屬性的,在外部的文件中想使用,只要適當的聲明就可以使用;但是全局變量被 static 修飾之后,外部鏈接屬性就變成了內部鏈接屬性,只能在自己所在的源文件內部使用了。
使用建議:如果一個全局變量,只想在所在的源文件內部使用,不想被其他文件發現,就可以使用static修飾。
8.3.3 static 修飾函數
代碼1:
add.c
int Add(int x, int y)
{return x+y;
}
test.c
#include <stdio.h>
extern int Add(int x, int y);
int main()
{printf("%d\n", Add(2, 3));return 0;
}
代碼2:
add.c
static int Add(int x, int y)
{return x+y;
}
test.c
#include <stdio.h>
extern int Add(int x, int y);
int main()
{printf("%d\n", Add(2, 3));return 0;
}
結果:代碼1是能夠正常運行的,但是代碼2就出現了鏈接錯誤。
解釋:
static 修飾函數和 static 修飾全局變量是一模一樣的,一個函數在整個工程都可以使用,被static修飾后,只能在本文件內部使用,其他文件無法正常的鏈接使用了。
本質是因為函數默認是具有外部鏈接屬性,具有外部鏈接屬性,使得函數在整個工程中只要適當的聲明就可以被使用。但是被 static 修飾后變成了內部鏈接屬性,使得函數只能在自己所在源文件內部使用。
使用建議:一個函數只想在所在的源文件內部使用,不想被其他源文件使用,就可以使用 static 修飾。