二維數組的動態初始化與復制


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\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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM