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


    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是清明的茗
  • 相关阅读:
    [Windows Powershell]-学习笔记(1)
    MyBatis For .NET学习-问题总结
    Zynq学习笔记(1)
    规范的位操作方法
    浮点数转换成字符串函数
    测试卡尔曼滤波器(Kalman Filter)
    关于按键扫描程序的终极讨论
    关于STM8的用户数据空间读写问题
    IPv4分析
    关于STM8空间不足的解决方法
  • 原文地址:https://www.cnblogs.com/MinPage/p/13955164.html
Copyright © 2020-2023  润新知