GetMemory的典型例子
原文地址:http://blog.csdn.net/wl_haanel/article/details/5186568
NO.1: 程式首先申請一個char型別的指標str,並把str指向NULL(即str裡存的是NULL的地址,*str為NULL中的值為0),呼叫函式的過程 中做了如下動作:1申請一個char 型別的指標p,2把str的內容copy到了p裡(這是引數傳遞過程中系統所做的),3為p指標申請了100個空間,4返回Test函式.最後程式把字元 串hello world拷貝到str指向的記憶體空間裡.到這裡錯誤出現了!str的空間始終為NULL而並沒有實際的空間.深刻理解函式呼叫的第2步,將不難發現問題 所在!
因為 GetMemory 並不能傳遞動態記憶體,函式引數是傳值的,也就是說引數的變化不會影響到實參,因此這裡分配到的空間的地址不會存到全域性的str中 ,Test 函式中的 str 一直都是 NULL。 strcpy(str, "hello world");將使程式崩潰。
void GetMemory(char *p)
{
p = (char*)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
//請問執行Test函式後會是什麼樣的結果?
NO.2: 程式首先申請一個char型別的指標str,並把str指向NULL.呼叫函式的過程中做了如下動作:1申請一陣列p[]並將其賦值為hello world(陣列的空間大小為12),2返回陣列名p付給str指標(即返回了陣列的首地址).那麼這樣就可以列印出字串"hello world"了麼?當然是不能的!因為在函式呼叫的時候漏掉了最後一步.也就是在第2步return陣列名後,函式呼叫還要進行一步操作,也就是釋放記憶體 空間.當一個函式被呼叫結束後它會釋放掉它裡面所有的變數所佔用的空間.所以陣列空間被釋放掉了,也就是說str所指向的內容將不確定是什麼東西.
char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
NO.3:問題同NO.1,正確答案為可以列印出hello.但記憶體洩漏了!
void GetMemory(char **p, int num)
{
*p = (char*)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
NO.4: 申請空間,拷貝字串,釋放空間.前三步操作都沒有任何問題.到if語句裡的判斷條件開始出錯了,因為一個指標被釋放之後其內容並不是NULL,而是一個 不確定的值.所以if語句永遠都不能被執行.這也是著名的"野"指標問題.所以我們在編寫程式釋放一個指標之後一定要人為的將指標付成NULL.這樣就會 避免出現"野"指標的出現.有人說"野"指標很可怕,會帶來意想不到的錯誤.
void Test(void)
{
char *str = (char*)malloc(100);
strcpy(str, "hello");
free(str);
if (str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
void GetMemory1(char *p)
{
p = (char *)malloc(100);
}
void Test1(void)
{
char *str = NULL;
GetMemory1(str);
strcpy(str, "hello world");
printf(str);
}
//str一直是空,程式崩潰
char *GetMemory2(void)
{
char p[] = "hello world";
return p;
}
void Test2(void)
{
char *str = NULL;
str = GetMemory2();
printf(str);
}
char *GetMemory3(void)
{
return "hello world";
}
void Test3(void)
{
char *str = NULL;
str = GetMemory3();
printf(str);
}
//Test3 中列印hello world,因為返回常量區,而且並沒有被修改過。Test2中不一定能列印出hello world,因為指向的是棧。
void GetMemory4(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test4(void)
{
char *str = NULL;
GetMemory3(&str, 100);
strcpy(str, "hello");
printf(str);
}
//記憶體沒釋放
void Test5(void)
{
char *str = (char *) malloc(100);
strcpy(str, "hello");
free(str);
if(str != NULL)
{
strcpy(str, "world");
printf(str);
}
}
//str為野指標,列印的結果不得而知
void Test6()
{
char *str=(char *)malloc(100);
strcpy(str, "hello");
str+=6;
free(str);
if(str!=NULL)
{
strcpy(str, "world");
printf(str);
}
}
//VC斷言失敗,執行錯誤
另轉一則:
char *GetMemory3(int num)
{
char *p = (char *)malloc (sizeof(char) * num);
return p; //返回指標 p
}
void Test3(void)
{
char *str = NULL;
str = GetMemory3(100); //這裡指標 str也和指標 p的指向一樣的記憶體塊。
strcpy(str, "hello");
cout<< str << endl;
free(str); //這裡最終只是釋放了str指向的記憶體塊,對於str指標 依然還是指向那塊記憶體,看了一些資料說應該加一句str=0;那指標 p呢?p也依然在指向那塊記憶體啊。
}
回覆:
答者:wutaozhao() 信譽:100 級別:user2 日期:2007-6-29 21:42:21 id:41451636
指標 之間傳遞的就是地址,所以str和p所指向的記憶體塊是同一個,釋放其中任何一個即可
答者:what_a_big() 信譽:100 級別:user1 日期:2007-6-29 21:42:21 id:41451637
那指標 p呢?
=============================================================================
after returning from GetMemory()
p (區域性 變數)沒了,那塊記憶體還在。
現在str 指向那塊記憶體。
看了一些資料說應該加一句str=0
=================================
也可以不寫str=NULL,只要你不再引用str。
答者:believefym(feng) 信譽:100 級別:user5 日期:2007-6-29 21:50:38 id:41451675
同一塊記憶體,釋放一次即可,只不過所有指向那塊記憶體的指標 都失效了,就像樓主程式碼裡的p和str
釋放之後str就變成了野指標 ,加str=NULL,可以避免之後錯誤使用該指標 ,方便除錯
答者:lightnut() 信譽:100 級別:star1 日期:2007-6-29 22:05:48 id:41451736
1.
函式進入Test3():
char* str = NULL;
======================
變數 變數的地址 變數的值(內容)
str 0x0013fe8c 0
2.
str = GetMemory3(..)=====>
char *p = (char *)malloc (sizeof(char) * num);
將分配的記憶體起始地址(0x003a60b0)賦給棧變數p,
===============================================
變數 變數的地址 變數的值(內容)
p 0x0013fda8 0x003a60b0
3. 從GetMemory3(..)返回, p的值(0x003a60b0)
拷貝給str, 棧變數p生命結束, 釋放其所佔棧記憶體
(地址0x0013fda8)
=================================================
變數 變數的地址 變數的值(內容)
str 0x0013fe8c 0x003a60b0
4. free(str): 釋放str指向的記憶體(0x003a60b0開始的記憶體空間)
5. 推出Test3()後, 棧變數str生命結束, 釋放其所佔棧記憶體
(地址0x0013fe8c)
答者:freshui(五月的風 -最近老犯困) 信譽:100 級別:user1 日期:2007-6-29 22:12:07 id:41451763
呵呵 p沒了
已經死了
:)
注意看變數的作用域
答者:buhaohaoxuexi() 信譽:100 級別:user1 日期:2007-6-29 22:37:00 id:41451888
為什麼會死呢,不是說動態分配是分配在堆上的嗎?他不應該死啊。
答者:yydrewdrew(滿堂花醉三千客,一劍霜寒十四州) 信譽:100 級別:user1 日期:2007-6-29 23:55:01 id:41452325
char *GetMemory3(int num)
{
char *p = (char *)malloc (sizeof(char) * num);
return p; //返回指標 p
}
void Test3(void)
{
char *str = NULL;
str = GetMemory3(100); //呼叫完後p被析構,p為區域性 作用域存在於函式GetMemory3的棧中,當GetMemory3被呼叫完後,棧空間被釋放,因而被析構。
strcpy(str, "hello");
cout<< str << endl;
free(str); //這裡最好加一句str = NULL。
}
答者:yydrewdrew(滿堂花醉三千客,一劍霜寒十四州) 信譽:100 級別:user1 日期:2007-6-29 23:56:59 id:41452334
注意p和它指向的物件的生命期是兩回事
p是一個區域性 指標 ,而它指向的物件是堆空間具有全域性生命期
答者:xlbdan(流浪劍客) 信譽:100 級別:user5 日期:2007-6-30 0:15:43 id:41452409
return p; //返回指標 p
這裡返回之後,p已經消失.
但是p指向的那塊記憶體依然存在,並且被返回到了呼叫端,用str接收了.
所以只要free(str)就行了,也就釋放了p申請的那塊記憶體
然後把 str賦為NULL,是防止再錯誤的去使用它
相關文章
- 子查詢的典型例子
- .NET調PHP Web Service的典型例子PHPWeb
- Angular Ngrx Store 應用程式狀態的一些典型例子Angular
- 一個小例子,給你講透典型的 Go 併發操作Go
- Vue 兩個欄位聯合校驗典型例子--修改密碼Vue密碼
- PMM Query Analytics的查詢分析器怎麼用?典型教學例子一個
- 關於《完全手冊Excel VBA典型例項大全——透過368個例子掌握》隨書樣例的下載Excel
- Javacc的例子Java
- sqlldr的例子SQL
- 典型的ETL使用場景
- 幾個SQLLDR的典型案例SQL
- JSONP的例子JSON
- at new 的使用例子
- 五個典型的JavaScript面試題JavaScript面試題
- 5個典型的JavaScript面試題JavaScript面試題
- 常用的幾個典型指令碼指令碼
- CRM系統的典型功能 (轉)
- Context的典型使用場景Context
- Flutter 最常出現的典型錯誤Flutter
- 非典型開發者的形象三變
- 5個典型的JavaScript面試題(上)JavaScript面試題
- CTI的典型應用之二 (轉)
- CTI的典型應用之一 (轉)
- CTI的典型應用之三 (轉)
- jQuery的常用小例子jQuery
- php常用到的例子PHP
- PIPE函式的例子函式
- 發郵件的例子
- [Shell] Sort排序的例子排序
- XPATH的簡單例子單例
- 【python小例子】小例子拾憶Python
- MYSQL典型的configure選項(轉)MySql
- split 例子
- hasMap 的鍵值對的例子ASM
- 為什麼它有典型FaaS能力,卻是非典型FaaS架構?架構
- python字典的小例子Python
- ps命令的10個例子
- TensorFlow 的簡單例子單例