在处理C内存分派的时候,我们总会毫不犹豫的犯下各种错误,不信的话,你先看看下面几个例子。

  例子一:

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

  如果,上面四个例子,你竟然都答对了,那下面的内容,就不是为你准备的了,你还是去别处转转吧!

 

                      C/C++程序内存的分配

  在C/C++程序中分为这几个存储区:

   1.栈区: 存放函数参数,局部变量等,由编译器自动分配释放。

  2.堆区: 用于动态分配内存的, 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。

  3.全局区(静态区):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,

   未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 程序结束时释放。

  4.另外还有一个专门放常量的地方,程序结束释放。

  例如:

  int a = 0; //全局初始化区

  char *p1; //全局未初始化区

  main()
  {
    int b; //
    char s[] = "abc"; //S在栈上,"abc"在常量区
    char *p2; //
    char *p3 = "123456"; //"123456"在常量区,p3在栈上
    static int c = 0; //全局(静态)初始化区
    p1 = (char *)malloc(10);
    p2 = (char *)malloc(20);//分配得来得1020字节的区域就在堆区。
    strcpy(p1, "123456");//"123456"放在常量区,编译器可能会将p1与p3所指向的"123456"优化成一块。
  }

                        一些常见的内存错误及其应对策略

      1、内存分配为成功便使用。常用解决办法是,在使用内存之前检查指针是否为 NULL。

  2、尚未初始化就引用。犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为零,

    导致引用初值错误(例如数组) 。所以无论用何种方式创建数组,都别忘了赋初值。 

  3、操作越过了内存的边界。

  4、忘了释放内存,造成内存泄漏。动态内存的申请与释放必须配对,程序中 malloc 与 free 的使用次数一定要相同,

    否则肯定有错误(new/delete 同理) 。

  5、释放了的内存,还继续使用。主要有两种情况: 

    (1)函数的 return 语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用” ,因为该内存在函数体结束时被自动销毁。 

    (2)使用 free 或 delete 释放了内存后,没有将指针设置为 NULL。导致产生“野指针” 。  

     因此,建议你:

  1、用 malloc 或 new 申请内存之后,应该立即检查指针值是否为 NULL。防止使用指针值为 NULL 的内存。

  2、不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。

  3、避免数组或指针的下标越界,特别要当心发生“多 1”或者“少 1”操作。

  4、动态内存的申请与释放必须配对,防止内存泄漏。

  5、用 free 或 delete 释放了内存之后,立即将指针设置为 NULL,防止产生“野指针” 。