由于作leetcode的一道算法题https://leetcode-cn.com/problems/regular-expression-matching/,须要用到二维数组,结果本身在理解和使用上有很大误解,因此单独拿出来,从内存等各方面透彻的梳理一遍。算法
char * a = (char*)malloc(8 * sizeof(char)); memset(a, 0, 8); for (int i = 0; i < 8; i++) { *(a + i) = 'a' + i; } for (int i = 0; i < 8; i++) { cout << *(a+i); } for (int i = 0; i < 8; i++) { cout << a[i]; } free(a);
输出内容abcdefghabcdefghexpress
这样申请与char a[8]是同样的,无论是底层实现仍是使用,都是同样的,这就是一个8个字节长度的数组。咱们看内存,也是一段连续的数据。数组
释放内存的时候,系统能够根据内存管理把这连续的8个字节的空间回收。函数
char a[8][4] = { 0 }; for (int i = 0; i < 8; i++) { for (int j = 0; j < 4; j++) { a[i][j] = 'a' + i; } } for (int i = 0; i < 8; i++) { for (int j = 0; j < 4; j++) { cout << a[i][j]; } }
输出结果 aaaabbbbccccddddeeeeffffgggghhhhspa
咱们看一下内存.net
是一段连续的内存,数组a[n][m],按照m跳度,前m个是第一个n的序列,而后是第二个n的m个序列,实际上这是一个一维数组。翻译
char** a = (char**)malloc(8 * sizeof(char*)); for (int i = 0; i < 8; i++) { *(a + i) = (char*)malloc(4 * sizeof(char)); } for (int i = 0; i < 8; i++) { for (int j = 0; j < 4; j++) { a[i][j] = 'a' + i; } } for (int i = 0; i < 8; i++) { for (int j = 0; j < 4; j++) { cout << a[i][j]; } }
a是一个数组,也就是a指向了申请的一块空间,空间是8个char*大小。而后为a的每个数组元素,又指向了一块空间,空间是4个char大小。内存空间如图所示,a指向了一块空间,有8个元素,每一个元素的空间用来保存了一个char*的数据,也就是char的指针,a算是一个指向指针的指针。a是一个指针,指向了一块数据,这块数据保存的是一个指针,指向了一块数据,这块数据保存的是一个4字节的char。指针
咱们看一下实际的内存地址code
这是char*数组a的数据,8个char*的空间,标蓝的是第一个a+0保存的数据,是一个指针地址,由于是32位的,因此是4个字节,翻译过来就是0X00557600blog
咱们看一下a的第一块数据指向的内容,是一块数据,保存了aaaa,四个a。
这就是二维数组的实质。一维数组a指向了一块数据,保存的是字符,二维数组指向了一块数据,保存的至关因而一个一维数组指针的列表,每一个二维数组元素至关于一个一维数组。以此类推,三维数组就是保存了一个二维数组指针的列表。
它是如何访问数据的呢,与一维数组同样,先经过a+i访问到a的元素指针,而后经过*(a+i)访问到数据,这个数据又是个数组,经过*(a+i)+j访问到元素指针,再经过*(*(a+i)+j)访问到数据,最后提醒,别忘了释放空间。
for (int i = 0; i < 8; i++) { for (int j = 0; j < 4; j++) { cout << *(*(a + i) + j); } } for (int i = 0; i < 8; i++) { free(*(a + i)); } free(a);
咱们看到,若是经过char a[8][4]申请一个二维数组,实际上空间是连续的,咱们能不能模拟呢,这样整块申请内存,效率更高。代码以下
char* a = (char*)malloc(8 * 4 * sizeof(char)); for (int i = 0; i < 8; i++) { for (int j = 0; j < 4; j++) { *(a + i * 4 + j) = 'a' + i; } } for (int i = 0; i < 8; i++) { for (int j = 0; j < 4; j++) { cout << *(a + i * 4 + j); } } free(a);
申请了一个一维数组,大小是a[n][m]中n*m个数组元素个数。访问呢,就模仿二维数组的访问,m个元素是一组。内存以下
这里有一个小小的一问,char a[8][4]这种能够经过 a[1][2]访问,可是这种方式不行。char[8][4]系统知道是一个二维数组,保留了它的信息,知道如何跳,而char* a = (char*)malloc(8 * 4 * sizeof(char));系统认为是一维数组,按照二维的那种方式跳,就会运行错误。
除了malloc,也能够用new,更方便一些
char * a = new char[8]();
减小了初始化的步骤,这里就是建立一块空间,大小是8,单位是char,调用()初始化。这里()的意思就是调用默认构造函数等于new char[8]{}
上面的方法空间在一块儿了,可是没法用二维数组的方式访问 ,很别扭,那么有没有动态二维数组呢,上面插曲的new为咱们提供了方法。
auto a = new char[8][4](); for (int i = 0; i < 8; i++) { for (int j = 0; j < 4; j++) { a[i][j] = 'a' + i; } } for (int i = 0; i < 8; i++) { for (int j = 0; j < 4; j++) { cout << a[i][j]; } } delete[](a);
感谢评论参考 https://blog.csdn.net/u012027907/article/details/16370625
这种方法的实质是什么呢?实际上就是第二种方法,只不过告诉了系统,这是一个二维数组。那么二维数组的指针怎么定义呢?能够用以下代替
char(* a)[4] = (char(*)[4])malloc(8 * 4 * sizeof(char)); for (int i = 0; i < 8; i++) { for (int j = 0; j < 4; j++) { a[i][j] = 'a' + i; } } for (int i = 0; i < 8; i++) { for (int j = 0; j < 4; j++) { cout << a[i][j]; } } free(a);