http://blog.csdn.net/tianmo2010/article/details/6785912
常見的 指針,內存操作問題
- void getMemory(char *p)
- {
- p = (char *)malloc(100);
- }
- int main()
- {
- char *str = NULL;
- getMemory(str);
- strcpy(str,"hello world.");
- printf("str = %s\n",str);
- }
傳入中GetMemory( char *p )函數的形參爲字符串指針,在函數內部修改形參並不能真正的改變傳入形參的值,執行完 char *str = NULL; GetMemory( str ); 後的str仍然爲NULL
- char* getMemory()
- {
- char p[] = "hello world";
- return p;
- }
- int main()
- {
- char *str = NULL;
- str = getMemory();
- printf("str = %s\n",str);
- }
char p[] = "hello world"; return p; 的p[]數組爲函數內的局部自動變量,在函數返回後,內存已經被釋放。這是許多程序員常犯的錯誤,其根源在於不理解變量的生存期。
- void getMemory(char **p,int num)
- {
- *p = (char *)malloc(num);
- }
- int main()
- {
- char *str = NULL;
- getMemory(&str,100);
- strcpy(str,"hello world.");
- printf("str = %s\n",str);
- }
傳入GetMemory的參數爲字符串指針的指針,但是在GetMemory中執行申請內存及賦值語句 tiffanybracelets *p = (char *) malloc( num ); 後未判斷內存是否申請成功,應加上:
if ( *p == NULL ) { ...//進行申請內存失敗處理 }
- int main()
- {
- char *str = (char *)malloc(100);
- strcpy(str,"hello world.");
- printf("str = %s\n",str);
- free(str);
- }
在執行 char *str = (char *) malloc(100); 後未進行內存是否申請成功的判斷;另外,在free(str)後未置str爲空,導致可能變成一個“野”指針,應加上: str = NULL;
關於指針應用的小結:(非常重要的幾個知識點)
1. 每當寫一個子函數時,如果函數的形式參數有指針類型時,應該首先判斷其是否爲空
2. 每當對一個指針變量申請動態存儲空間後,應該立即判斷其是否申請成功
3. 對應的指針變量,如果開始已經申請動態存儲空間,在其使用完畢以後,我們應該立即將其空間釋放,以免造成內存泄露
補充的問題:
找出下面幾個函數的錯誤:
試題1:
void test1()
{
char string[10];
char* str1 = "0123456789";
strcpy( string, str1 );
}
/*
這個題目咋一看,沒有任何錯誤, 給strcpy()函數傳遞的兩個實參參數類型均能滿足要求。 但是細心一看我們會發現這個函數存在越界問題,"0123456789"這個字符串 的長度爲 strlen("0123456789") + 1 = 11 , 而很顯然string[10],不可能存儲這麼大的空間。 通常在使用strcpy函數時一定要考慮源串、和目的串的大小問題。
*/
函數改成下面的形式可能會健壯一些:
int StrCpy(const char *source; char dest[])
{
if( NULL==source || NULL == dest || ( strlen(dest) < strlen(source) ) )
return 1; // 返回值=1 表示複製失敗
else
strcpy(dest,source);
return 0; //返回值=0 表示複製成功
}
試題2::
void test2()
{
char string[10], str1[10];
int i;
for(i=0; i<10; i++)
{
str1 = 'a';
}
strcpy( string, str1 );
}
/*
這個題目考查了兩個問題:
1、 數組的首地址是常量,不可以作爲左值, 即str1是一個常量,
它代表整個數組的首地址。
2、 第二數組的引用需要用下標,除了初始化時可以int iArray[10]={1,2}
這樣賦值外,在其他地方不可以批量給數組元素賦值。
3、 同時strcpy複製函數是針對具有'\0'的字符類型變量,因此這個函數賦
值同樣存在賦值越界的情況。
*/
改成下面的方式估計會健壯一些:
void test2( )
{
char string[10],
str1[10] ;
for(int i=0; i<10; i++)
str1[i] = 'a';
str[9]='\0';
strcpy(string , str1);
}
試題3:
void test3(char* str1)
{
char string[10];
if( strlen( str1 ) <= 10 )
{
strcpy( string, str1 );
}
}
//試題3同樣存在越界的可能性。如果strlen(str1)=10, 則實際上str1佔用的空間是11個。
//strlen函數返回的長度沒有計算末尾'\0'字符。 因此需要注意。
改爲下面的方式可能會更健壯:
void test3(char* str1)
{
char string[10];
if( strlen( str1 ) < 10 && NULL != str1 )
strcpy( string, str1 );
}
試題4:
void GetMemory( char *p )
{
p = (char *) malloc( 100 );
}
void Test( void )
{
char *str = NULL;
GetMemory( str );
strcpy( str, "hello world" );
printf( str );
}
/*
首先這個題目存在內存泄露的問題和指針指向空地址問題
說說這個題目的存在的幾個問題:
1、 在GetMemory函數裏面, 沒有對malloc函數返回值進行測試
if(NULL==p)
2、 在函數裏面沒有對指針p進行釋放
free(p);
3、這裏會有一個問題,在C語言中默認時按值傳遞的, 不是按照地址傳遞的。
在程序裏面不能改變str的指向。
GetMemory(str);不能改變str的指向。
函數原型爲:
void GetMemory(char *p); 定義的就是一個指針類型的參數。
4、在函數內部不能改變傳值參數的值
*/
/*****************
malloc函數的實質體現在,它有一個將可用的內存塊連接爲一個長長的列表的所謂空閒鏈表。調用malloc函數時,
它沿連接表尋找一個大到足以滿足用戶請求所需要的內存塊。然後,將該內存塊一分爲二(一塊的大小與用戶請求
的大小相等,另一塊的大小就是剩下的字節)。接下來,將分配給用戶的那塊內存傳給用戶,並將剩下的那塊(如果
有的話)返回到連接表上。調用free函數時,它將用戶釋放的內存塊連接到空閒鏈上。到最後,空閒鏈會被切成很多
的小內存片段,如果這時用戶申請一個大的內存片段,那麼空閒鏈上可能沒有可以滿足用戶要求的片段了。於是,
malloc函數請求延時,並開始在空閒鏈上翻箱倒櫃地檢查各內存片段,對它們進行整理,將相鄰的小空閒塊合併成較大
的內存塊。如果無法獲得符合要求的內存塊,malloc函數會返回NULL指針,因此在調用malloc動態申請內存塊時,一定要
進行返回值的判斷。
**************/
改成下面形式可能更健壯一些:
Void GetMemory(char **p)
{
char *temp;
if(NULL != (temp=(char *)malloc(1000)))
*p=temp;
free(temp);
}
試題5:
char *GetMemory( void )
{
char p[] = "hello world";
return p;
}
void Test( void )
{
char *str = NULL;
str = GetMemory();
printf( str );
}
/* 其實怎麼說呢這個題目的理解比上面一個題目來對簡單, 但是通過這個題目和上面
的題目需要知道一個事實:
那就是函數內部聲明的局部變量(static類型的除外,當然還有register的除外),這裏指的
是auto類型的變量, 其內存空間是在系統爲應用程序開闢的棧裏面申請。
而malloc函數申請的空間則是從系統爲應用程序開闢的堆裏面申請。堆裏面申請的不會自動釋放,
而棧裏面申請的會隨着函數聲明週期的結束而自動釋放。
這個題目的錯誤之處在於沒有理解局部變量的生命週期。
*/
改成下面的形式可能會更健壯:
char *getmemory(void)
{
char *p=NULL;
if(NULL !=(p=(char *)malloc(strlen("hello word")+1))
return p;
}
試題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 );
}
/*
這個題目在第四個題目已經實現和論述,不再論述
指的一提的是:
傳遞&str值,並不能改變str的指向。
*/
試題7:
void Test( void )
{
char *str = (char *) malloc( 100 );
strcpy( str, "hello" );
free( str );
... //省略的其它語句
}
/*
這個題目比上面的更加簡單, 它的問題就是沒有對malloc函數的返回情況進行
檢測,
如果 NULL=(char *)malloc(NUM) 那麼strcpy函數將不會成功執行,