這種錯誤常有人會犯:在副函式裡面使用指標配置了一個新的記憶體空間,最後把這個指標傳回給主程式。為什麼不行?如果這個問題不知道答案的話,請回到 CallByValue 詳細看一遍再回來看解說...
先看以下的 code 再做說明
原始碼
// ====================================
// FileName: PtrFunc.cpp
// Author : Edison.Shih.
// Complier: VC 2008
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define DemoString "Edison.Shih."
#define LEN strlen(DemoString)
#define TEST_NUM 50000
#define TEST_LOOP 500
// ====================================
char* Error1()
{
char String[] = DemoString; // warning
return String;
}
void Error2(char *String)
{
strcpy(String, DemoString); // run-time error
}
void Error3(char *String)
{
String = (char*)malloc(sizeof(char)*LEN);
strcpy(String, DemoString);
}
char* CareFor(char *String)
{
String = (char*)malloc(sizeof(char)*(LEN*TEST_NUM));
strcpy(String, DemoString);
return String;
}
// ====================================
int main(int argc, char **argv)
{
char *ptr;
int i=0;
ptr = NULL, ptr = Error1(), printf("%s(len=%d)\n", ptr, strlen(ptr));
// ptr = NULL, Error2(ptr), printf("%s(len=%d)\n", ptr, strlen(ptr));
ptr = NULL, Error3(ptr), printf("%s\n", ptr); // strlen(ptr) has run time error.
system("pause");
for(i=0; i<TEST_LOOP; i++)
ptr = NULL, ptr = CareFor(ptr), printf("%s(len=%d)\n", ptr, strlen(ptr)), free(ptr);
return 0;
}
char *Error1() : 在副函式中配置變數,離開副函式後什麼都沒有
void Error2(char *String):原本在主程式裡面並沒有配置 String 該有的記憶體空間,導致想要複製字串時沒有實體空間可複製,這將造成 run-time error.
void Error3(char *String):傳進一個指標後,先在副函式裡面做配置的動作,到最後所有的配置動作也都只是在記憶體,最後回傳時,String 仍為 NULL。
char* CareFor(char *String):這種用法真的要小心,一般而言我們用到 malloc 時,必須要有能力進行 free 的動作才有意義。這個函式它的回傳值是正確沒錯,但最後應注意的是,最後「一定」要有另一個指標去接它,且一次 malloc,就要對到一次 free。
如上程式碼所述,在 loop 裡,紅色的 CareFor 已用 malloc 進行了配置,最後也要再用 free 將記憶體釋放。
一般而言,我比較建議初學者,所有配置動態記憶體的動作都在主函式裡面配置完畢,再呼叫副函式處理、運算配置好的動態空間。若有能力寫出一段副函式,可以隨心所欲配置各種資料型態之二維陣列 (且效率要好),倒是可考慮包成副函式。
如果硬要在副函式裡面配置記憶體空間的話,提供下面方式給各位參考...如果有其它方式,也歡迎提出
void test(char **Ptr2)
{
*Ptr2 = (char*)malloc(sizeof(char*)*LEN*TEST_NUM);
strcpy(*Ptr2, "Edison.Shih.");
}
main(){
...
...
char **ptr2 = &ptr;
test(ptr2);
printf("%s\n", ptr);
free(*ptr2);
}
如果本身指標不行的話…換個角度…直接再用指標的指標去控制!因為這真的很麻煩,所以還是建議,要配置動態記憶體的話,還是先在 main() 裡面配置完後,再交給副函式做運算處理…
以上.指標特輯到此告一段落,下一篇將整理所有的目錄
若對於指標或是C\C++有問題,歡迎一起討論指教