二维数组的动态初始化与复制
int **指针与二维数组问题
1)定义二维数组方法:
int matrix[ROWS][COLUMNS]; //定义一个二维数组,其中ROWS和COLUMNS为常数
2)加入有如下声明的子函数:
void printMatrix(int ** numbers,int rows,int columns);
3)如果直接使用如下方法调用,是错误的;
printMatrix(matrix,ROWS,COLUMNS); //直接这样调用时错误的
原因在于matrix是 int (*)[COLUMNS]类型的(即[][]内存连续分配),但是函数printMatrix需要的是int **类型的,这两者明显不匹配。
int **从类型上讲是一个指向整型指针的指针,用它来表示一个矩阵,实现代码如下:
int ** generateMatrix(int rows,int columns) { int **numbers=new int*[rows]; for(int i=0;i<rows;i++){ numbers[i]=new int[columns]; for(int j=0;j<columns;j++) numbers[i][j]=i*columns+j; } return numbers; }
把int*当做一个整体。它表示创建了一个大小为rows的数组,这个数组的每一个元素代表一个指针。内存布局如下:
这里numbers是一个指向指针的指针,能够用numbers用来表示矩阵的关键就在于使用new关键字分配的内存是连续的,这样number[i]的地址就可以根据numbers的地址计算出来,因为指针变量占据4个字节的内存区域(32位机器)。如果不使用上面的方式分配内存,numbers就真的只是一个指向指针的指针了
04)正确使用printMatrix(matrix,ROWS,COLUMNS)的测试代码:
#include <stdlib.h> #include <stdio.h> #include <iostream> //打印矩阵 void printMatrix(int ** numbers,int rows,int columns){ for(int i=0;i<rows;i++) { for(int j=0;j<columns;j++) std::cout<<numbers[i][j]<<" "; std::cout<<std::endl; } } //生成矩阵 int ** generateMatrix(int rows,int columns) { int **numbers=new int*[rows]; for(int i=0;i<rows;i++){ numbers[i]=new int[columns]; for(int j=0;j<columns;j++) numbers[i][j]=i*columns+j; } return numbers; } int main(){ int **numbers=generateMatrix(4,5); printMatrix(numbers,4,5); //释放内存 for(int i=0;i<4;i++) delete [] numbers[i]; delete numbers; return 0; }
memset()和memcpy()
memset()用法
void *memset(void *s,int c,size_t n)
作用:将已开辟内存空间$s$的首$n$个字节的值设为值$c$(给空间初始化)
C语言需要包含头文件string.h;C++需要包含cstring 或 string.h
#include <string.h> #include <stdio.h> #include <memory.h> int main(void) { char buffer[] = "Hello world\n"; printf("Buffer before memset: %s\n", buffer); memset(buffer, '*', strlen(buffer) ); printf("Buffer after memset: %s\n", buffer); return 0; }
示例
输出结果:
Buffer before memset: Hello world
Buffer after memset: ***********
memset() 函数常用于内存空间初始化。如:
char str[100];
memset(str,0,100);
memset()错误用法:
int main(void) { char *buffer = "Hello world\n"; printf("Buffer before memset: %s\n", buffer); memset(buffer, '*', strlen(buffer) ); printf("Buffer after memset: %s\n", buffer); return 0; }
报错原因:char * buffer = "Hello world\n"; 字符串"Hello world\n"存在于只读存储区(字面量),其内容不能被随意更改!!!!
memcpy()函数用法
void *memcpy(void *dest, const void *src, size_t n);
C语言需要包含头文件string.h;C++需要包含cstring 或 string.h。
用法:用来将src地址处的内容拷贝n个字节的数据至目标地址dest指向的内存中去。函数返回指向dest的指针。
示例1
作用:将s中的字符串复制到字符数组d中
#include <stdio.h> #include <string.h> int main() { char *s="Golden Global View"; char d[20]; clrscr(); memcpy(d,s,( strlen(s)+1) ); printf("%s",d); getchar(); return 0; } //输出结果:Golden Global View
示例2
作用:将s中第14个字符开始的4个连续字符复制到d中。(从0开始)
#include <string.h> int main() { char *s="Golden Global View"; char d[20]; memcpy(d,s+14,4); //从第14个字符(V)开始复制,连续复制4个字符(View)
//memcpy(d,s+14*sizeof(char),4*sizeof(char));也可 d[4]='\0'; printf("%s",d); getchar(); return 0; } //输出结果: View
示例3
作用:复制后覆盖原有部分数据;
#include <stdio.h> #include <string.h> int main(void) { char src[] = "******************************"; char dest[] = "abcdefghijlkmnopqrstuvwxyz0123as6"; printf("destination before memcpy: %s\n", dest); memcpy(dest, src, strlen(src)); printf("destination after memcpy: %s\n", dest); return 0; } //输出结果: //destination before memcpy:abcdefghijlkmnopqrstuvwxyz0123as6 //destination after memcpy: ******************************as6
注意事项
memcpy用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度;例:char a[100],b[50]; memcpy(b, a, sizeof(b));注意如用sizeof(a),会造成b的内存溢出。
另外:strcpy只能拷贝字符串,它遇到'\0'就结束拷贝;例:char a[100],b[50]; strcpy(a,b); 如用strcpy(b,a),要注意a中的字符串长度(第一个‘\0’之前)是否超过50位,如超过,则会造成b的内存溢出。会造成缓冲区溢出,轻者程序崩溃,重者系统会出现问题!!
小结
一维数组的动态分配,初始化和撤销
//动态分配10个空间 int *array=new int [10]; //初始化 memset(array,0,sizeof(array)); //或者 memset(array,0,10*sizeof(int)); //撤销 delete [] array;
二维数组(n行m列)利用new来进行动态分配、初始化及撤销
//动态分配分块连续内存及初始化 int **array; array=new int *[10]; for(int i=0;i<10;i++) { array[i]=new int [5]; memset(array[i],0,5*sizeof(int)); } //撤销 for (int i = 0; i < 10; i ++) { delete[] array[i]; array[i] = NULL;//不要忘记,释放空间后p[i]不会自动指向NULL值,还将守在原处,只是释放内存而已,仅此而已。 } delete [] array; array=NULL;
补充一个不常用的分配方式:
int (*p)[4] = new int[3][4];
解释:非动态分配,它的分配必须得有最外层 const 的支持
int x = 3, y = 4; int (*p)[y] = new int[x][y];//error,y必须是const,也就是不能动态。
所以这种方式不能达到真正的动态分配二维数组的目的,只能相当于半自动化的一个分配方式。
最后提醒:千万不要有
int *p = new int[4][2];
这样的错误写法。
参考资料:
https://blog.csdn.net/diaodi1938/article/details/101491501