c++题目标题:生成指定字符构成的php 字符串相关的题目。

  Java编程语言是一种面向对象的语言,它通过提供最基本的方法来完成指定的任务,只需理解一些基本的概念,就可以用它编写出适合于各种情况的应用程序。 Java软件编程略去了运算符重载、多重继承等模糊的概念,并且通过实现自动垃圾收集大大简化了程序设计者的内存管理工作。另外,Java也适合于在小型机上运行,它的基本解释器及类的支持只有40KB左右,加上标准类库和线程的支持也只有215KB左右。
  Java软件编程何时开始发展?
  最早大概可追溯至1991年四月份,Sun的绿色计划(Green Project)开始着手于发展消费性电子产品( Electronics),所使用的语言是C、C++、及Oak (为Java语言的前身),后因语言本身和市场的问题,使得消费性电子产品的发展无法达到当初预期的目标,再加上网络的兴起,绿色计划也因此而改变发展的方向,这已是1994 年了。
  高效能的(High Performance):Java位元码迅速地能被转换成机器码(Machine Code), 从位元码转换到机器码的效能几乎与C与C++没有分别。 多线程的(Multi threaded):Java语言具有多线程的功能,这对于交互回应能力及即时执行行为是有帮助的。动态的(Dynamic):Java比C或C++语言更具有动态性,更能适应时刻在变的环境, Java不会因程序库的更新,而必须重新编译程序。
  Java代码是可移植的,但C及C++不是
  Java原代码(Source Code)是比C语言来得可移植一点,差别在于Java的目标码。Java码在一种机器上进行编译,而能在所有的机器上执行,只要那部机器上有Java解释器。
  Java软件编程语言能被拓展而在机器上执行任何事情
  理论上,Java Applet (Java小应用程序)能做任何事情,如模拟3D VRML模型、播放电影、产生音频....等。但事实上,一个小应用程序(Applet)仅能在那一页上被执行,而无法在那一页之外执行。同时,Java亦受限于程序库的功能。
  Java软件编程是适合于建立大型的应用程序
  如果Java适合于大型程序,则Java就不适合应用于Web浏览器了。第一个商业 性的Java Applets (Applix's Java-Based Spreadsheet) 并不是全然使用Java,它只使用Java作为用户接口,而所有的处理工作,是用CGI码。
  目前IT行业Java编程是最炙手可热的技术,Java应用范围广泛,企业在大量招收Java人才,薪水也随之上涨,发展前景越来越好,许多刚毕业的大学生,想转行的社会人士都想从事此行业,对于这些零基础想要学习Java的同学,推荐动力节点Java培训,动力节点是一家专注Java培训的机构,09年成立,至今已有8年的教学历史,从最初的“默默无闻”到如今的“口口相传”,被业界称为“口口相传的Java黄埔军校” 在其它培训机构不断开发出UI、iOS、Android、HTML5等课程,并且分校在全国遍地开花时,8年来,动力节点始终坚守在北京的大本营,不盲目扩张,坚持将Java做细、做精、做强,用专一定义专业,并把学员利益放在企业利益的前面,在这些年内汇聚国内一线Java专家团队,拥有几十余位一线技术大牛,多位核心研发工程师,有着多年软件行业实战经验的IT精英人士组成的讲师团队,课程体系围绕企业真实项目而设计,把各个知识点穿插到项目中去讲解,达到融汇贯通的目的,确保学员去企业就可以胜任项目开发。且课程研发部门每期会对课程做一次评估,更新一次课程内容和案例,确保课程体系紧跟行业发展,满足企业用人需求,做到永不脱节。
声明:本文由入驻搜狐公众平台的作者撰写,除搜狐官方账号外,观点仅代表作者本人,不代表搜狐立场。Windows环境下32位汇编语言程序设计(典藏版) - 推酷
Windows环境下32位汇编语言程序设计(典藏版)
《Windows环境下32位汇编语言程序设计(典藏版)》
作者: 罗云彬 &&
出版社:电子工业出版社
上架时间:
出版日期:2013 年7月
开本:16开
所属分类:计算机
更多关于 》》》《
& & 计算机书籍
windows环境下32位汇编语言是一种全新的编程语言。它使用与c++语言相同的api接口,不仅可以开发出大型的软件,而且是了解操作系统运行细节的最佳方式。
《windows环境下32位汇编语言程序设计(典藏版)》从编写应用程序的角度,从“hello,world!”这个简单的例子开始到编写多线程、注册表和网络通信等复杂的程序,通过70多个实例逐步深入windows环境下32位汇编语言编程的方方面面。
作者罗云彬拥有10余年汇编语言编程经验,本书是作者多年来编程工作的总结,适合于欲通过windows环境下32汇编语言编写windows程序的读者。&
《windows环境下32位汇编语言程序设计(典藏版)》&
第1章 背景知识
1.1 win32的软硬件平台
1.1.1 80x86系列处理器简史
1.1.2 windows的历史
1.1.3 win32平台的背后——wintel联盟
1.2 windows的特色
1.3 必须了解的基础知识
1.3.1 80x86处理器的工作模式
1.3.2 windows的内存管理
1.3.3 windows的特权保护
第2章 准备编程环境
2.1 win32可执行文件的开发过程
2.2 编译器和链接器
2.2.1 masm系列
2.2.2 tasm系列
2.2.3 其他编译器
2.2.4 masm,tasm还是nasm
2.2.5 我们的选择——masm32 sdk软件包
.2.3 创建资源
2.3.1 资源编译器的使用
2.3.2 所见即所得的资源编辑器
2.4 make工具的用法
2.4.1 make工具是什么
2.4.2 nmake的用法
2.4.3 描述文件的语法
2.5 获取资料
2.5.1 windows资料的来源
2.5.2 intel处理器资料
2.6 构建编程环境
2.6.1 ide还是命令行
2.6.2 本书推荐的工作环境
2.6.3 尝试编译第一个程序
第3章 使用masm
3.1 win32汇编源程序的结构
3.1.1 模式定义
3.1.2 段的定义
3.1.3 程序结束和程序入口
3.1.4 注释和换行
3.2 调用api
3.2.1 api是什么
3.2.2 调用api
3.2.3 api参数中的等值定义
3.3 标号、变量和数据结构
3.3.1 标号
3.3.2 全局变量
3.3.3 局部变量
3.3.4 数据结构
3.3.5 变量的使用
3.4 使用子程序
3.4.1 子程序的定义
3.4.2 参数传递和堆栈平衡
3.5 高级语法
3.5.1 条件测试语句
3.5.2 分支语句
3.5.3 循环语句
3.6 代码风格
3.6.1 变量和函数的命名
3.6.2 代码的书写格式
3.6.3 代码的组织
第4章 第一个窗口程序
4.1 开始了解窗口
4.1.1 窗口是什么
4.1.2 窗口界面
4.1.3 窗口程序是怎么工作的
4.2 分析窗口程序
4.2.1 模块和句柄
4.2.2 创建窗口
4.2.3 消息循环
4.2.4 窗口过程
4.3 窗口间的通信
4.3.1 窗口间的消息互发
4.3.2 在窗口间传递数据
4.3.3 sendmessage和postmessage函数的区别
第5章 使用资源
5.1 菜单和加速键
5.1.1 菜单和加速键的组成
5.1.2 菜单和加速键的资源定义
5.1.3 使用菜单和加速键
5.2 图标和光标
5.2.1 图标和光标的资源定义
5.2.2 使用图标和光标
5.3.1 位图简介
5.3.2 在资源中定义位图
5.4 对话框
5.4.1 对话框简介
5.4.2 对话框的资源定义
5.4.3 使用对话框
5.4.4 在对话框中使用子窗口控件
5.5 字符串资源
5.6 版本信息资源
5.6.1 版本信息资源的定义
5.6.2 在程序中检测版本信息
5.7 二进制资源和自定义资源
5.7.1 使用二进制资源
5.7.2 使用自定义资源
第6章 定时器和windows时间
6.1 定时器
6.1.1 定时器简介
6.1.2 定时器的使用方法
6.2 windows时间
6.2.1 windows时间的获取和设置
6.2.2 计算时间间隔
第7章 图形操作
7.1 gdi原理
7.1.1 gdi程序的结构
7.1.2 设备环境
7.1.3 色彩和坐标
7.2 绘制图形
7.2.1 画笔和画刷
7.2.2 绘制像素点
7.2.3 绘制图形
7.2.4 绘图模式
7.3 创建和使用位图
7.3.1 一个使用位图的时钟例子
7.3.2 创建和使用位图
7.3.3 使用设备无关位图
7.4 块传送操作
7.4.1 块传送方式
7.4.2 块传送函数
7.5 区域和路径
7.5.1 使用区域
7.5.2 使用路径
第8章 通用对话框
8.1 通用对话框简介
8.2 使用通用对话框
8.2.1 “打开”文件和“保存”文件对话框
8.2.2 字体选择对话框
8.2.3 “颜色”选择对话框
8.2.4 “查找”和“替换”文本对话框
8.2.5 “页面设置”对话框
8.2.6 “浏览目录”对话框
第9章 通用控件
9.1 通用控件简介
9.1.1 通用控件的分类
9.1.2 使用通用控件
9.2 使用状态栏
9.2.1 创建状态栏
9.2.2 状态栏的控制消息
9.2.3 在状态栏上显示菜单提示信息
9.3 使用工具栏
9.3.1 创建工具栏
9.3.2 工具栏的控制消息
9.3.3 工具栏的通知消息
9.4 使用richedit控件
9.4.1 创建richedit控件
9.4.2 richedit控件的控制消息
9.4.3 richedit控件的通知消息
9.5 窗口的子类化
9.5.1 什么是窗口的子类化
9.5.2 窗口子类化的实现
9.6 控件的超类化
9.6.1 什么是控件的超类化
9.6.2 控件超类化的实现
第10章 内存管理和文件操作
10.1 内存管理
10.1.1 内存管理基础
10.1.2 内存的当前状态
10.1.3 标准内存管理函数
10.1.4 堆管理函数
10.1.5 虚拟内存管理函数
10.1.6 其他内存管理函数
10.2 文件操作
10.2.1 windows的文件i/o
10.2.2 创建和读写文件
10.2.3 查找文件
10.2.4 文件属性
10.2.5 其他文件操作
10.3 驱动器和目录
10.3.1 逻辑驱动器操作
10.3.2 目录操作
10.4 内存映射文件
10.4.1 内存映射文件简介
10.4.2 使用内存映射文件
第11章 动态链接库和钩子
11.1 动态链接库
11.1.1 动态链接库的概念
11.1.2 编写动态链接库
11.1.3 使用动态链接库
11.1.4 动态链接库中的数据共享
11.1.5 在vc++中使用动态链接库
11.2 windows钩子
11.2.1 什么是windows钩子
11.2.2 远程钩子的安装和使用
11.2.3 日志记录钩子
第12章 多线程
12.1 进程和线程
12.2 多线程编程
12.2.1 一个单线程的“问题程序”
12.2.2 多线程的解决方法
12.2.3 与线程有关的函数
12.3 使用事件对象控制线程
12.3.1 事件
12.3.2 等待事件
12.3.3 进一步改进计数程序
12.4 线程间的同步
12.4.1 产生同步问题的原因
12.4.2 各种用于线程间同步的对象
第13章 过程控制
13.1 环境变量和命令行参数
13.1.1 环境变量
13.1.2 命令行参数
13.2 执行可执行文件
13.2.1 方法一:shell调用
13.2.2 方法二:创建进程
13.3 进程调试
13.3.1 获取运行中的进程句柄
13.3.2 读写进程的地址空间
13.3.3 调试api的使用
13.4 进程的隐藏
13.4.1 在windows 9x中隐藏进程
13.4.2 windows nt中的远程线程
第14章 异常处理
14.1 异常处理的用途
14.2 使用筛选器处理异常
14.2.1 注册回调函数
14.2.2 异常处理回调函数
14.3 使用seh处理异常
14.3.1 注册回调函数
14.3.2 异常处理回调函数
14.3.3 seh链和异常的传递
14.3.4 展开操作(unwinding)
第15章 注册表和ini文件
15.1 注册表和ini文件简介
15.2 ini文件的操作
15.2.1 ini文件的结构
15.2.2 管理键值
15.2.3 管理小节
15.2.4 使用不同的ini文件
15.3 对注册表的操作
15.3.1 注册表的结构
15.3.2 管理子键
15.3.3 管理键值
15.3.4 子键和键值的枚举
15.3.5 注册表应用举例
第16章 winsock接口和网络编程
16.1 windows socket接口简介
16.2 windows socket接口的使用
16.2.1 ip地址的转换
16.2.2 套接字
16.2.3 网络应用程序的一般工作流程
16.2.4 监听、发起连接和接收连接
16.2.5 数据的收发
16.2.6 一个最简单的tcp服务端程序
16.3 tcp应用程序的设计
16.3.1 通信协议和工作线程的设计
16.3.2 tcp聊天室例子——服务器端
16.3.3 tcp聊天室例子——客户端
16.3.4 以非阻塞方式工作的tcp聊天室客户端
16.3.5 其他常用函数
第17章 pe文件
17.1 pe文件的结构
17.1.1 概论
17.1.2 dos文件头和dos块
17.1.3 pe文件头(nt文件头)
17.1.4 节表和节
17.2 导入表
17.2.1 导入表简介
17.2.2 导入表的结构
17.2.3 查看pe文件导入表举例
17.3 导出表
17.3.1 导出表的结构
17.3.2 查看pe文件导出表举例
17.4.1 资源简介
17.4.2 资源的组织方式
17.4.3 查看pe文件中的资源列表举例
17.5 重定位表
17.5.1 重定位表的结构
17.5.2 查看pe文件的重定位表举例
17.6 应用实例
17.6.1 动态获取api入口地址
17.6.2 在pe文件上添加执行代码
第18章 odbc数据库编程
18.1 基础知识
18.1.1 数据库接口的发展历史
18.1.2 sql语言
18.1.3 odbc程序的流程
18.2 连接数据库
18.2.1 连接和断开数据库
18.2.2 连接字符串
18.3 数据的管理
18.3.1 执行sql语句
18.3.2 执行结果的处理
18.3.3 获取结果集中的数据
18.3.4 事务处理
18.4 数据库操作的例子
18.4.1 结果集处理模块
18.4.2 例子的源代码
附录a、b、c(见本书配套光盘)
信息来源:
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致5.5 C语言编程进阶_图文_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
5.5 C语言编程进阶
上传于|0|0|暂无简介
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩126页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢后使用快捷导航没有帐号?
查看: 37784|回复: 29
  伟大的Bill Gates 曾经失言:
  640K ought to be enough for everybody — Bill Gates 1981
  程序员们经常编写内存管理程序,往往提心吊胆。如果不想触雷,唯一的解决办法就是发现所有潜伏的地雷并且排除它们,躲是躲不了的。本文的内容比一般教科书的要深入得多,读者需细心阅读,做到真正地通晓内存管理。
  1、内存分配方式
  内存分配方式有三种:
  (1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
  (2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
  (3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。
  2、常见的内存错误及其对策
  发生内存错误是件非常麻烦的事情。编译器不能自动发现这些错误,通常是在程序运行时才能捕捉到。而这些错误大多没有明显的症状,时隐时现,增加了改错的难度。有时用户怒气冲冲地把你找来,程序却没有发生任何问题,你一走,错误又发作了。 常见的内存错误及其对策如下:
  * 内存分配未成功,却使用了它。
  编程新手常犯这种错误,因为他们没有意识到内存分配会不成功。常用解决办法是,在使用内存之前检查指针是否为NULL。如果指针p是函数的参数,那么在函数的入口处用assert(p!=NULL)进行
  检查。如果是用malloc或new来申请内存,应该用if(p==NULL) 或if(p!=NULL)进行防错处理。
  * 内存分配虽然成功,但是尚未初始化就引用它。
  犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为零,导致引用初值错误(例如数组)。内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无不可信其有。所以无论用何种方式创建数组,都别忘了赋初值,即便是赋零值也不可省略,不要嫌麻烦。
  * 内存分配成功并且已经初始化,但操作越过了内存的边界。
  例如在使用数组时经常发生下标“多1”或者“少1”的操作。特别是在for循环语句中,循环次数很容易搞错,导致数组操作越界。
  * 忘记了释放内存,造成内存泄露。
  含有这种错误的函数每被调用一次就丢失一块内存。刚开始时系统的内存充足,你看不到错误。终有一次程序突然死掉,系统出现提示:内存耗尽。
  动态内存的申请与释放必须配对,程序中malloc与free的使用次数一定要相同,否则肯定有错误(new/delete同理)。
  * 释放了内存却继续使用它。
  有三种情况:
  (1)程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。
  (2)函数的return语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。
  (3)使用free或delete释放了内存后,没有将指针设置为NULL。导致产生“野指针”。
  【规则1】用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。
  【规则2】不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
  【规则3】避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作。
  【规则4】动态内存的申请与释放必须配对,防止内存泄漏。
  【规则5】用free或delete释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。
  3、指针与数组的对比
  C /C程序中,指针和数组在不少地方可以相互替换着用,让人产生一种错觉,以为两者是等价的。
  数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。
  指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指针来操作动态内存。指针远比数组灵活,但也更危险。
  下面以字符串为例比较指针与数组的特性。
  3.1 修改内容
  示例3-1中,字符数组a的容量是6个字符,其内容为hello。a的内容可以改变,如a[0]= ‘X’。指针p指向常量字符串“world”(位于静态存储区,内容为world),常量字符串的内容是不可以被修改的。从语法上看,编译器并不觉得语句 p[0]= ‘X’有什么不妥,但是该语句企图修改常量字符串的内容而导致运行错误。char a[] = “hello”;
a[0] = ‘X’;
cout && a &&
char *p = “world”; // 注意p指向常量字符串
p[0] = ‘X’; // 编译器不能发现该错误
cout && p &&复制代码示例3.1 修改数组和指针的内容
  3.2 内容复制与比较
  不能对数组名进行直接复制与比较。示例7-3-2中,若想把数组a的内容复制给数组b,不能用语句 b = a ,否则将产生编译错误。应该用标准库函数strcpy进行复制。同理,比较b和a的内容是否相同,不能用if(b==a) 来判断,应该用标准库函数strcmp进行比较。
  语句p = a 并不能把a的内容复制指针p,而是把a的地址赋给了p。要想复制a的内容,可以先用库函数malloc为p申请一块容量为strlen(a) 1个字符的内存,再用strcpy进行字符串复制。同理,语句if(p==a) 比较的不是内容而是地址,应该用库函数strcmp来比较。// 数组…
char a[] = &hello&;
char b[10];
strcpy(b, a); // 不能用 b =
if(strcmp(b, a) == 0) // 不能用 if (b == a)

// 指针…
int len = strlen(a);
char *p = (char *)malloc(sizeof(char)*(len 1));
strcpy(p,a); // 不要用 p =
if(strcmp(p, a) == 0) // 不要用 if (p == a)
…复制代码示例3.2 数组和指针的内容复制与比较
  3.3 计算内存容量
  用运算符sizeof可以计算出数组的容量(字节数)。示例7-3-3(a)中,sizeof(a)的值是12(注意别忘了’’)。指针p指向a,但是 sizeof(p)的值却是4。这是因为sizeof(p)得到的是一个指针变量的字节数,相当于sizeof(char*),而不是p所指的内存容量。 C /C语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。
  注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。示例7-3-3(b)中,不论数组a的容量是多少,sizeof(a)始终等于sizeof(char *)。char a[] = &hello world&;
char *p =
cout&& sizeof(a) && // 12字节
cout&& sizeof(p) && // 4字节复制代码示例3.3(a) 计算数组和指针的内存容量void Func(char a[100])
{
 cout&& sizeof(a) && // 4字节而不是100字节
}复制代码示例3.3(b) 数组退化为指针
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 &&
 free(str);
}复制代码示例4.2用指向指针的指针申请动态内存
  由于“指向指针的指针”这个概念不容易理解,我们可以用函数返回值来传递动态内存。这种方法更加简单,见示例4.3。char *GetMemory3(int num)
{
 char *p = (char *)malloc(sizeof(char) * num);
 
}
void Test3(void)
{
 char *str = NULL;
 str = GetMemory3(100);
 strcpy(str, &hello&);
 cout&& str &&
 free(str);
}复制代码示例4.3 用函数返回值来传递动态内存
  用函数返回值来传递动态内存这种方法虽然好用,但是常常有人把return语句用错了。这里强调不要用return语句返回指向“栈内存”的指针,因为该内存在函数结束时自动消亡,见示例4.4。char *GetString(void)
{
 char p[] = &hello world&;
  // 编译器将提出警告
}
void Test4(void)
{
 char *str = NULL;
 str = GetString(); // str 的内容是垃圾
 cout&& str &&
}复制代码示例4.4 return语句返回指向“栈内存”的指针
  用调试器逐步跟踪Test4,发现执行str = GetString语句后str不再是NULL指针,但是str的内容不是“hello world”而是垃圾。
如果把示例4.4改写成示例4.5,会怎么样?char *GetString2(void)
{
 char *p = &hello world&;
 
}
void Test5(void)
{
 char *str = NULL;
 str = GetString2();
 cout&& str &&
}复制代码示例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” && }
};
void Test(void)
{
 A *p;
 {
  A
  p = &a; // 注意 a 的生命期
 }
 p-&Func(); // p是“野指针”
}复制代码函数Test在执行语句p-&Func()时,对象a已经消失,而p是指向a的,所以p就成了“野指针”。但奇怪的是我运行这个程序时居然没有出错,这可能与编译器有关。
  6、有了malloc/free为什么还要new/delete?
  malloc与free是C /C语言的标准库函数,new/delete是C 的运算符。它们都可用于申请动态内存和释放内存。
  对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
   因此C 语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。我们先看一看malloc/free和new/delete如何实现对象的动态内存管理,见示例6。class Obj
{
 public :
  Obj(void){ cout && “Initialization” && }
  ~Obj(void){ cout && “Destroy” && }
  void Initialize(void){ cout && “Initialization” && }
  void Destroy(void){ cout && “Destroy” && }
};
void UseMallocFree(void)
{
 Obj *a = (obj *)malloc(sizeof(obj)); // 申请动态内存
 a-&Initialize(); // 初始化
 //…
 a-&Destroy(); // 清除工作
 free(a); // 释放内存
}
void UseNewDelete(void)
{
 Obj *a = new O // 申请动态内存并且初始化
 //…
  // 清除并且释放内存
}复制代码示例6 用malloc/free和new/delete如何实现对象的动态内存管理
  类Obj的函数Initialize模拟了构造函数的功能,函数Destroy模拟了析构函数的功能。函数UseMallocFree中,由于 malloc/free不能执行构造函数与析构函数,必须调用成员函数Initialize和Destroy来完成初始化与清除工作。函数 UseNewDelete则简单得多。
  所以我们不要企图用malloc/free来完成动态对象的内存管理,应该用new/delete。由于内部数据类型的“对象”没有构造与析构的过程,对它们而言malloc/free和new/delete是等价的。
  既然new/delete的功能完全覆盖了malloc/free,为什么C 不把malloc/free淘汰出局呢?这是因为C 程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。
  如果用free释放“new创建的动态对象”,那么该对象因无法执行析构函数而可能导致程序出错。如果用delete释放“malloc申请的动态内存 ”,理论上讲程序不会出错,但是该程序的可读性很差。所以new/delete必须配对使用,malloc/free也一样。
  7、内存耗尽怎么办?
  如果在申请动态内存时找不到足够大的内存块,malloc和new将返回NULL指针,宣告内存申请失败。通常有三种方式处理“内存耗尽”问题。
  (1)判断指针是否为NULL,如果是则马上用return语句终止本函数。例如:void Func(void)
{
 A *a = new A;
 if(a == NULL)
 {
  
 }
 …
}复制代码(2)判断指针是否为NULL,如果是则马上用exit(1)终止整个程序的运行。例如:void Func(void)
{
 A *a = new A;
 if(a == NULL)
 {
  cout && “Memory Exhausted” &&
  exit(1);
 }
 …
}复制代码(3)为new和malloc设置异常处理函数。例如Visual C 可以用_set_new_hander函数为new设置用户自己定义的异常处理函数,也可以让malloc享用与new相同的异常处理函数。详细内容请参考C 使用手册。
  上述(1)(2)方式使用最普遍。如果一个函数内有多处需要申请动态内存,那么方式(1)就显得力不从心(释放内存很麻烦),应该用方式(2)来处理。
  很多人不忍心用exit(1),问:“不编写出错处理程序,让操作系统自己解决行不行?”
  不行。如果发生“内存耗尽”这样的事情,一般说来应用程序已经无药可救。如果不用exit(1) 把坏程序杀死,它可能会害死操作系统。道理如同:如果不把歹徒击毙,歹徒在老死之前会犯下更多的罪。
  有一个很重要的现象要告诉大家。对于32位以上的应用程序而言,无论怎样使用malloc与new,几乎不可能导致“内存耗尽”。我在Windows 98下用Visual C 编写了测试程序,见示例7。这个程序会无休止地运行下去,根本不会终止。因为32位操作系统支持“虚存”,内存用完了,自动用硬盘空间顶替。我只听到硬盘嘎吱嘎吱地响,Window 98已经累得对键盘、鼠标毫无反应。
  我可以得出这么一个结论:对于32位以上的应用程序,“内存耗尽”错误处理程序毫无用处。这下可把Unix和Windows程序员们乐坏了:反正错误处理程序不起作用,我就不写了,省了很多麻烦。
  我不想误导读者,必须强调:不加错误处理将导致程序的质量很差,千万不可因小失大。void main(void)
{
 float *p = NULL;
 while(TRUE)
 {
  p = new float[1000000];
  cout && “eat memory” &&
  if(p==NULL)
   exit(1);
 }
}复制代码示例7试图耗尽操作系统的内存
  8、malloc/free 的使用要点
  函数malloc的原型如下:void * malloc(size_t size);复制代码用malloc申请一块长度为length的整数类型的内存,程序如下:int *p = (int *) malloc(sizeof(int) * length);复制代码我们应当把注意力集中在两个要素上:“类型转换”和“sizeof”。
  * malloc返回值的类型是void *,所以在调用malloc时要显式地进行类型转换,将void * 转换成所需要的指针类型。
  * malloc函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。我们通常记不住int, float等数据类型的变量的确切字节数。例如int变量在16位系统下是2个字节,在32位下是4个字节;而float变量在16位系统下是4个字节,在32位下也是4个字节。最好用以下程序作一次测试:cout && sizeof(char) &&
cout && sizeof(int) &&
cout && sizeof(unsigned int) &&
cout && sizeof(long) &&
cout && sizeof(unsigned long) &&
cout && sizeof(float) &&
cout && sizeof(double) &&
cout && sizeof(void *) &&复制代码在malloc的“()”中使用sizeof运算符是良好的风格,但要当心有时我们会昏了头,写出 p = malloc(sizeof(p))这样的程序来。
  * 函数free的原型如下:void free( void * memblock );复制代码为什么free 函数不象malloc函数那样复杂呢?这是因为指针p的类型以及它所指的内存的容量事先都是知道的,语句free(p)能正确地释放内存。如果p是 NULL指针,那么free对p无论操作多少次都不会出问题。如果p不是NULL指针,那么free对p连续操作两次就会导致程序运行错误。
  9、new/delete 的使用要点
  运算符new使用起来要比函数malloc简单得多,例如:int *p1 = (int *)malloc(sizeof(int) * length);
int *p2 = new int[length];复制代码这是因为new内置了sizeof、类型转换和类型安全检查功能。对于非内部数据类型的对象而言,new在创建动态对象的同时完成了初始化工作。如果对象有多个构造函数,那么new的语句也可以有多种形式。例如class Obj
{
 public :
  Obj(void); // 无参数的构造函数
  Obj(int x); // 带一个参数的构造函数
  …
}
void Test(void)
{
 Obj *a = new O
 Obj *b = new Obj(1); // 初值为1
 …
 
 
}复制代码如果用new创建对象数组,那么只能使用对象的无参数构造函数。例如Obj *objects = new Obj[100]; // 创建100个动态对象复制代码不能写成Obj *objects = new Obj[100](1);// 创建100个动态对象的同时赋初值1复制代码在用delete释放对象数组时,留意不要丢了符号‘[]’。例如delete [] // 正确的用法
// 错误的用法复制代码后者相当于delete objects[0],漏掉了另外99个对象。
  10、一些心得体会
  我认识不少技术不错的C /C程序员,很少有人能拍拍胸脯说通晓指针与内存管理(包括我自己)。我最初学习C语言时特别怕指针,导致我开发第一个应用软件(约1万行C代码)时没有使用一个指针,全用数组来顶替指针,实在蠢笨得过分。躲避指针不是办法,后来我改写了这个软件,代码量缩小到原先的一半。
  我的经验教训是:
  (1)越是怕指针,就越要使用指针。不会正确使用指针,肯定算不上是合格的程序员。
  (2)必须养成“使用调试器逐步跟踪程序”的习惯,只有这样才能发现问题的本质。
建议做成PDF文档进行发布,比较方便,呵呵
赞成做成PDF文档进行发布
感谢楼主分享
这里做成了PDF
本帖子中包含更多资源
才可以下载或查看,没有帐号?
louzhu 你太厉害了 支持你
感谢楼主分享
感谢楼主,感谢pdf maker
也不用加上伟大吧
谢谢,楼主V5
Powered by Discuz!
& Comsenz Inc.

我要回帖

更多关于 acm题目 字符串 的文章

 

随机推荐