数据抽象和类II
中山大学计算机学院
主讲人:潘茂林 中山大学MOOC课程组
C/C++
程序内存布局与对象(变量)存放位置
正文
• 函数实现,库实现,字符串等资源。不可改
静态变量(对象)
• 编译阶段初始化数据
• 用零初始化
栈(Stack)
• 函数参数,自动变量(对象)
堆(Heap)
• 动态变量(对象),由 stdlib.h 管理
char *s1 = "Literal"; // 文字在代码区,仅分配了字符指针
// s1[0] = 'I'; //Segmentation fault
char s2[] = "Initial Literal"; // 分配数组空间
Point *po = &((Point){2,3}); // 分配结构空间且指针
C
语言动态对象(变量)管理
堆(Heap)
• 共享的对象(变量)空间
• 由 stdlib 库管理
正确使用堆空间
• 必须 #include <stdlib.h>
• 申请空间,void * malloc(size_t)
• 释放空间,void free(void *)
• 申请的空间必须释放,否则就是内存泄漏
• Free 后再使用指针或释放,行为不可预测
• 如何申请、释放对象或一维数组?
• 如何申请、释放二维数组?
#include<stdio.h>
#include<stdlib.h>
typedef struct { int x; int y; } Point;
int main() {
// 分配变量或一维可变数组
Point *p1 = malloc(sizeof(Point) * 10);
// 分配二维数组(n,m是常数)
Point (*p2)[2][3] = malloc(sizeof(Point) * 6);
// 分配数组的数组
int n = 2, m = 3;
Point **p3 = malloc(sizeof(Point *) * n);
for (size_t i = 0; i < n; i++)
{
p3[i] = malloc(sizeof(Point) * m);
}
// do somesthing
free(p1);
free(p2);
// 必须先释放行数组
for (size_t i = 0; i < n; i++)
{
free(p3[i]);
}
free(p3);
return 0;
}
C++也是这样用的吗?
C++
用
malloc
分配对象数组(
超纲
)
程序要点
• #include<cstdlib>
• if 语句判断空间是否分配
• 初始化对象
• new(void *) 构造函数
• 处理构造异常
• 调用对象析构
• 对象.~析构函数
• 最后释放空间
#include <iostream>
#include <cstdlib>
#include <string>
int main() {
// 为 4 个 string 的数组分配足够空间
if(auto p = (std::string*)std::malloc(4 * sizeof(std::string))) {
int i = 0;
try {
for(; i != 4; ++i) // 填充数组
new(p + i) std::string(5, 'a' + i);
for(int j = 0; j != 4; ++j) // 打印出来
std::cout << "p[" << j << "] == " << p[j] << std::endl;
}
catch(...) {}
for(; i != 0; --i) // 清理
p[i - 1].~basic_string();
std::free(p);
}
}
C++
新关键字:
new
和
delete
运算符
新关键字优点:
• new 类型 初始化
• 分配空间
• 每个对象调用构造器
• 有错误抛出异常
• delete []p
• 为数组每个对象析构
• 释放空间
/*new-delete-strings-demo*/
#include <iostream>
#include <string>
int main() {
// 为 n 个 string 的数组分配空间
int n = 4;
std::string *p = new std::string[n] {
std::string(5, 'a'),
std::string(5, 'b'),
std::string(5, 'c'),
std::string(5, 'd')
};
for(int i=0; i<n; i++) {
std::cout << p[i] << std::endl;
}
delete []p;
}
Cppreference:new 表达式