林锐C/C++高质量编程指南之二
2021-02-14 22:17
标签:malloc 内存泄漏 bsp 缺省 ons func 常量 列表 语法 只是记了一部分我认为比较难理解的,或常用的,部分掌握的就没有写。 【规则 7-2-1】用 malloc 或 new 申请内存之后,应该立即检查指针值是否为 NULL。 防止使用指针值为 NULL 的内存。 【规则 7-2-2】不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右 值使用。 【规则 7-2-3】避免数组或指针的下标越界,特别要当心发生“多 1”或者“少 1” 操作。 【规则 7-2-4】动态内存的申请与释放必须配对,防止内存泄漏。 【规则 7-2-5】用 free 或 delete 释放了内存之后,立即将指针设置为 NULL,防止产 生“野指针” 以字符串为例比较指针与数组的特性。 示例 7-3-1 中,字符数组 a 的容量是 6 个字符,其内容为 hello\0。a 的内容可以改变, 如 a[0]= ‘X’。 指针 p 指向常量字符串“world”(位于静态存储区,内容为 world\0),常 量字符串的内容是不可以被修改的。 从语法上看,编译器并不觉得语句 p[0]= ‘X’有什么 不妥,但是该语句企图修改常量字符串的内容而导致运行错误 内容复制与比较 计算内存容量: 7.4指针参数是如何传递内存的 看下面的几个例子, 好多笔试题遇见过这几个例子 例一: 例二: 例三: 例四: 7.6:动态分配的内存会自动释放吗? 我们发现指针有一些“似是而非”的特征: (1)指针消亡了,并不表示它所指的内存会被自动释放。 (2)内存被释放了,并不表示指针会消亡或者成了 NULL 指针。 7.7野指针 “野指针”不是 NULL 指针,是指向“垃圾”内存的指针 造成野指针出现的原因: (1)指针变量没有被初始化。例如:char *p; 这个就是野指针,应该修改为char *p = NULL; (2)指针 p 被 free 或者 delete 之后,没有置为 NULL 7.11new和delete的使用要点: 如果 C++程序要调用已经被编译后的 C 函数 假设某个 C 函数的声明如下: void foo(int x, int y); 该函数被 C 编译器编译后在库中的名字为_foo,而 C++编译器则会产生像_foo_int_int 之类的名字用来支持函数重载和类型安全连接。 由于编译后的名字不同,C++程序不能 直接调用 C 函数。 C++提供了一个 C 连接交换指定符号 extern“C”来解决这个问题。 这就告诉 C++编译译器,函数 foo 是个 C 连接,应该到库中找名字_foo 而不是找 _foo_int_int。 C++编译器开发商已经对 C 标准库的头文件作了 extern“C”处理,所以我 们可以用#include 直接引用这些头文件 注意并不是两个函数的名字相同就能构成重载。全局函数和类的成员函数同名不算 重载,因为函数的作用域不同 调用时要加上作用域运算符 构造函数的列表初始化: 如果类存在继承关系,派生类必须在其初始化表里调用基类的构造函数。 拷贝构造函数和赋值函数,当涉及到默认的含有内存操作时,要注意。 。以类 String 的两个对象 a,b 为例,假设 a.m_data 的内容为“hello”, b.m_data 的内容为“world”。 现将 a 赋给 b,缺省赋值函数的“位拷贝”意味着执行 b.m_data = a.m_data。 这将造成三个错误: 一是 b.m_data 原有的内存没被释放,造成内存泄露; 二是 b.m_data 和 a.m_data 指向同一块内存,a 或 b 任何一方变动都会影响另一方; 三是 在对象被析构时,m_data 被释放了两次。 string类的成员函数实现: 拷贝构造和赋值函数 林锐C/C++高质量编程指南之二 标签:malloc 内存泄漏 bsp 缺省 ons func 常量 列表 语法 原文地址:https://www.cnblogs.com/xiaokang01/p/12716736.html林锐C/C++高质量编程指南之二
第七章内存管理
char a[] = "hello";
a[0] = ‘X‘;
cout endl;
char *p = "world"; // 注意 p 指向常量字符串
p[0] = ‘X‘; // 编译器不能发现该错误
cout
char a[] = "hello world";
char *p = a;
coutsizeof(a) // 12 字节
coutsizeof(p) // 4 字节
void Func(char a[100])
{
cout}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");将使程序崩溃。 void GetMemory(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)内存泄漏 (没有加free函数)
char *GetMemory(void)
{
char p[] = "hello world";
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
printf(str);
}
请问运行 Test 函数会有什么样的结果?
答:可能是乱码。
因为 GetMemory 返回的是指向“栈内存” 的指针,
该指针的地址不是 NULL,但其原 现的内容已经被清除,新内容不可知
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)语句不起作用。
void GetMemory(char *p)
{
p = (char *)malloc(100); // 动态内存会自动释放吗
}
int *p1 = (int *)malloc(sizeof(int) * length);
int *p2 = new int[length];
delete p2;
如果用 new 创建对象数组,那么只能使用对象的无参数构造函数。
Obj *objects = new Obj[100]; // 创建 100 个动态对象
在用 delete 释放对象数组时,留意不要丢了符号‘[]’。例如
delete []objects; // 正确的用法
delete objects; // 错误的用法
后者相当于 delete objects[0],漏掉了另外 99 个对象。
第八章:C++的高级特性
extern “C”
{
void foo(int x, int y);
… // 其它函数
}
或者:extern “C”
{
#include “myheader.h”
… // 其它 C 头文件
}第九章:类的构造函数,析构函数,赋值函数
class String
{
public:
String(const char *str = NULL); // 普通构造函数
String(const String &other); // 拷贝构造函数
~ String(void); // 析构函数
String &operator =(const String &other); // 赋值函数
private:
char *m_data; // 用于保存字符串
};
// String 的普通构造函数
String::String(const char *str)
{
if (str == NULL)
{
m_data = new char[1];
*m_data = ‘\0’;
}
else
{
int length = strlen(str);
m_data = new char[length + 1];
strcpy(m_data, str);
}
}
// String 的析构函数 String::~String(void)
{
delete[] m_data; // 由于 m_data 是内部数据类型,也可以写成 delete m_data;
}
// 拷贝构造函数
String::String(const String &other)
{
// 允许操作 other 的私有成员 m_data
int length = strlen(other.m_data);
m_data = new char[length + 1];
strcpy(m_data, other.m_data);
}
// 赋值函数
String &String::operate =(const String &other)
{
// (1) 检查自赋值
if(this == &other)
return *this;
// (2) 释放原有的内存资源
delete []m_data;
// (3)分配新的内存资源,并复制内容
int length = strlen(other.m_data);
m_data = new char[length + 1];
strcpy(m_data, other.m_data);
// (4)返回本对象的引用
return *this;
}
课后题及答案