歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux技術 >> 嵌入式Linux C語言(三)――指針與函數

嵌入式Linux C語言(三)――指針與函數

日期:2017/3/3 11:54:42   编辑:Linux技術

嵌入式Linux C語言(三)――指針與函數

指針對函數的功能有巨大的貢獻,指針能夠將數據傳遞給函數,並且允許函數對數據進行修改。指針對於函數的作用主要有兩方面:將指針傳遞給函數和聲明函數指針。

一、程序的棧和堆

程序的棧和堆是C語言程序運行的運行時元素。

1、程序棧

程序棧是支持函數執行的內存區域,通常和堆共享一塊內存區域,通常程序棧占據內存區域的下部,堆用內存區域的上部。程序棧存放棧幀,棧幀存放函數參數和局部變量。調用函數時,函數的棧幀被推倒棧上,棧向上長出一個棧幀,當函數終止時,函數的棧幀從程序棧上彈出,棧幀所使用的內存不會被清理,但可能會被推倒程序棧上的另一個函數的棧幀所覆蓋。動態分配的內存來自於堆,堆向下生長,隨著內存的分配和釋放,堆中會布滿碎片。盡管堆是向下生長的,但只是一個大體方向,實際內存可能分配在堆上的任意位置。

2、棧幀

棧幀的組成:
A、返回地址
函數完成後要返回的程序內部地址
B、局部數據存儲
為局部變量分配的內存
C、參數存儲
為函數參數分配的內存
D、棧指針和基指針
運行時系統用來管理棧的指針
棧指針通常指向棧的頂部,基指針(幀指針)通常存在並指向棧幀內部的地址
ARM的棧幀布局如下:



main stack frame為調用函數的棧幀,func1 stack frame為當前函數(被調用者)的棧幀,棧底在高地址,棧向下增長。圖中FP就是棧基址,指向函數的棧幀起始地址;SP則是函數的棧指針,指向棧頂的位置。ARM壓棧的順序依次為當前函數指針PC、返回指針LR、棧指針SP、棧基址FP、傳入參數個數及指針、本地變量和臨時變量。如果函數准備調用另一個函數,跳轉之前臨時變量區先要保存另一個函數的參數。

二、通過指針傳遞和返回數據

1、用指針來傳遞數據

函數中用指針變量作為參數來傳遞數據可以在函數中修改數據,如果不需要修改數據,則將指針變量限制為const類型。典型的函數應用如下:char *strcpy(char *dest, const char *src);如果函數用值傳遞數據,則在函數中將無法修改數據。

2、返回指針

返回指針需要返回的類型是某種數據類型的指針。
從函數返回指針存在的問題:
A、返回未初始化的指針
B、返回指向無效地址的指針。
C、返回局部變量的指針
D、返回指針但是沒有釋放內存
從函數返回動態分配的內存,在使用完內存後必須釋放,否則會造成內存洩漏。
函數返回局部數據的指針或局部變量是錯誤的,函數返回後,局部數據所在的棧幀將會被彈出程序棧,保存在棧幀上的數據極易被後續調用函數的棧幀覆蓋。通過將局部變量聲明為static類型,可以將局部數據、變量的作用域限定在函數內部,但分配在棧外(data數據段),可以避免局部數據、變量被其他函數的棧幀覆蓋。

3、傳遞指針的指針

將指針傳遞給函數時,傳遞的是指針變量的值,如果需要修改原指針而不是指針變量的副本,就需要傳遞指針的指針。

三、函數指針

函數指針是持有函數地址的指針變量,指向函數地址的指針變量。

1、函數指針的聲明

函數指針變量的聲明一般格式為;數據類型 (*指針變量名)();Void * fun(void);//返回void*類型指針的函數void (*pFun)(void);//函數指針
void *(*pFun)(void *, void *);//函數指針
typedef void(*Fun)(void);//定義一個函數指針類型FunFun pfun = fun;//將函數fun的地址賦值給函數指針pfunFun pfun = &fun;//將函數fun的地址賦值給函數指針pfunvoid *(*pf[5])(void);//函數指針數組

2、函數指針的使用

調用函數指針的一般流程:
A、定義函數指針變量
B、被調函數的入口地址(函數名)賦予該函數指針變量
C、用函數指針變量形式調用函數
D、函數指針變量形式調用函數的一般形式為:(*指針變量名) (實參列表)
函數調用和函數指針變量形式調用函數方式如下:
fun();//函數調用 (*fun)();//函數指針變量形式調用函數 (**fun)();//函數指針變量形式調用函數 pfun();//函數指針形式調用函數 (*pfun)();//函數指針形式調用函數 (**pfun)();//函數指針形式調用函數函數指針變量不能進行算術運算,函數指針的偏移是毫無意義的。函數調用中(*指針變量名)的兩邊的括號不可少,其中的*不應該理解為求值運算,*只是一種表示符號。

3、傳遞函數指針

將函數指針變量作為函數的參數進行傳遞,使程序代碼變得更加靈活。int add(int num1, int num2)
{
return num1 + num2;}
int sub(int num1, int num2)
{
return num1 - num2;}
typedef int (*pFun)(int, int);
int compute(pFun operation, int num1, int num2)
{
return operation(num1, num2);}
compute(add, 5, 6);
compute(sub, 10,2);
add、sub函數的地址被傳遞給compute函數作為參數,compute使用add、sub函數的地址調用對應的操作。

4、返回函數指針

返回函數指針需要把函數的返回類型聲明為函數指針。int add(int num1, int num2)
{
return num1 + num2;}
int sub(int num1, int num2)
{
return num1 - num2;}
typedef int (*pFun)(int, int);
pFun select(char opcode)
{
switch(opcode){case ‘+’:return add;case ‘-’:return sub;}}
int evaluate(char opcode, int num1, num2)
{
pFun operation = select(opcode);return operation(num1, num2);}
evaluate(‘+’, 5, 6);
evaluate(‘-’, 10, 6);
通過輸入一個字符和兩個操作數就可以進行相應的計算

5、函數指針數組使用

函數指針數組可以基於某些條件選擇要執行的函數,函數指針數組聲明如下:第一種聲明:typedef int (*operation)(int, int);operation operations[128] = {NULL};第二種聲明:int (*operations[128]) (int, int) = {NULL};函數指針數組聲明後可以將某一類操作函數賦值給數組。operations[‘+’] = add;operations[‘-’] = sub;int evaluate_array(char opcode, int num1, num2)
{
pFun operation = operations[opcode];return operation(num1, num2);}
evaluate_array(‘+’, 6 ,9);

6、函數指針轉換

將指向函數的指針變量轉換為其它類型的指針變量。無法保證函數指針和數據指針相互轉換後正常工作。
本文出自 “生命不息,奮斗不止” 博客,請務必保留此出處http://9291927.blog.51cto.com/9281927/1789683
Copyright © Linux教程網 All Rights Reserved