1

I wrote the following simple program to print out a given matrix:

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

char matrix[10][10] = {
        {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'},
        {'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'},
        {'U', 'V', 'W', 'X', 'Y', 'Z', '.', ',', '!', '?'},
        {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'},
        {'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'},
        {'U', 'V', 'W', 'X', 'Y', 'Z', '.', ',', '!', '?'},
        {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'},
        {'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'},
        {'U', 'V', 'W', 'X', 'Y', 'Z', '.', ',', '!', '?'},
        {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'}
};

void printMatrix(char* matrix, int matrix_size)
{
  for (int i = 0; i < matrix_size; i = i + 1)
    {
      for (int j = 0; j < matrix_size; j = j + 1)
        {
          printf("%c", matrix[i * matrix_size + j]);
          if (j == matrix_size - 1)
            printf("\n");
        }
    }
  printf("\n");
}

int main()
{
     printMatrix(matrix, 10);
}

The program runs as expected, but my compiler (GNU) gives the following warning:

...warning: passing argument 1 of 'printMatrix' from incompatible pointer type [-Wincompatible-pointer-types]|
...note: expected 'char *' but argument is of type 'char (*)[10]'|
||=== Build finished: 0 error(s), 1 warning(s) (0 minute(s), 3 second(s)) ===|

Could you please tell me what I am doing wrong?

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
3nondatur
  • 353
  • 2
  • 9
  • 2
    When you pass `char matrix[10][10]` to a function, what the function receives is properly declared as `char matrix[][10]`, or equivalently, `char (*matrix)[10]`. Given what your `printMatrix` function is doing, you want to call `printMatrix(&matrix[0][0], 10);`. – Steve Summit Apr 26 '23 at 12:39
  • 2
    @SteveSummit Deep into language lawyer territory...: notably, doing it like that will only work for `char` because they are a special type with special exceptions as per 6.3.2.3. Had it been an `int[10][10]` then inspecting `matrix[i*n + j]` would strictly speaking be undefined behavior, because we access the first `int [10]` array out of bounds and pointer arithmetic isn't defined to work for that. In practice I don't think any system will misbehave though, especially since arrays are guaranteed to have contiguous allocation. – Lundin Apr 26 '23 at 12:57

1 Answers1

2

An array when used in an expression, or declared as function parameter, "decays" into a pointer to the first element. The first element of a char [10][10] is of type char [10]. A pointer to such an array element is char (*)[10]. Hence:

expected 'char *' but argument is of type 'char (*)[10]'

These are incompatible pointer types so your code is invalid C. Your compiler generated an executable anyway because you run it with lax non-standard settings - I recommend switching to this: What compiler options are recommended for beginners learning C? Because what will happen if you run an executable formed out of invalid C is anyone's guess.

However, there is a rule in C saying that any type can be inspected byte by byte using a character pointer. So if you just change the code to printMatrix((char*)matrix, 10); then it's valid C and actually guaranteed to work as intended.

It is better practice to rewrite the whole function to use 2D arrays proper though:

void printMatrix (int matrix_size, char matrix[matrix_size][matrix_size])
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 1
    Wouldn't that 2nd function parameter type allocate an entire nxn array and copy it on the stack? – spartygw Apr 26 '23 at 12:55
  • 1
    @spartygw No, it is very hard to allocate array parameters on the stack in C, as per intentional language design (the 1st paragraph of this answer actually explains why). The only way to do so is to wrap the array in a struct and pass the struct by value. – Lundin Apr 26 '23 at 12:58
  • 1
    Also notably the above "pointer to VLA" syntax is soon once again mandatory to support by all conforming ISO C compilers, as soon as C23 goes live later this year. – Lundin Apr 26 '23 at 13:01
  • @spartygw: No. In the context of a function parameter declaration, `T a[N]` and `T a[]` are "adjusted" to `T *a` The parameter declaration `char matrix[matrix_size][matrix_size]` will be adjusted to `char (*matrix)[matrix_size]` (this is true for regular arrays and VLAs). When you pass an array expression as a function argument, what the function actually receives is a pointer to the first element, not a copy of the array. – John Bode Apr 26 '23 at 14:22