一些 C++ 相关的概念和操作

本文主要记录了一些常用的 C++ 相关的概念和操作。


string 与 char* 互转

1
2
3
4
5
6
7
// string to char*
string name = "name";
char *str = (char*)name.data();

// char* to string
char *name = "name";
string str = string(name);

释放 std::vector 所占用的内存

在容器 vector 中,其内存占用的空间是只增不减的,比如说首先分配了 10,000 个字节,然后 erase 掉后面 9999个,则虽然有效元素只有一个,但是内存占用仍为 10,000 个。所有内存空间在 vector 析构时回收。
一般,我们都会通过 vector 中成员函数 clear 进行一些清除操作,但它清除的是所有的元素,使 vector 的大小减少至 0,却不能减小 vector 占用的内存。要避免 vector 持有它不再需要的内存,这就需要一种方法来使得它从曾经的容量减少至它现在需要的容量,这样减少容量的方法被称为 “收缩到合适(shrink to fit)”。

使用以下代码可以实现此功能:

1
2
3
4
vector<T>().swap(X)  // X 的类型为 std::vector<T>;
//其相当于
std::vector<T> temp(X);
temp.swap(X);

其背后原理为:vector() 使用 vector 的默认构造函数建立临时 vector 对象,再在该临时对象上调用 swap 成员,swap 调用之后对象 X 占用的空间就等于一个默认构造的对象的大小,临时对象就具有原来对象 X 的大小,而该临时对象随即就会被析构,从而其占用的空间也被释放。

参考


二维数组和双重指针在内存中的差别

首先,下例是不可行的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#define ROW 2
#define COL 3

void myputs(char **pos);

int main() {
char **p;
char a[ROW][COL]={"abc", "def"};

p = a;
myputs(p);
return 0;
}

void myputs(char **p) {
int i, j;
for (i = 0; i < ROW; i++) {
for (j = 0; j < COL; j++)
printf("%c ", p[i][j]); // 试图用双重指针的方式访问二维数组,不可行
printf("\n");
}
}

myputs(char **p) 接受双重指针作为参数,main() 函数将二维数组的头指针赋给双重指针,并作为 myputs(char **p) 的参数传入,再使用 p[i][j] 的方式访问某个元素。这是不行的,而这与两者的内存分布有关。


二维数组的内存分布

定义了二维数组后,就会在内存中分配一块逻辑上连续的内存块。char c[10][10],系统就会分配一块 100 字节的连续内存。也就是说这样的二维数组跟一维数组 char c[100] 具有相似的内存分布。
二维数组的内存分布如下:
二维数组的内存分布

双重指针的内存分布

双重指针的内存分配一般采取动态方式
双重指针的内存分布

可以看出,当将二维数组的头指针赋值给双重指针后,再使用 p[i][j] 的方式访问里面的元素,就会出现错误。这是因为,二维数组的内存是以连续的方式分配的,但是在访问时,却使用了双重指针的方式进行访问,这就会导致段错误。


总结

char **pchar p[2][3] 之间不能相互传递参数,因为它们具体的内存分布不一样,这样在运行时就会出现段错误。
此外还需注意的一点:
二维数组中的 a[i][j] 和双重指针中的 a[i][j] 的意思是不一样的。
二维数组 int a[10][10] 中,a[i][j] 指的是第 i 行第 j 列数元素。
双重指针中 int **a 中, a[i][j] 指的是第 i 个存放 int * 指针所指向地址中的第 j 个元素。也就是 *(*(a+i)+j)

原文


文章作者: taosean
文章链接: https://taosean.github.io/2019/06/26/Cxx-Related/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 taosean's 学习之旅