C内存操作

来源:互联网 发布:苹果蜂窝网络怎么回事 编辑:程序博客网 时间:2024/05/21 21:40

一、使用指针做函数返回值:

1、当使用指针做为函数的返回值时,主函数处的char *p;将获得调用函数char *pf;的值,即一个地址值,如oxAE72。此时需要我们注意的是该地址值所指向的空间是否存在(即已向操作系统声明注册,不会被释放,即可能被其他操作修改)

2、使用栈内存返回指针是明显错误的,因为栈内存将在调用结束后自动释放,从而主函数使用该地址空间将很危险。

   例如:

            char* GetMemory()

            {

                        char p[] = "hi";

                        return p;

            }

            void main()

            {

                      char *str = GetMemory(); //出错得到一块已释放的内存

                        printf(str);

            }

3、使用堆内存返回指针是正确的,但是注意可能产生内存泄露问题,在使用完毕后主函数中释放该段内存。

   例如:

            char* GetMemory()

            {

                        char *p = new char[100];

                        return p;

            }

            void main()

            {

                        char *str = GetMemory();

                        delete [] str;       //防止内存泄露!

            }

 

二、使用指针做函数参数:

1、有的情况下我们可能需要需要在调用函数中分配内存,而在主函数中使用,而针对的指针此时为函数的参数。此时应注意形参与实参的问题,因为在C语言中,形参只是继承了实参的值,是另外一个量(ps:返回值也是同理,传递了一个地址值(指针)或实数值),形参的改变并不能引起实参的改变。

2、直接使用形参分配内存的方式显然是错误的,因为实参的值并不会改变,如下则实参一直为NULL:

            void GetMemory(char* p)

            {

                        char *p = new char[100];

            }

            void main()

            {

                        char *str;

                        GetMemory(str);

                        strcpy(str, "hi"); //出错! str = NULL!

            }

3、由于通过指针是可以传值的,因为此时该指针的地址是在主函数中申请的栈内存,我们通过指针对该栈内存进行操作,从而改变了实参的值。

            void Change(char *p)

            {

                        *p = 'b';

            }

            void main()

            {

                        char a = 'a';

                        char* p = &a;

                        Change(p);

                        printf("%c"n", a);           //a改变!

            }

4、根据上述的启发,我们也可以采用指向指针的指针来进行在调用函数中申请,在主函数中应用。如下:假设a的地址为ox23,内容为'a';而str的地址是ox46,内容为ox23;而pstr的地址是ox79,内容为ox46

我们通过调用函数GetMemory,从而将pstr的内容赋给了p,此时p = ox46。通过对*p(ox23)的操作,即将内存地址为ox23之中的值改为char[100]的首地址,从而完成了对char* str地址的分配。

            void GetMemory(char** p)

            {

                        char *p = new char[100];

            }

            void main()

            {

                        char a = 'a';

                        char* str = &a;

                        char** pstr = &str;

                        GetMemory(pstr);

                        strcpy(str, "hi");

            }

5、注意指针的释放问题,可能形成悬浮指针。

当我们释放掉一个指针p后,只是告诉操作系统该段内存可以被其他程序使用,而该指针p的地址值(ox23)仍然存在。如果再次给这块地址赋值是危险的,应该将p指针置为NULL

调用函数删除主函数中的内存块时,虽然可以通过地址传递直接删除,但由于无法对该指针赋值(形参不能传值),可能造成悬浮指针,所以此时也应该采用指向指针的指针的形参。例如:

            void MemoryFree(char** p)

            {

                        delete *p;

                        *p = NULL;

            }

            void main()

          {

                        char *str = new char[100];

                        char *pstr = &str;

                        MemoryFree(pstr);        

            }

 

 

 

 

 

 

内存操作

 

 

 

 

 

 

 

 

 

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");将使程序崩溃。

  char *GetMemory(void)

  {

  char p[] = "hello world";

  return p;

  }

  void Test(void)

  {

  char *str = NULL;

  str = GetMemory();

  printf(str);

  }

  请问运行Test函数会有什么样的结果?

  答:可能是乱码。

  因为GetMemory返回的是指向“栈内存”的指针,该指针的地址不是 NULL,但其原现的内容已经被清除,新内容不可知。

  void GetMemory2(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)内存泄漏

  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)语句不起作用。

 

 

试题4:
void GetMemory( char *p )
{
 p = (char *) malloc( 100 );
}

void Test( void ) 
{
 char *str = NULL;
 GetMemory( str ); 
 strcpy( str, "hello world" );
 printf( str );
}
试题4传入中GetMemory( char *p )函数的形参为字符串指针,在函数内部修改形参并不能真正的改变传入形参的值,执行完
char *str = NULL; GetMemory( str ); 后的str仍然为NULL;
  
试题5:
char *GetMemory( void )

 char p[] = "hello world"; 
 return p; 
}

void Test( void )

 char *str = NULL; 
 str = GetMemory(); 
 printf( str ); 
}
试题5中char p[] = "hello world"; return p; 的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 ); 
}
试题6的GetMemory避免了试题4的问题,传入GetMemory的参数为字符串指针的指针,但是在GetMemory中执行申请内存及赋值语句*p = (char *) malloc( num );后未判断内存是否申请成功,应加上:
if ( *p == NULL )
{
 ...//进行申请内存失败处理
}
  试题6的Test函数中也未对malloc的内存进行释放。

试题7:
void Test( void )
{
 char *str = (char *) malloc( 100 );
 strcpy( str, "hello" );
 free( str ); 
 ... //省略的其它语句
}
试题7存在与试题6同样的问题,在执行char *str = (char *) malloc(100);后未进行内存是否申请成功的判断;另外,在free(str)后未置str为空,导致可能变成一个“野”指针,应加上:str = NULL;


  剖析:

  试题4~7考查面试者对内存操作的理解程度,基本功扎实的面试者一般都能正确的回答其中50~60的错误。但是要完全解答正确,却也绝非易事。

  对内存操作的考查主要集中在:

  (1)指针的理解;

  (2)变量的生存期及作用范围;

  (3)良好的动态内存申请和释放习惯。

原创粉丝点击