Jerry's Blog

Recording what I learned everyday

View on GitHub


2 January 2021

cpp -- Pointers and Dynamic Memory Management(2)

by Jerry Zhang

Using const with Pointers

A constant pointer points to a constant memory location, but the actual value in the memory location can be changed.

常量指针指向一个不变的内存地址,但这个地址的值可以改变。

double radius = 5;
double* const p = &radius;

如果在指针类型关键字(比如double*)的前面加const,就代表数据也是常量,不可修改。

const double* const pValue = &radius;

Arrays and Pointers

A C++ array name is actually a constant pointer to the first element in the array.

数组的变量名实际上是它的起始地址,数组本质上就是一个指针。

比如:

int list[6] = {11, 12, 13, 14, 15, 16};

访问它的每个值, 也可以写成list,(list + 1), *(list + 2), *(list + 3), *(list + 4). 不要忘了加括号。

数组和指针的区别是,数组的地址不能改,比如以下代码是错误的:

int list1[10], list2[10];
list1 = list2; // Wrong

数组实际上是一个常量指针。

Passing Pointer Arguments in a Function Call

A C++ function may have pointer parameters.

前面学了一个函数的参数可以传值,可以传引用。传值是指把变量的值复制一份传给函数,传引用是指给这个变量起个别名传给函数,其实指向的同一个地址。

一个函数还可以传指针。比如:

void f(int* p1, int* &p2)

假如我们现在有两个指针q1, q2,传到函数中f(q1, q2)。此时,q1是值传递,q2是引用传递。

Passing Pointer Arguments in a Function Call

Useful Array Functions

The min_element, max_element, sort, random_shuffle, and find functions can be used for arrays.

要引入algorithm包:#include <algorithm>

#include <iostream>
#include <algorithm>
using namespace std;

void printArray(int* const list, int size)
{
  for (int i = 0; i < size; i++)
    cout << list[i] << " ";
  cout << endl;
}

int main()
{
  int list[] = {4, 2, 3, 6, 5, 1};
  printArray(list, 6);

  int* min = min_element(list, list + 6);
  int* max = max_element(list, list + 6);
  cout << "The min value is " << *min << " at index " 
    << (min - list) << endl;
  cout << "The max value is " << *max << " at index " 
    << (max - list) << endl;

  random_shuffle(list, list + 6);
  printArray(list, 6);

  sort(list, list + 6);
  printArray(list, 6);

  int key = 4;
  int* p = find(list, list + 6, key);
  if (p != list + 6)
    cout << "The value " << *p << " is found at position " 
         << (p - list) << endl;
  else
    cout << "The value " << *p << " is not found" << endl;

  return 0;
}

这些函数返回的指针,用星号就能拿到它们的值,比如*min;用这个指针减去这个数组的头指针,就能得到它的index,比如min - list;

另外,这些函数的参数一般是这个数组的起始和结束点的指针,比如,这个数组叫list,那就传进去list和list+6。

Dynamic Persistent Memory Allocation

动态的内存分配,用new关键字

The new operator can be used to create persistent memory at runtime for primitive type values, arrays, and objects.

动态数组的长度可以在runtime时确定:

int* list = new int[size];

new出来的数组会存在heap中,当函数退出时,它不会被销毁,需要用delete手动销毁:

delete [] list;

删除后的指针叫dangling pointers,不要使用*在这些指针上。另外,delete只能用在new出来的指针上。

Memory leak

int* p = new int;
*p = 45;
p = new int;

下图解释了上面三行代码发生了什么:

Unreferenced memory space causes memory leak.

因此,任何时候,都要记得把new出来的东西delete掉。

Creating and Accessing Dynamic Objects

To create an object dynamically, invoke the constructor for the object using the syntax new ClassName(arguments).

ClassName* pObject = new ClassName(); or
ClassName* pObject = new ClassName;

ClassName* pObject = new ClassName(arguments);

例如:

string* p = new string();
string* p = new string("abcdefg");

以前声明对象时,语法是这样的:Circle circle1;或者Circle circle2(5.0);

现在new出来的对象,是一个该类型的指针。所以如果想用它的方法,必须先用星号找到它的内容,再用“点”去调用方法:

string* p = new string("abcdefg");
cout << "The first three characters in the string are "
<< (*p).substr(0, 3) << endl;
cout << "The length of the string is " << (*p).length() << endl;

或者简化的写法是用箭头

cout << "The first three characters in the string are "
<< p->substr(0, 3) << endl;
cout << "The length of the string is " << p->length() << endl;

该对象在程序结束时被删除,也可手动删除。

delete p;

The this Pointer

The this pointer points to the calling object itself.

跟Java用法差不多,但c++的this是个指针,所以要用箭头调用它的实例变量。

this->radius = radius;

Destructors

Every class has a destructor, which is called automatically when an object is deleted.

Constructor前面加一个波浪号,就是destructor。比如,在.h文件中,~Circle();就声明了destructor。

.cpp实现:

Circle::~Circle()
{
    numberOfObjects--;
}

You should customize a destructor if the class contains a pointer data field that points to dynamically created memory. Otherwise, the program may have memory leak.

Copy Constructors

For example

Circle(const Circle&)

默认的是shallow copy,所以要自己写一个deep copy,同时别忘了destructor中把所有的指针销毁。

tags: cpp