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++提供了三种主要的内存分配方式: 1. **静态存储区域分配**: - 这种方式下的...
源码中会包含如何用C++实现二维数组来表示雷区,以及如何进行逻辑判断,显示安全和雷格子。 通过学习这些源代码,你不仅可以掌握C++编程基础,还能深入理解游戏开发中的关键概念,如游戏循环、图形渲染、用户输入...
**C++扫雷程序源代码详解** 扫雷游戏是一款经典的逻辑推理游戏,它在Windows操作系统中广为人知。本篇文章将深入探讨一个使用C++语言实现的扫雷程序,包括其设计思路、主要功能模块以及代码结构。通过阅读源代码和...
**C++可视化扫雷小游戏详解** C++可视化扫雷小游戏是一款经典的桌面游戏,它通过编程语言C++实现,为玩家提供了交互式的体验。这款游戏利用了C++的强大功能,结合了面向对象编程的思想,实现了游戏逻辑、图形用户...
本篇将深入探讨如何使用C++编写一款经典的扫雷游戏,这对于初学者来说是一个极好的实践项目,能够帮助理解面向对象编程、动态内存管理和事件驱动编程等概念。 ### 1. 面向对象编程 扫雷游戏的核心在于设计清晰的类...
C++中,可以使用结构体或类来表示每个格子的状态,并使用算法来生成随机的雷区布局。 9. **李白打酒加强版**(未提供具体内容,但可以推断): - 可能是一个基于数学或逻辑的趣味问题,可能需要理解故事背景并解决...
《C++扫雷代码实现详解》 扫雷,这款经典的Windows小游戏,以其简单却富有挑战性的玩法深受用户喜爱。本文将详细介绍如何使用C++语言实现扫雷游戏的编程过程,包括游戏规则、资源编辑、变量函数定义以及具体实现。 ...
《C++实现MFC扫雷游戏详解》 扫雷,这款经典的Windows系统小游戏,以其简单易上手、挑战性高的特点深受用户喜爱。本项目"Mine_sweeper.rar_Mine!_c++扫雷mfc"是用C++语言基于Microsoft Foundation Classes (MFC)...
【扫雷小游戏 C++ 实现详解】 扫雷是一款经典的单人益智游戏,深受玩家喜爱。用 C++ 来实现这款游戏,可以让我们深入了解面向对象编程、事件驱动编程以及游戏逻辑设计等多个方面的重要知识点。 1. **面向对象编程*...
《C++扫雷游戏开发详解》 扫雷游戏,这个小巧而经典的益智游戏,以其简单易懂的规则和挑战性的玩法,深受广大玩家喜爱。本文将深入探讨如何使用C++编程语言来实现这一游戏,旨在帮助正在学习C++的朋友们理解和实践...
【扫雷小游戏C++实现详解】 扫雷游戏是一款经典的单人益智游戏,玩家需要根据数字提示找出所有未被标记的雷区。本篇将详细解释C++版本的扫雷小游戏代码实现,主要涉及以下几个核心知识点: 1. **内存动态分配**: ...
在实际开发过程中,还会遇到如内存管理、错误处理等问题,这些都是提升编程技能的重要环节。尽管VC6.0已经较为老旧,但它作为经典工具,对于学习C++和MFC仍具有一定的参考价值。而扫雷游戏的实现,无疑是一个很好的...
### C++实现扫雷游戏详解 #### 一、游戏简介及规则 扫雷是一款非常经典的逻辑推理游戏,最初作为Windows操作系统自带的小游戏被广大用户所熟知。本篇将详细介绍如何使用C++语言结合Visual C++ (VC) 开发环境来实现...
5. **游戏逻辑**:扫雷游戏的逻辑包括雷区的生成、点击格子的判定、标记等,这些都需要在网络环境中进行处理,并且需要考虑并发执行时的线程安全。 6. **用户界面**(UI):客户端的界面设计,包括按钮、计时器、...
《扫雷游戏——Visual C++实现详解》 扫雷,这款经典的Windows系统自带小游戏,以其简单易上手、挑战智力的特点深受用户喜爱。在本文中,我们将深入探讨如何使用C++编程语言,结合Visual Studio IDE,来实现一个...
《基于MFC技术实现的扫雷游戏开发详解》 扫雷,这是一款经典的电脑小游戏,以其独特的逻辑性和挑战性深受用户喜爱。本文将探讨如何利用Microsoft Foundation Classes (MFC)库来开发一款与Windows自带扫雷游戏类似的...
《C++实现的控制台扫雷游戏——Buscaminas-cpp详解》 在编程世界里,经典的游戏总是能激发程序员们的创新精神。"Buscaminas-cpp"就是一个使用C++语言在控制台环境中实现的扫雷游戏,它不仅展示了C++的基本语法和...
2. **C++编程**:作为基础语言,C++为游戏的逻辑运算和内存管理提供了高效和灵活的控制。开发者使用C++编写游戏的核心算法,如雷区生成、数字计算、标记等。 3. **自定义UI**:不依赖于UI控件拖拽,意味着开发者...
在本项目中,我们将探讨使用Qt框架实现扫雷游戏的源码解析。 首先,Qt是一个跨平台的C++图形用户界面应用程序开发框架,广泛用于开发桌面应用、移动应用以及嵌入式系统。其丰富的API库和强大的设计工具使得开发者...