Reputation: 137
I programmed a function which can rotate 4 x 4 arrays, and now i want to output it... But I get a bunch warnings, but it compiles and works, so I guess i only did some "minor/formal" mistakes.
#include <stdio.h>
//-----------------------------------------------------------------------------
///
/// This function prints four 4x4 matrix
///
/// @param m1, m2, m3, m4 input matrix you want to print.
///
/// @return 0
//-----------------------------------------------------------------------------
void *print_matrix(char m1[4][4], char m2[4][4], char m3[4][4], char m4[4][4])
{
for(int i = 0; i < 4; i++)
{
for(int j = 0; j < 4; j++)
{
printf("%c ", m1[i][j]);
}
printf(" ");
for(int j = 0; j < 4; j++)
{
printf("%c ", m2[i][j]);
}
printf(" ");
for(int j = 0; j < 4; j++)
{
printf("%c ", m3[i][j]);
}
printf(" ");
for(int j = 0; j < 4; j++)
{
printf("%c ", m4[i][j]);
}
printf("\n");
}
printf("\n");
return 0;
}
//-----------------------------------------------------------------------------
///
/// This function rotates a 4x4 matrix
/// (and collects tears from overworked students @2am, because wtf is )
///
/// @param m, the matrix you want to rotate
///
/// @return m_r the rotated matrix
//-----------------------------------------------------------------------------
char *rotate_matrix(char m[4][4])
{
static char m_r[4][4];
for(int i = 0; i < 4; i++)
{
for(int j = 0; j < 4; j++)
{
m_r[i][j] = m[3-j][i];
}
}
return *m_r;
}
int main(void)
{
char matrix_t [4][4] = {{ '-', '-', '-', '-' },
{ '-', 'O', '-', '-' },
{ 'O', 'O', 'O', '-' },
{ '-', '-', '-', '-' }
};
char matrix_z [4][4] = {{ '-', '-', '-', '-' },
{ '-', 'O', 'O', '-' },
{ 'O', 'O', '-', '-' },
{ '-', '-', '-', '-' }
};
char matrix_l [4][4] = {{ '-', '-', '-', '-' },
{ '-', 'O', '-', '-' },
{ '-', 'O', '-', '-' },
{ '-', 'O', 'O', '-' }
};
char matrix_i [4][4] = {{ '-', '-', 'O', '-' },
{ '-', '-', 'O', '-' },
{ '-', '-', 'O', '-' },
{ '-', '-', 'O', '-' }
};
char (*array)[4][4];
print_matrix(matrix_t, matrix_z, matrix_l, matrix_i);
array = rotate_matrix(matrix_t);
print_matrix(array, matrix_z, matrix_l, matrix_i);
return 0;
}
This are the errors i get:
102:9: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
array = rotate_matrix(matrix_t);
,
103:16: warning: passing argument 1 of ‘print_matrix’ from incompatible pointer type [-Wincompatible-pointer-types]
print_matrix(array, matrix_z, matrix_l, matrix_i);
and
note: expected ‘char (*)[4]’ but argument is of type ‘char (*)[4][4]’
void *print_matrix(char m1[4][4], char m2[4][4], char m3[4][4], char m4[4][4])
And to be honest, i don't get these errors, because the code seems to work, I'm never out of boundaries and obviously I'm not doing any memory violations...
Upvotes: 0
Views: 83
Reputation: 183251
The warnings are because these:
char * // pointer to char or to first element of char[]
char (*)[4] // pointer to char[4] or to first element of char[][4]
char (*)[4][4] // pointer to char[4][4] or to first element of char[][4][4]
are different types. A pointer doesn't just denote a memory location, but also (via its type) how that memory location should be interpreted.
One tricky bit is that an array name (or any other expression that evaluates to an array) decays to a pointer. For example, this is perfectly valid:
char abc[4] = "abc"; // abc is an array of four characters
char a = *abc; // a is 'a', the first character of abc
. . . and conversely, you can use array notation on a pointer (to perform pointer arithmetic and immediately dereference the result):
char * abc = "abc"; // abc is a pointer (into static memory)
char c = abc[2]; // c is 'c', the third character of abc
So char *
is interconvertible with char ()[]
, char (*)[4]
is interconvertible with char ()[][4]
, and char (*)[4][4]
is interconvertible with char ()[][4][4]
.
And what makes it extra tricky is that C doesn't quite support passing an array as a function parameter (though if you really want that, you can achieve the same effect by wrapping the array in a struct and passing that). It does let you declare a function parameter as having an array type, but that is actually syntactic sugar for a function parameter with a pointer type. So these three signatures are equivalent:
void *print_matrix(char m1[4][4], char m2[4][4], char m3[4][4], char m4[4][4])
void *print_matrix(char m1[][4], char m2[][4], char m3[][4], char m4[][4])
void *print_matrix(char (*m1)[4], char (*m2)[4], char (*m3)[4], char (*m4)[4])
Your code works because your various warnings all sort of cancel out:
rotate_matrix
should return either a char (*)[4]
(a pointer to the first row of a char[][4]
) or a char (*)[4][4]
(a pointer to a complete char[4][4]
). Instead, you have it return char *
, and to accomplish that, you dereference the desired pointer, thereby getting (after array-to-pointer decay) a pointer to the first element of the first row of the matrix. Of course, all of these pointers point to the same memory location, just with different types.
char (*)[4]
, you can write char (*rotate_matrix(char m[4][4]))[4]
. . . but it's probably better to declare a row
type, typedef char row[4]
, and then write row * rotate_matrix(char m[4][4])
. In this case you would return m_r
at the end, which decays to a pointer to the first row of m_r
.char (*)[4][4]
, same thing, just with extra [4]
's (and a name like matrix
rather than row
). In this case you would return &m_r
at the end, meaning a pointer to the entirety of m_r
.char (*)[4][4]
.array
has type char (*)[4][4]
, which is fine. The code warning in array = rotate_matrix(matrix_t)
is because of the mis-declaration of rotate_matrix
. But the actual value of the returned pointer was already fine, at least on typical platforms.
array
, then you should probably call it array_ptr
, since it's a pointer to your usual array type.array
as an argument to print_matrix
, which takes a parameter of type char [4][4]
, meaning char (*)[4]
. You can't convert a char (*)[4][4]
(pointer to array of 4 rows of 4 chars) to a char (*)[4]
(pointer to array of 4 chars). To fix this, you just need to dereference array
, by passing *array
instead.(Note: I'm not sure that all of the above implicit conversions are actually guaranteed to work; pointers to different types of objects might not all be interconvertible on all platforms. And even on typical modern platforms, where they are all interconvertible, you might run afoul of strict aliasing rules, which means that your compiler might end up performing optimizations that totally break your code. But it will usually work.)
Upvotes: 1