Position 2D array bug as parameter causes memory dumps

1

This is my program in C++, which accepts an 2D array a[m][n]. If an element a[i][j] is zero, then set all the ith row and jth column elements to zero.

This is code sample:

#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;
}

Environment: WIN8 Visual Studio 2012.

Edit: The program can compile but cannot execute normally. It will stop when it reaches if(a[i][j] == 0 && b[i][j]){

The error message is:

Unhandled exception at 0x012875DD in CCLC.exe: 0xC0000005: Access violation reading location 0x0000004B.

c++
arrays
pointers
asked on Stack Overflow Jun 13, 2013 by Zachary • edited Jun 13, 2013 by Zachary

2 Answers

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

a is not an array of pointers, it is simply a 2 dimensional array.

notice how the access violation is reading address 0x0000004B? that's 75, a number between 0 and 99 :) because you are treating a 2 dimensional array (which is just a one dimensional array with a neat way of accessing it) as an array of arrays, it is taking one of the values in your array (75) to be the address of a sub array, then trying to read the non existent array at address 75 (or 0x0000004B)

I suggest that you 'flatten' your arrays and work with them as one dimensional arrays, which I find simpler:

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;
}
answered on Stack Overflow Jun 13, 2013 by matt • edited Jun 13, 2013 by matt
1

One suggestion about the SetZero(). There is a function called memset() which allows you to set all bytes to a specific value given a starting pointer and the range. This function could make your SetZero() function more cleaner:


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

Fill block of memory. Sets the first num bytes of the block of memory pointed by ptr to the specified value (interpreted as an unsigned char).

Parameters

  • ptr: Pointer to the block of memory to fill.
  • value: Value to be set. The value is passed as an int, but the function fills the block of memory using the unsigned char conversion of this value.
  • num: Number of bytes to be set to the value, size_t is an unsigned integral type.

For example, the following code block from your program:

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

can be achieved by memset in a cleaner way:

 memset(a[i], 0, n * sizeof(int));
 memset(b[i], 0, n * sizeof(int));
answered on Stack Overflow Jun 13, 2013 by keelar • edited Jun 13, 2013 by keelar

User contributions licensed under CC BY-SA 3.0