在程序开发时,我们有些时候不可能预先知道一个数组的最大储存量是多少,所以需要在程序运行时,代码自动的从堆(heap)中申请分配一段内存,堆是一个很大的内存块,用以在程序运行时分配一些小的储存空间。本文通过以下两个例子来阐述c++动态数组的动态扩容机制:
- 从给定范围内(start,end)找寻素数并储存在一个一维数组中——函数GetPrimerNumber();
- 读取文本,将所有的单词储存到一个二维数组中——函数GetWordsFromTxt();
方法说明
在标准c中,动态内存分配函数包括malloc()、calloc()、realloc()和free()。c++不是采用库函数调用的方法,而是采用更加高级的方法——被集成进c++中的动态存储分配,使用关键字new和delete。
c++通过new关键字向堆(heap)申请内存,使用完毕后,需要用delete关键字显式的告诉堆管理器回收内存。
注意:
- 任何时候申请内存都有可能失败(一般来是申请特别大的内存时),例如存储单元用完了,c++ 内存申请失败的时候会抛出bad_alloc异常,可以用try-catch来处理;
- 任何由new分配的内存块必须用delete来释放,如果忘记了使用delete,这个内存块就不能用了,这被称为内存泄漏(memory leak),泄漏到一定程度,内存就耗尽了;
- 对于二维数组或者多维数组,申请内存时是由外而内,释放内存时是由内而外,具体见代码;
- 动态数组不能作为形参传给函数,因为通过new和delete操作,主函数传递给子函数的动态数组地址与子函数实际运行结果的动态数组地址不一样,我们可以用一小段代码来测试:`
int main()
{
int *result = new int[1];
//初始化,赋值为0
result[0] = 0;
cout << "主函数动态数组地址(函数未调用前):" << result << endl;
test(result);
cout << "主函数动态数组地址(函数调用后):" << result << endl;
return 0;
}
void test(int *arr)
{
delete arr;
arr = new int[2];
arr[0] = arr[1] = 2;
cout << "子函数动态数组地址:"<<arr << endl;
}
其运行结果为:
可见,不能用动态数组作为子函数形参。
代码
说明:
- 代码中判断新单词出现的依据是:前一个字符不是字母且当前字符为字母,所以当出现“un-friendly”、"I’m"等这种中间有非字母连接的单词时,将其认为是两个单词,读者就这一点可以进行优化;
- 本代码读取的文本内容为:“For a start,leaving lockdown is a process, not an event.Even when the worst is over, cases ebb slowly. A month after Italy’s deaths peaked at about 900 a day, the toll is still over 300. With the virus still present, some social distancing is bound to stay.”
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
#define MAXLEN 30 //单词最长为30个字符
int * GetPrimerNumber(int start, int end, int *PrimerNumCounts);
char ** GetWordsFromTxt(string file_name, int *word_counts);
int main()
{
int start, end;//范围 (start,end)
int WordCounts = 0;
int PrimerNumCounts = 0;
int *t = &PrimerNumCounts;
int *p = &WordCounts;
string filename = "test.txt";
//输入起点,终点
cout << "请输入起点(大于等于2):";
cin >> start;
cout << "请输入终点:";
cin >> end;
//定义二维数组并赋值,获取单词总数
char **allWords = GetWordsFromTxt