題目:void GetMemory(char *p)
{
p = (char *)malloc(100);
}
void Test(void)
{
char *str = NULL;
GetMemory(str);
strcpy(str, "hello world");
printf(str);
}
請問運行Test 函數會有什麼樣的結果?
分析:程序崩潰。因爲GetMemory 並不能傳遞動態內存,Test 函數中的 str 一直都是 NULL。strcpy(str, "hello world");將使程序崩潰。
執行GetMemory之後,p得到新分配的空間地址,str依然爲NULL;
沒有對內存進行回收free(),局部變量存在棧區,malloc()在堆區;局部變量在函數執行完畢之後回收棧空間;
題目:char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
請問運行Test 函數會有什麼樣的結果?
分析:可能是亂碼。因爲GetMemory 返回的是指向“棧內存”的指針,該指針的地址不是 NULL,但其原來的內容已經被清除,新內容不可知。
打印內容未知;p指向“棧內存”;調用GetMemory()之後棧內存釋放,但str仍指向棧區地址,造成內存泄露,該棧區可能用作其他用途,存儲其他內容。因此打印內容未知。
題目:void GetMemory(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}
請問運行Test 函數會有什麼樣的結果?
分析:
(1)能夠輸出hello
(2)內存泄漏
將動態分配的內存的指針賦值給str指針;但GetMemory()函數中未檢查分配失敗的情況;if(*p==NULL){ };
沒有對分配的內存進行回收free();
題目:void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str, “hello”);
free(str);
if(str != NULL)
{
strcpy(str, “world”);
printf(str);
}
}
請問運行Test 函數會有什麼樣的結果?
分析:
篡改動態內存區的內容,後果難以預料,非常危險。
因爲free(str);之後,str 成爲野指針,if(str != NULL)語句不起作用。
應在free(str)之後將str賦值爲空 str=NULL;
正確寫法的實例
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
char *GetMemory(char *&p, int num)
{
p = (char *)malloc(sizeof(char)*num);
//p = new char[num];
return p;
}
int main(void)
{
char *str ;
GetMemory(str, 100);
strcpy(str, "hello");
cout << str << endl;
return 0;
}
//上面是一個正確的程序,下面是轉載的一些相關的知識
GetMemory錯誤講解(指針練習) 錯誤程序:
void GetMemory( char *p )
{
p = (char *) malloc( 100 );
}
void Test( void )
{
char *str = NULL;
GetMemory( str ); //GetMemory(&str)編譯出錯,將一個指針地址值傳遞給一級指針。
strcpy( str, "hello world" );
printf( “%s”,str );
}
這個一個考驗對指針理解的題目,上面程序在運行之後:
1,調用GetMemory( str )後, str並未產生變化,依然是NULL.只是改變的str的一個拷貝的內存的變化
2,strcpy( str, "hello world" );程序運行到這將產生錯誤。
3,new的時候有可能內存出錯,應該在*p = (char *) malloc( num ); 後判斷內存是否申請成功,應加上:
if ( *p == NULL )
{
...//進行申請內存失敗處理
}
4,動態創建的內存沒釋放。
錯誤分析:
錯認爲 GetMemory(char *p)中的 p “就是” GetMemory(str)中的str。但p“不是”str,它只是“等於”str 。
就象: int a = 100;
int b = a; // 現在b等於a
b = 500; // 現在能認爲a = 500 ?
顯然不能認爲a = 500,因爲b只是等於a,但不是a! 當b改變的時候,a並不會改變,b就不等於a了。 因此,雖然p已經有new的內存,但str仍然是null
str沒有得到分配內存的地址值。
內存空間狀態:首先申請了四個字節的棧空間,存放str指針,此時str的值爲0,存放str的這塊內存的地址值爲0x0012ff7c。調用函數 GetMemory,指針P入棧,也分配了四個字節的棧空間,P被賦str的值即此時P的值也爲0,存放指針P的內存地址是0x0012ff2c。然後將新開闢的100個字節的內存空間地址賦給P,此時P的值爲0x00372b70。函數調用結束時str的值仍爲0,str並沒有得到那塊100個字節的內存空間地址值!
GetMemory(str); //把str傳進去,str是一個指針,而他實際上是一個int
void GetMemory(char *p) // p是str的一個副本
{
p=(char *)new char[100]; // p的值改變,但是str的值並沒有改變。
}
而雙重指針爲什麼就可以了呢:
GetMemory(&str); //把str的地址傳進去
void GetMemory(char ** p) // p是str地址的一個副本
{
*p = (char *)new char[100]; // p指向的值改變,也就是str的值改變。
}
str可以得到分配內存的地址值。
內存空間狀態:首先申請了四個字節的棧空間,存放str指針,此時str的值爲0,存放str的這塊內存的地址值爲0x0012ff7c。調用函數 GetMemory,指針P入棧,也分配了四個字節的棧空間,此時P是一個二級指針,存放了指針str的地址值,即P的值是0x0012ff7c,存放指針P的內存空間的地址值是0x0012ff2c。然後將新開闢的100個字節的內存空間地址值0x00372b70賦給*P,即str,所以str的值爲
0x00372b70。函數返回時str的值爲分配的100個字節的內存空間的地址!
修改方法1:(推薦使用這種方法)
void GetMemory2(char **p)變爲二級指針.
void GetMemory2(char **p, int num)
{
*p = (char *)malloc(sizeof(char) * num);
}
void Test(void)
{
char *str=NULL;
GetMemory=(&str);
strcpy(str,"hello world");
printf(str);
}
修改方法2:
char *GetMemory()
{
char *p=(char *)malloc(100);
return p;
}
void Test(void){
char *str=NULL;
str=GetMemory();
strcpy(str,"hello world");
printf(str);
}
附錄A(相關資料)
試題5:
char *GetMemory( void )
{
char p[] = "hello world";
return p;
}
void Test( void )
{
char *str = NULL;
str = GetMemory();
printf( str );
}
試題6:
void GetMemory( char **p, int num )
{
*p = (char *) malloc( num );
}
void Test( void )
{
char *str = NULL;
GetMemory( &str, 100 );
strcpy( str, "hello" );
printf( str );
}
試題7:
void Test( void )
{
char *str = (char *) malloc( 100 );
strcpy( str, "hello" );
free( str );
... //省略的其它語句
}
解答:
試題5中
char p[] = "hello world";
return p;
的p[]數組爲函數內的局部自動變量,在函數返回後,內存已經被釋放。這是許多程序員常犯的錯誤,其根源在於不理解變量的生存期。
試題6中
1、GetMemory避免了試題4的問題,傳入GetMemory的參數爲字符串指針的指針,但是在GetMemory中執行申請內存及賦值語句
*p = (char *) malloc( num );
後未判斷內存是否申請成功,應加上:
if ( *p == NULL )
{
...//進行申請內存失敗處理
}
2、試題6的Test函數中也未對malloc的內存進行釋放。
試題7中
存在與試題6同樣的問題,在執行char *str = (char *) malloc(100); 後未進行內存是否申請成功的判斷;另外,在free(str)後未置str爲空,導致可能變成一個“野”指針,應加上: str = NULL; 打印未知。
剖析:
試題4~7考查面試者對內存操作的理解程度,基本功紮實的面試者一般都能正確的回答其中50~60的錯誤。但是要完全解答正確,卻也絕非易事。
對內存操作的考查主要集中在:
(1)指針的理解;
(2)變量的生存期及作用範圍;
(3)良好的動態內存申請和釋放習慣。
再看看下面的一段程序有什麼錯誤:
swap( int* p1,int* p2 )
{
int *p;
*p = *p1;
*p1 = *p2;
*p2 = *p;
}
在swap函數中,p是一個“野”指針,有可能指向系統區,導致程序運行的崩潰。在VC++中DEBUG運行時提示錯誤“Access Violation”。該程序應該改爲:
swap( int* p1,int* p2 )
{
int p;
p = *p1;
*p1 = *p2;
*p2 = p;
}