`
weiyinchao88
  • 浏览: 1234383 次
文章分类
社区版块
存档分类
最新评论

踏入C++中的雷区——C++内存管理详解(II)

 
阅读更多
4、指针参数是如何传递内存的?

  如果函数的参数是一个指针,不要指望用该指针去申请动态内存。示例7-4-1中,Test函数的语句GetMemory(str, 200)并没有使str获得期望的内存,str依旧是NULL,为什么?

void GetMemory(char *p, int num)
{
 p = (char *)malloc(sizeof(char) * num);
}
void Test(void)
{
 char *str = NULL;
 GetMemory(str, 100); // str 仍然为 NULL
 strcpy(str, "hello"); // 运行错误
}
      示例4.1 试图用指针参数申请动态内存

  毛病出在函数GetMemory中。编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是 _p,编译器使 _p = p。如果函数体内的程序修改了_p的内容,就导致参数p的内容作相应的修改。这就是指针可以用作输出参数的原因。在本例中,_p申请了新的内存,只是把_p所指的内存地址改变了,但是p丝毫未变。所以函数GetMemory并不能输出任何东西。事实上,每执行一次GetMemory就会泄露一块内存,因为没有用free释放内存。

  如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”,见示例4.2。

void GetMemory2(char **p, int num)
{
 *p = (char *)malloc(sizeof(char) * num);
}
void Test2(void)
{
 char *str = NULL;
 GetMemory2(&str, 100); // 注意参数是 &str,而不是str
 strcpy(str, "hello");
 cout<< str << endl;
 free(str);
}
      示例4.2用指向指针的指针申请动态内存

  由于“指向指针的指针”这个概念不容易理解,我们可以用函数返回值来传递动态内存。这种方法更加简单,见示例4.3。

char *GetMemory3(int num)
{
 char *p = (char *)malloc(sizeof(char) * num);
 return p;
}
void Test3(void)
{
 char *str = NULL;
 str = GetMemory3(100);
 strcpy(str, "hello");
 cout<< str << endl;
 free(str);
}
       示例4.3 用函数返回值来传递动态内存

  用函数返回值来传递动态内存这种方法虽然好用,但是常常有人把return语句用错了。这里强调不要用return语句返回指向“栈内存”的指针,因为该内存在函数结束时自动消亡,见示例4.4。

char *GetString(void)
{
 char p[] = "hello world";
 return p; // 编译器将提出警告
}
void Test4(void)
{
 char *str = NULL;
 str = GetString(); // str 的内容是垃圾
 cout<< str << endl;
}
      示例4.4 return语句返回指向“栈内存”的指针

  用调试器逐步跟踪Test4,发现执行str = GetString语句后str不再是NULL指针,但是str的内容不是“hello world”而是垃圾。
如果把示例4.4改写成示例4.5,会怎么样?

char *GetString2(void)
{
 char *p = "hello world";
 return p;
}
void Test5(void)
{
 char *str = NULL;
 str = GetString2();
 cout<< str << endl;
}
     示例4.5 return语句返回常量字符串

  函数Test5运行虽然不会出错,但是函数GetString2的设计概念却是错误的。因为GetString2内的“hello world”是常量字符串,位于静态存储区,它在程序生命期内恒定不变。无论什么时候调用GetString2,它返回的始终是同一个“只读”的内存块。

  5、杜绝“野指针”

  “野指针”不是NULL指针,是指向“垃圾”内存的指针。人们一般不会错用NULL指针,因为用if语句很容易判断。但是“野指针”是很危险的,if语句对它不起作用。 “野指针”的成因主要有两种:

  (1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。例如

char *p = NULL;
char *str = (char *) malloc(100);

  (2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。

  (3)指针操作超越了变量的作用范围。这种情况让人防不胜防,示例程序如下:

class A
{
 public:
  void Func(void){ cout << “Func of class A” << endl; }
};
void Test(void)
{
 A *p;
 {
  A a;
  p = &a; // 注意 a 的生命期
 }
 p->Func(); // p是“野指针”
}


  函数Test在执行语句p->Func()时,对象a已经消失,而p是指向a的,所以p就成了“野指针”。但奇怪的是我运行这个程序时居然没有出错,这可能与编译器有关。

分享到:
评论

相关推荐

    C++中的雷区——C++内存管理详解

    C++中的雷区——C++内存管理详解C++中的雷区——C++内存管理详解C++中的雷区——C++内存管理详解C++中的雷区——C++内存管理详解

    踏入C++中的雷区C++内存管理详解

    ### C++内存管理详解 #### 一、内存分配方式 C++中的内存管理非常重要,它直接关系到程序的稳定性和性能。根据不同的应用场景,C++提供了三种主要的内存分配方式: 1. **静态存储区域分配**: - 这种方式下的...

    《Visual C++ 游戏开发经典案例详解》源代码

    源码中会包含如何用C++实现二维数组来表示雷区,以及如何进行逻辑判断,显示安全和雷格子。 通过学习这些源代码,你不仅可以掌握C++编程基础,还能深入理解游戏开发中的关键概念,如游戏循环、图形渲染、用户输入...

    C++扫雷程序源代码

    **C++扫雷程序源代码详解** 扫雷游戏是一款经典的逻辑推理游戏,它在Windows操作系统中广为人知。本篇文章将深入探讨一个使用C++语言实现的扫雷程序,包括其设计思路、主要功能模块以及代码结构。通过阅读源代码和...

    C++可视化扫雷小游戏

    **C++可视化扫雷小游戏详解** C++可视化扫雷小游戏是一款经典的桌面游戏,它通过编程语言C++实现,为玩家提供了交互式的体验。这款游戏利用了C++的强大功能,结合了面向对象编程的思想,实现了游戏逻辑、图形用户...

    C++程序小例子

    本篇将深入探讨如何使用C++编写一款经典的扫雷游戏,这对于初学者来说是一个极好的实践项目,能够帮助理解面向对象编程、动态内存管理和事件驱动编程等概念。 ### 1. 面向对象编程 扫雷游戏的核心在于设计清晰的类...

    2022年第十三届蓝桥杯省赛 C/C++ B组 真题

    C++中,可以使用结构体或类来表示每个格子的状态,并使用算法来生成随机的雷区布局。 9. **李白打酒加强版**(未提供具体内容,但可以推断): - 可能是一个基于数学或逻辑的趣味问题,可能需要理解故事背景并解决...

    C++扫雷代码

    《C++扫雷代码实现详解》 扫雷,这款经典的Windows小游戏,以其简单却富有挑战性的玩法深受用户喜爱。本文将详细介绍如何使用C++语言实现扫雷游戏的编程过程,包括游戏规则、资源编辑、变量函数定义以及具体实现。 ...

    Mine_sweeper.rar_Mine!_c++扫雷mfc

    《C++实现MFC扫雷游戏详解》 扫雷,这款经典的Windows系统小游戏,以其简单易上手、挑战性高的特点深受用户喜爱。本项目"Mine_sweeper.rar_Mine!_c++扫雷mfc"是用C++语言基于Microsoft Foundation Classes (MFC)...

    扫雷 c++ 小游戏

    【扫雷小游戏 C++ 实现详解】 扫雷是一款经典的单人益智游戏,深受玩家喜爱。用 C++ 来实现这款游戏,可以让我们深入了解面向对象编程、事件驱动编程以及游戏逻辑设计等多个方面的重要知识点。 1. **面向对象编程*...

    C++扫雷游戏

    《C++扫雷游戏开发详解》 扫雷游戏,这个小巧而经典的益智游戏,以其简单易懂的规则和挑战性的玩法,深受广大玩家喜爱。本文将深入探讨如何使用C++编程语言来实现这一游戏,旨在帮助正在学习C++的朋友们理解和实践...

    扫雷小游戏代码c++版.pdf

    【扫雷小游戏C++实现详解】 扫雷游戏是一款经典的单人益智游戏,玩家需要根据数字提示找出所有未被标记的雷区。本篇将详细解释C++版本的扫雷小游戏代码实现,主要涉及以下几个核心知识点: 1. **内存动态分配**: ...

    用vc6.0写的扫雷游戏

    在实际开发过程中,还会遇到如内存管理、错误处理等问题,这些都是提升编程技能的重要环节。尽管VC6.0已经较为老旧,但它作为经典工具,对于学习C++和MFC仍具有一定的参考价值。而扫雷游戏的实现,无疑是一个很好的...

    C++ 扫雷游戏

    ### C++实现扫雷游戏详解 #### 一、游戏简介及规则 扫雷是一款非常经典的逻辑推理游戏,最初作为Windows操作系统自带的小游戏被广大用户所熟知。本篇将详细介绍如何使用C++语言结合Visual C++ (VC) 开发环境来实现...

    基于Visual C++实现的网络扫雷游戏

    5. **游戏逻辑**:扫雷游戏的逻辑包括雷区的生成、点击格子的判定、标记等,这些都需要在网络环境中进行处理,并且需要考虑并发执行时的线程安全。 6. **用户界面**(UI):客户端的界面设计,包括按钮、计时器、...

    saolei.rar_visual c

    《扫雷游戏——Visual C++实现详解》 扫雷,这款经典的Windows系统自带小游戏,以其简单易上手、挑战智力的特点深受用户喜爱。在本文中,我们将深入探讨如何使用C++编程语言,结合Visual Studio IDE,来实现一个...

    用MFC开发的扫雷游戏程序(含源码)

    《基于MFC技术实现的扫雷游戏开发详解》 扫雷,这是一款经典的电脑小游戏,以其独特的逻辑性和挑战性深受用户喜爱。本文将探讨如何利用Microsoft Foundation Classes (MFC)库来开发一款与Windows自带扫雷游戏类似的...

    Buscaminas-cpp:Consola中的Buscaminas utilizando C ++

    《C++实现的控制台扫雷游戏——Buscaminas-cpp详解》 在编程世界里,经典的游戏总是能激发程序员们的创新精神。"Buscaminas-cpp"就是一个使用C++语言在控制台环境中实现的扫雷游戏,它不仅展示了C++的基本语法和...

    基于QT扫雷小游戏.rar

    2. **C++编程**:作为基础语言,C++为游戏的逻辑运算和内存管理提供了高效和灵活的控制。开发者使用C++编写游戏的核心算法,如雷区生成、数字计算、标记等。 3. **自定义UI**:不依赖于UI控件拖拽,意味着开发者...

    扫雷小游戏详解源码1111111

    在本项目中,我们将探讨使用Qt框架实现扫雷游戏的源码解析。 首先,Qt是一个跨平台的C++图形用户界面应用程序开发框架,广泛用于开发桌面应用、移动应用以及嵌入式系统。其丰富的API库和强大的设计工具使得开发者...

Global site tag (gtag.js) - Google Analytics