2

I am tring to make a simple transpose func on an r*r matrix. In my code below, when i get to the line temp = mat[i][j] I get SIGSEGV. but I dont really get why. Any tips would be appreciated.

void transpose(int** mat, size_t col)
{
 int i = 0;
 int j = 0 ;

 for(i= 0; i< col; ++i)
 {
    for(j = i ; j< col; ++j)
    {
        int temp = mat[i][j];
        mat[i][j] = mat[j][i];
        mat[j][i] = temp;
    }
 }
}
void printMat(int* arr, int size)
{
 int i = 0;
 for(i = 0 ; i< size*size ;++i)
 {
    printf("%d| ", arr[i]);
    if((1+i)%size == 0)
    {
        printf("\n");
    }
 }
}
int main()
{
 int arr[][3] = {{1,2,3},{4,5,6},{7,8,9}};
 printMat((int*)arr, 3);
 transpose((int**)arr, 3);
 printMat((int*)arr, 3);

return 0;
}
H.cohen
  • 517
  • 3
  • 9
  • Where is `arr` defined? – Andrew Henle Nov 06 '18 at 16:45
  • sorry, it accidentally didn't make my original post - in main. @AndrewHenle – H.cohen Nov 06 '18 at 16:47
  • 3
    Why are you slamming hard casts on that variable to make it fit into functions otherwise-not-designed for arrays of arrays ?... *repeatedly* ? fyi `int ar[x][y]` is **not** synonymous with `int **`, and all the casting in the world isn't going to change that. The error you were getting (and covered up with the hard casts) was there for a reason. Casting like this is C is almost never required, and if you're just starting out in the language it is a near-guarantee you're doing something wrong. – WhozCraig Nov 06 '18 at 16:52
  • Did you try using GDB or [Valgrind](http://valgrind.org) ? – Jean-Marc Zimmer Nov 06 '18 at 16:53
  • i used gdb and got :Program received signal SIGSEGV, Segmentation fault. 0x00005555555548a6 in transpose (mat=0x7fffffffe030, col=3) @Jean-MarcZimmer – H.cohen Nov 06 '18 at 16:55
  • i dont want to define N in transpose(arr[]N] mat, int col) what do you suggest? @WhozCraig – H.cohen Nov 06 '18 at 16:57
  • C toolchains nearly all support VLAs (ex of one that doesn't: MSVC), so if you flip the order of your arguments you can do what you seek without forcing N externally. [Like this](https://ideone.com/BCqmpa). – WhozCraig Nov 06 '18 at 16:59
  • `col=3` : Well it's trying to access the fourth row in the table/the fourth cell in the row. Now the question is : how the hell did `i` or `j` increment up to 3 ? – Jean-Marc Zimmer Nov 06 '18 at 16:59
  • @WhozCraig I don't really understand what you mean - Not like this right: void transpose(size_t col, int** mat) – H.cohen Nov 06 '18 at 17:04
  • This is a common FAQ. See for example https://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays – Lundin Nov 06 '18 at 17:13
  • performance tip: if `i==j` there is no benefit to swapping `mat[i][j]` with `mat[j][i]` – Tim Randall Nov 06 '18 at 17:39

3 Answers3

1

void transpose(int** mat, size_t col) is saying you have a pointer to an array of pointers.

But the array is a single piece of memory

change void transpose(int** mat, size_t col) to

void transpose(int mat[][3], size_t col)

will work

lostbard
  • 5,065
  • 1
  • 15
  • 17
1

If you're using a native array of arrays of int, you can't force-feed it to a function expecting a pointer to a sequence of pointers. All of those hard casts are a clear-and-present indicator you're doing something wrong. Whoever told you int[N][M] is synonymous with int** was lying; they're not.

Most toolchain vendors support VLAs (variable length arrays) in C in automatic variable locations, including function arguments. The only requirement is the size must precede the array in the argument list:

#include <stdio.h>

void transpose(size_t siz, int mat[][siz])
{
    for(size_t i= 0; i< siz; ++i)
    {
        for(size_t j = i ; j< siz; ++j)
        {
            int temp = mat[i][j];
            mat[i][j] = mat[j][i];
            mat[j][i] = temp;
        }
    }
}

void printMat(size_t siz, int const arr[][siz])
{
    for(size_t i=0; i<siz; ++i)
    {
        for (size_t j=0; j<siz; ++j)
            printf("%d| ", arr[i][j]);
        fputc('\n',stdout);
    }
}

int main()
{
    int arr[][3] = {{1,2,3},{4,5,6},{7,8,9}};
    printMat(3, arr);
    transpose(3, arr);
    printMat(3,arr);

    return 0;
}

Output

1| 2| 3| 
4| 5| 6| 
7| 8| 9| 
1| 4| 7| 
2| 5| 8| 
3| 6| 9| 

See it live.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
0

So, I was thinking about how the 2D array is set in the memory, the col are needed to let the compiler know how many ints (in this case) to skip over between the rows, but in fact A 2D array is simply set as a regular array in the memory, a continuous block of memory.

So- if I want to "move" between the rows I can simply calculate the offset myself. For example- the element mat[1,0] is set in the mat[col_num*1 +0] if I ask the compiler to look at mat as an ordinary int array.

The reason I wanted to set my function this way is that I wanted this function to work without having to #define col 3, or set it as a literal int the function definition (int mat[][3]). keeping in mind the int mat[][3] I declared in main will have to be casted into (int*)mat when calling the function, this works:

void TransposeOfD2Array(int* mat, size_t col)
{
    int i = 0;
    int j = 0;

   for(i= 0; i< col; ++i)
   {
     for(j = i ; j< col; ++j)
     {
     int temp = mat[(col*i)+j];
       mat[(col*i)+j] = mat[(col*j)+i];
       mat[(col*j)+i] = temp;
     }
   }
}
void printMat(int* arr, int size)
{
  int i = 0;
  for(i = 0 ; i< size*size ;++i)
  {
     printf("%d| ", arr[i]);
     if((1+i)%size == 0)
     {
         printf("\n");
     }
  }
}
int main()
{
   int mat[][3] = {{0,1,2},{3,4,5},{6,7,8}};
   TransposeOfD2Array((int*)mat, 3);
   printMat((int*)mat, 3);
   return 0;
}
H.cohen
  • 517
  • 3
  • 9