将2D数组错误定位为参数会导致内存转储

时间:2013-06-13 03:58:28

标签: c++ arrays pointers

这是我的C ++程序,它接受一个2D数组a[m][n]。如果元素a[i][j]为零,则将所有ith行和jth列元素设置为零。

这是代码示例:

#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

class SetZero{
public:
    static void setZero(int **, int , int);
};

void SetZero::setZero(int ** a, int m, int n){
    int i, j, k;
    int ** b = new int *[m]; //flags to identify whether set to zero or not.

    for(i = 0; i < m; i++){
        b[i] = new int[n];
        for(j = 0; j < n; j++)
            b[i][j] = 1;
    }

    for(i = 0; i < m; i++)
        for(j = 0; j < n; j++)
            if(a[i][j] == 0 && b[i][j]){//DUMP here. If I change it to (a+i)[j], then works.
                for (k = 0; k < n; k++){
                    a[i][k] = 0;//but there is NO dump here. Weird!
                    b[i][k] = 0;
                }
                for(k = 0; k < m; k++){
                    a[k][j] = 0;
                    b[k][j] = 0;
                }
                j = n;//break. next row loop.
            }

    for(int i = 0; i < m; i++)
        delete[] b[i];
    delete[] b;
}

int main(){
    int a[4][5];

    srand(time(NULL));
    for(int i = 0; i < 4; i++){//create an 2D array
        for(int j = 0; j < 5; j++){
            a[i][j] = rand() % 100;
            cout << a[i][j] << " ";
        }
        cout << endl;
    }

    SetZero::setZero((int **)a, 4, 5);//type cast.

    cout << endl;
    for(int i = 0; i < 4; i++){//print result
        for(int j = 0; j < 5; j++)
            cout << a[i][j] << " ";
        cout << endl;
    }

    return 0;
}

环境:WIN8 Visual Studio 2012。

修改 程序可以编译但无法正常执行。它会在达到if(a[i][j] == 0 && b[i][j]){

时停止

错误消息是:

  

CCLC.exe中0x012875DD处的未处理异常:0xC0000005:Access   违规读取位置0x0000004B。

2 个答案:

答案 0 :(得分:2)

SetZero::setZero((int **)a, 4, 5)

a不是一个指针数组,它只是一个二维数组。

注意访问冲突是如何读取地址0x0000004B的?这是75,一个0到99之间的数字:)因为你正在处理一个二维数组(它只是一个一维数组,有一个简洁的访问方式)作为一个数组数组,它​​采取你的一个值array(75)是子数组的地址,然后尝试读取地址为75(或0x0000004B)的不存在的数组

我建议你'压扁'你的阵列并将它们作为一维数组使用,我觉得这个数组更简单:

void SetZero::setZero(int * a, int m, int n){
int i, j, k;
int * b = new int [m*n]; //flags to identify whether set to zero or not.

for(i = 0; i < m; i++){
    b[i] = new int[n];
    for(j = 0; j < n; j++)
        b[i*n+j] = 1;
}

for(i = 0; i < m; i++)
    for(j = 0; j < n; j++)
        if(a[i*n+j] == 0 && b[i*n+j]){//DUMP here. If I change it to (a+i)[j], then works.
            for (k = 0; k < n; k++){
                a[i*n+k] = 0;//but there is NO dump here. Weird!
                b[i*n+k] = 0;
            }
            for(k = 0; k < m; k++){
                a[k*n+j] = 0;
                b[k*n+j] = 0;
            }
            j = n;//break. next row loop.
        }


delete[] b;
}

int main(){
int a[4*5];

srand(time(NULL));
for(int i = 0; i < 4; i++){//create an 2D array
    for(int j = 0; j < 5; j++){
        a[i*5+j] = rand() % 100;
        cout << a[i*5+j] << " ";
    }
    cout << endl;
}

SetZero::setZero(a, 4, 5);//type cast.

cout << endl;
for(int i = 0; i < 4; i++){//print result
    for(int j = 0; j < 5; j++)
        cout << a[i*5+j] << " ";
    cout << endl;
}

return 0;
}

答案 1 :(得分:1)

关于SetZero()的一个建议。有一个名为memset()的函数,它允许您在给定起始指针和范围的情况下将所有字节设置为特定值。此功能可以使您的SetZero()功能更清晰:


void * memset ( void * ptr, int value, size_t num );

填充内存块。将num指向的内存块的第一个ptr字节设置为指定的value(解释为unsigned char)。

参数

  • ptr:指向要填充的内存块的指针。
  • value:要设置的值。该值作为int传递,但该函数使用此值的unsigned char转换填充内存块。
  • num:要设置为该值的字节数,size_t是无符号整数类型。

例如,您的程序中的以下代码块:

 for (k = 0; k < n; k++){
   a[i][k] = 0;//but there is NO dump here. Weird!
   b[i][k] = 0;
 }

可以通过memset以更清洁的方式实现:

 memset(a[i], 0, n * sizeof(int));
 memset(b[i], 0, n * sizeof(int));