Home > Mobile >  C, 2D Array, How to find specific number in all 8 directions
C, 2D Array, How to find specific number in all 8 directions

Time:02-10

You are allowed to enter only 0 and 1 as values in the arrays. Then in place of all elements having a value of 0, enter the number of elements with a value of 1 around that element in all eight directions. And on the end print the 2d array and the values with 1 change to *.

Here is an example how it's supposed to look like:

enter image description here

Here is my code

#include <stdio.h>
#include <stdlib.h>

int main()
{
int n,m;
scanf("%d%d", &n, &m);
int a[n][m];
for(int i=0; i<n; i  ){
    for(int j=0; j<m; j  ){
        scanf("%d", &a[i][j]);
        if(a[i][j]==1){
            a[i][j]=9;
        }
    }
}
for(int i=0; i<n; i  ){
    for(int j=0; j<m; j  ){
        int counter=0;
        if(a[i][j]==9){
            printf("*\t");
        }else if(a[i][j]==0){
        if(a[i 1][j 1]==9 && i!=n && j!=m) counter  ;
        if(a[i-1][j-1]==9 && i!=0 && j!=0) counter  ;
        if(a[i 1][j-1]==9 && i!=n && j!=0) counter  ;
        if(a[i-1][j 1]==9 && i!=0 && j!=m) counter  ;
        if(a[i][j 1]==9 && j!=m) counter  ;
        if(a[i][j-1]==9 && j!=0) counter  ;
        if(a[i 1][j]==9 && i!=n) counter  ;
        if(a[i-1][j]==9 && i!=0) counter  ;
        a[i][j]=counter;
        counter=0;
        printf("%d\t", a[i][j]);
        }
    }
    printf("\n");
 }

return 0;
}

CodePudding user response:

You have UB (undefined behavior).

With (e.g.):

if (a[i   1][j   1] == 9 && i != n && j != m)

Then, a is always fetched, even if i or j is out of range.

To fix this, reorder the terms:

if (i != n && j != m && a[i   1][j   1] == 9)

Now, if either i or j is out of range, then the if will be "short circuited": (i.e. _short circuit evaluation) and the a value will not be fetched.

But, your program output is incorrect. You're coding everything out longhand. It makes it hard to debug (i.e. which lines have a bug).

What wasn't explicitly described was that you are summing the non-zero values in a 3x3 kernal around a given zero point.

The hardcoding doesn't scale too well. Suppose the kernal had to be 100x100. Would we code up 10,000 lines of code?


It's much easier to debug if we refactor to use for loops. And, to use more descriptive names instead of i/j/m/n:

n       hgt
m       wid
i       y*
j       x*

Here is the code:

#include <stdio.h>
#include <stdlib.h>

int
main(int argc,char **argv)
{
    int hgt, wid;
    int counter;
    FILE *xf;

    --argc;
      argv;

    if (argc > 0)
        xf = fopen(*argv,"r");
    else
        xf = stdin;
    if (xf == NULL) {
        perror(*argv);
        exit(1);
    }

    fscanf(xf,"%d%d", &hgt, &wid);
    int a[hgt][wid];

    for (int ycur = 0; ycur < hgt; ycur  ) {
        for (int xcur = 0; xcur < wid; xcur  ) {
            int val;
            fscanf(xf,"%d", &val);

            if (val == 1)
                val = 9;

            a[ycur][xcur] = val;
        }
    }

    for (int yctr = 0; yctr < hgt; yctr  ) {
        for (int xctr = 0; xctr < wid; xctr  ) {
            if (a[yctr][xctr] == 9) {
                printf("*\t");
                continue;
            }

            counter = 0;
            for (int yoff = -1; yoff <= 1; yoff  ) {
                int ycur = yctr   yoff;

                if (ycur < 0)
                    continue;
                if (ycur >= hgt)
                    continue;

                for (int xoff = -1; xoff <= 1; xoff  ) {
                    int xcur = xctr   xoff;

                    if (xcur < 0)
                        continue;
                    if (xcur >= wid)
                        continue;

                    counter  = (a[ycur][xcur] == 9);
                }
            }

            printf("%d\t",counter);
        }

        printf("\n");
    }

    return 0;
}

Here is the program output for your sample input:

*   1   1   2   *
2   2   2   *   3
*   1   2   *   2

CodePudding user response:

Not sure what the question is, but there are bugs in the code - you are accessing out of array boundaries by doing, for example, this:

if(a[i-1][j-1]==9 && i!=0 && j!=0)

When i and j are zeros you are reading the value of a[-1][-1]. Changing the order of conditions and checking i and j first would guard against such an access. Same happens when you access the "borders" of the matrix. And, the "i!=n && j!=m" condition is always true within the loops - you iterate as long as i<n and j<m.

But aside of that, some of these accesses in fact read from within the array, but from a wrong location. Here is an example that shows that:

Given the matrix of 2x2

0 1
1 0

This is the result your code produced:

2   *
*   3

Where obviously, '3' is wrong.

Why it happened? The 2D array is in fact stored as a 1D array in memory, like this:

0  1  1  0  // this is your data

0  1  2  3  // this is the index in the array (offset from the array start)

And each element is located at an offset of row*columns column from the array start (i.e. this is the formula to find the index in 1D array given i and j). When you count the '1'-neighbours for the last element (a[1][1] in this example), you count the two obvious results (at a[1][0] and a[0][1]), but then you hit this condition:

if(a[i-1][j 1]==9 && i!=0 && j!=m)

For this last cell, i is 1 and j is 1, so the second part of the condition is true. But what about a[i-1][j 1]==9 ? This references a memory at row*columns column, right? I.e. (i-1)*2 (j 1), because that's what you tried to access. Substituting i and j with 1 and 1, and you get offset 2 in the 1D array above. Which is 1 in the input matrix (or actually 9 since you've replaced it). So you count it twice.

Guarding better against "stepping out" of the matrix (but not necessarily out of the actual array) will solve this bug.

  • Related