第三部分:动态存储分配
用指针访问数组元素
数组是一组连续存储的同类型数据,可以通过指针的算术运算,使指针依次指向数组的各个元素,进而可以遍历数组。使用指针来访问数组元素时,需要将数组的首地址赋值给指针变量,形式为: int *p,a[10];p=a(或者p=&a[0])。
经过上述定义及赋值后*pa就是a[0],*(pa+1)就是a[1],... ,*(pa+i)就是a[i]。a[i], *(pa+i), *(a+i), pa[i]都是等效的。
指针数组
顾名思义,数组元素是指针的数组就叫做指针数组。我们可以用二维数组来存放矩阵,也可以用一维指针数组来存放矩阵,见下面案例。
以指针作为函数参数
为什么需要用指针做参数?
- 需要数据双向传递时(引用也可以达到此效果)
- 用指针作为函数的参数,可以使被调函数通过形参指针存取主调函数中实参指针指向的数据,实现数据的双向传递
- 需要传递一组数据,只传首地址运行效率比较高
- 实参是数组名时形参可以是指针,数组名作为函数参数时会退化为一个指针
动态分配与释放内存
语法格式:new 类型名T (初始化列表)。其功能为:在程序执行期间,申请用于存放T类型对象的内存空间,并依初值列表赋以初值。结果为:成功:T类型的指针,指向新分配的内存;失败:抛出异常。释放内存:语法格式为 delete 指针p,功能为:释放指针P所指向的内存。
案例:
#include <iostream> using namespace std; class Point { public: Point() : x(0), y(0) { cout << "Default Constructor called." << endl; } Point(int x, int y) : x(x), y(y) { cout << "Constructor called." << endl; } ~Point() { cout << "Destructor called." << endl; } int getX() const { return x; } int getY() const { return y; } void move(int newX, int newY) { x = newX; y = newY; } private: int x, y; }; int main() { cout << "Step one: " << endl; Point *ptr1 = new Point; //调用默认构造函数 cout << "ptr1: "; cout << ptr1->getX() << "," << ptr1->getY() << endl; delete ptr1; //删除对象,自动调用析构函数,释放动态分配的内存空间,不是删除ptr1 cout << "Step two: " << endl; ptr1 = new Point(1, 2);//ptr1存放了新申请的内存空间地址 cout << "ptr1: "; cout << ptr1->getX() << "," << ptr1->getY() << endl; delete ptr1; //getchar(); return 0; }
申请和释放动态数组:分配语法:new 类型T [数组长度];释放语法:delete[] 数组名p。数组长度可以是任何整数类型的表达式,在运行时计算;释放内存时,不要忘记delete后的方括号[],如果没有这对方括号,那么在释放空间时只会释放动态数组的首地址对应的内存空间。
案例:
#include <iostream> using namespace std; class Point { public: Point() : x(0), y(0) { cout << "Default Constructor called." << endl; } Point(int x, int y) : x(x), y(y) { cout << "Constructor called." << endl; } ~Point() { cout << "Destructor called." << endl; } int getX() const { return x; } int getY() const { return y; } void move(int newX, int newY) { x = newX; y = newY; } private: int x, y; }; int main() { Point *ptr = new Point[2]; //创建对象数组 ptr[0].move(5, 10); //通过指针访问数组元素的成员 ptr[1].move(15, 20); //通过指针访问数组元素的成员 cout << "ptr[0]: "; cout << ptr->getX() << "," << ptr->getY() << endl; cout << "ptr[1]: "; cout << (ptr + 1)->getX()<<"," << (ptr+1)->getY() << endl;//通过指针访问对象成员名 cout << "Deleting..." << endl; delete[] ptr; //删除整个对象数组 return 0; }
动态申请多维数组:new 类型名T[第一维长度][第二维长度]…
案例:
#include<iostream> using namespace std; int main() { int(*cp)[9][8] = new int[7][9][8]; for (int i = 0; i < 7; i++) { for (int j = 0; j < 9; j++) { for (int k = 0; k < 8; k++) { //*(*(*(cp + i) + j) + k) = i * 100 + j * 10 + k; cp[i][j][k] = i * 100 + j * 10 + k; } } } for (int i = 0; i < 7; i++) { for (int j = 0; j < 9; j++) { for (int k = 0; k < 8; k++) { cout << cp[i][j][k] << ' '; } cout << endl; } cout << endl; } delete[]cp; system("pause"); return 0; }
将动态数组封装成类:更加简洁,便于管理;可以在访问数组元素前检查下标是否越界。
案例:
#include <iostream> #include<cassert> using namespace std; class Point { public: Point() : x(0), y(0) { cout << "Default Constructor called." << endl; } Point(int x, int y) : x(x), y(y) { cout << "Constructor called." << endl; } ~Point() { cout << "Destructor called." << endl; } int getX() const { return x; } int getY() const { return y; } void move(int newX, int newY) { x = newX; y = newY; } private: int x, y; }; class ArrayofPoints//定义一个动态数组类 { public: ArrayofPoints(int size) :size(size)//初始化 { points = new Point[size];//动态分配存储空间 } ~ArrayofPoints()//析构函数 { cout << "Deleting..." << endl; delete[]points;//释放存储空间 } Point& element(int index)//返回数组中类对象的引用,这样可以对对象进行操作 { assert(index >= 0 && index < size);//检查数组下标是否越界 return points[index]; } private: Point *points; int size; }; int main() { int count; cout << "Please enter the count of points:"; cin >> count; ArrayofPoints points(count); for (int i = 0; i < count; i++) { points.element(i).move(i, i+5); } for (int i = 0; i < count; i++) { cout << "points[" << i << "]:" << "(" << points.element(i).getX() << ","; cout<< points.element(i).getY()<<")" << endl; } return 0; }
运行结果:
智能指针:
- 显式管理内存在性能上有优势,但容易出错。
- C++11提供智能指针的数据类型,对垃圾回收技术提供了一些支持,实现一定程度的内存管理
- unique_ptr :不允许多个指针共享资源,可以用标准库中的move函数转移指针
- shared_ptr :多个指针共享资源
- weak_ptr :可复制shared_ptr,但其构造或者释放对资源不产生影响