二维数组的动态初始化与复制

C语言指针数组(数组每个元素都是指针)详解

C语言二维数组指针(指向二维数组的指针)详解

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
";
    printf("Buffer before memset: %s
", buffer);
    memset(buffer, '*', strlen(buffer) );
    printf("Buffer after memset: %s
", 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
";
    printf("Buffer before memset: %s
", buffer);
    memset(buffer, '*', strlen(buffer) );
    printf("Buffer after memset: %s
", buffer);
    return 0;
}

报错原因:char * buffer = "Hello world ";    字符串"Hello world "存在于只读存储区(字面量),其内容不能被随意更改!!!!

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]=''; 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
", dest);
    memcpy(dest, src, strlen(src));
    printf("destination after memcpy: %s
", 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只能拷贝字符串,它遇到''就结束拷贝;例:char a[100],b[50];  strcpy(a,b);  如用strcpy(b,a),要注意a中的字符串长度(第一个‘’之前)是否超过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

https://blog.csdn.net/longhopefor/article/details/20994919

Min是清明的茗
原文地址:https://www.cnblogs.com/MinPage/p/13955164.html