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.

Zachary
  • 1,633
  • 2
  • 22
  • 34
  • 1
    What doesn't work about it? Do you get a segmentation fault? An incorrect result? Have you tried running the code through a debugger? – GWW Jun 13 '13 at 04:00
  • define "doesn't work" – vidit Jun 13 '13 at 04:00
  • @GWW Yes. The program stops when it reaches "if(a[i][j] == 0 && b[i][j]){". I don't know why. – Zachary Jun 13 '13 at 04:05
  • Have you looked at the values of `i` and `j` using the debugger to see if they have unexpected values? – GWW Jun 13 '13 at 04:09
  • @GWW Yes. i and j are all zero. No problem. I have add information about the problem when executing. – Zachary Jun 13 '13 at 04:11

2 Answers2

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;
}
matt
  • 4,042
  • 5
  • 32
  • 50
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));
keelar
  • 5,814
  • 7
  • 40
  • 79
  • `memset` doesn't work for `setZero` function. Since I can determine the `num` parameter. `sizeof(b[i])` doesn't work. – Zachary Jun 13 '13 at 04:35
  • @Zack: I have included an example from your code in my answer, hopefully it will make it more clear. – keelar Jun 13 '13 at 04:36
  • Yes. I see. IT REALLY WORKS. But if I want to set all `elements` to `1` but `0`. How can I implement it except `for loop`? – Zachary Jun 13 '13 at 04:42
  • @Zack: Then memset won't work as it's processing unit is bit. – keelar Jun 13 '13 at 04:45
  • @Zack: [here](http://stackoverflow.com/questions/7202411/memset-integer-array) is some more details in case you're interested. – keelar Jun 13 '13 at 04:49