常見指針內存處理問題的詳解

http://blog.csdn.net/tianmo2010/article/details/6785912

常見的 指針,內存操作問題

  1. void getMemory(char *p)  
  2.   
  3. {  
  4.   
  5.          p = (char *)malloc(100);  
  6.   
  7. }  
  8.   
  9. int main()  
  10.   
  11. {  
  12.   
  13.          char *str = NULL;  
  14.   
  15.          getMemory(str);  
  16.   
  17.          strcpy(str,"hello world.");  
  18.   
  19.          printf("str = %s\n",str);  
  20.   
  21. }  


傳入中GetMemory( char *p )函數的形參爲字符串指針,在函數內部修改形參並不能真正的改變傳入形參的值,執行完 char *str = NULL; GetMemory( str ); 後的str仍然爲NULL

 

  1. char* getMemory()  
  2.   
  3. {  
  4.   
  5.          char p[] = "hello world";  
  6.   
  7.          return p;  
  8.   
  9. }  
  10.   
  11. int main()  
  12.   
  13. {  
  14.   
  15.          char *str = NULL;  
  16.   
  17.          str = getMemory();  
  18.   
  19.          printf("str = %s\n",str);  
  20.   
  21. }  


char p[] = "hello world"; return p; 的p[]數組爲函數內的局部自動變量,在函數返回後,內存已經被釋放。這是許多程序員常犯的錯誤,其根源在於不理解變量的生存期。

 

  1. void getMemory(char **p,int num)  
  2.   
  3. {  
  4.   
  5.          *p = (char *)malloc(num);  
  6.   
  7. }  
  8.   
  9. int main()  
  10.   
  11. {  
  12.   
  13.          char *str = NULL;  
  14.   
  15.          getMemory(&str,100);  
  16.   
  17.          strcpy(str,"hello world.");  
  18.   
  19.          printf("str = %s\n",str);  
  20.   
  21. }  


傳入GetMemory的參數爲字符串指針的指針,但是在GetMemory中執行申請內存及賦值語句 tiffanybracelets *p = (char *) malloc( num ); 後未判斷內存是否申請成功,應加上:

 if ( *p == NULL ) { ...//進行申請內存失敗處理 } 

  1. int main()  
  2.   
  3. {  
  4.   
  5.          char *str = (char *)malloc(100);  
  6.   
  7.          strcpy(str,"hello world.");  
  8.   
  9.          printf("str = %s\n",str);  
  10.   
  11.          free(str);  
  12.   
  13. }  


在執行 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函數將不會成功執行,


發佈了27 篇原創文章 · 獲贊 10 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章