常见指针内存处理问题的详解

来源:互联网 发布:淘宝发布品牌不能为空 编辑:程序博客网 时间:2024/05/22 03:10

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

常见的 指针,内存操作问题

[cpp] view plaincopy
  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

 

[cpp] view plaincopy
  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[]数组为函数内的局部自动变量,在函数返回后,内存已经被释放。这是许多程序员常犯的错误,其根源在于不理解变量的生存期。

 

[cpp] view plaincopy
  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 ) { ...//进行申请内存失败处理 } 

[cpp] view plaincopy
  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函数将不会成功执行,


原创粉丝点击