0

This is a follow up to my previous question. The following simple code to print a matrix works without any errors or warnings at my home computer (GNU GCC compiler):

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


void printMatrix(int rows, int columns, int matrix[rows][columns]);

void printMatrix(int rows, int columns, int matrix[rows][columns])
{
  for (int i = 0; i < rows; i = i + 1)
    {
      for (int j = 0; j < columns; j = j + 1)
        {
          printf("%d ", matrix[i][j]);
          if (j == columns - 1)
            printf("\n");
        }
    }
  printf("\n");
}

int main()
{
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12},
    };

    int rows = 3;
    int columns = 4;
    printMatrix(rows, columns, matrix);
}

However, when I try to use it at another computer (that uses the Clang compiler) I get the error:

||=== Build: Debug in Test (compiler: LLVM Clang Compiler) ===|

...|5|error: variable length array used [-Werror,-Wvla]|

...|5|error: variable length array used [-Werror,-Wvla]|

...|7|error: variable length array used [-Werror,-Wvla]|

...|7|error: variable length array used [-Werror,-Wvla]| ||=== Build failed: 4 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===

As I understand it this error is a complaint that "matrix[rows][columns]" uses variable lengths. Could you please tell me how to fix this error so that I can still use "printMatrix" in the same way for arbitrarily large matrices?

3nondatur
  • 353
  • 2
  • 9
  • 2
    What version of clang, and how exactly are you calling it? – dbush Apr 26 '23 at 22:37
  • 6
    Remove `-Wvla` when calling `clang`. – Barmar Apr 26 '23 at 22:39
  • 4
    It is an error generated by you. You want to use VLAs but ask the compiler to warn if they are used and to treat it as an error. – 0___________ Apr 26 '23 at 23:53
  • 1
    no need for `if (j == columns - 1) printf("\n");` just do `printf("\n");` after the inner loop. – yano Apr 27 '23 at 00:24
  • 1
    This is a compiler standards issue. See here for why: [Why does clang complain about using variable-length arrays with '-std=c99' flag?](https://stackoverflow.com/questions/61825661/why-does-clang-complain-about-using-variable-length-arrays-with-std-c99-flag) The answer is simply to disable complaints about VLAs as **Allan Wind** suggests (or, less ideally, to compile against the C99 standard). – Dúthomhas Apr 27 '23 at 03:04
  • Simply don't compile with `-Weverything`, it's a broken option. For strict but correct diagnostics compile with `-std=c17 -Wall -Wextra -pedantic-errors`. – Lundin Apr 27 '23 at 07:43

1 Answers1

3
  1. The code is correct and the most direct way of doing what you want to accomplish. I suggest you remove the -Wvla option.

  2. You could make it compile-time constants:

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

#define ROWS 3
#define COLUMNS 4

void printMatrix(int matrix[ROWS][COLUMNS]) {
    for (int i = 0; i < ROWS; i = i + 1) {
        for (int j = 0; j < COLUMNS; j = j + 1) {
            printf("%d ", matrix[i][j]);
            if (j == COLUMNS - 1)
                printf("\n");
        }
    }
    printf("\n");
}

int main() {
    int matrix[ROWS][COLUMNS] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12},
    };
    printMatrix(matrix);
}
  1. You can treat the int [4][3] as a int [4*3] but it's undefined behavior (UB) as int[i] is only well defined for read/write for i 0 through 3, and for forming the address at i = 4. It happens to work for me. The UB can be eliminated by changing the definition of matrix to int matrix[] = { ... }; (I prefer leaving out the size which in case would be 12).
#include <stdio.h>
#include <stdlib.h>

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

int main() {
    int matrix[3][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12},
    };
    int rows = sizeof matrix / sizeof *matrix;
    int columns = sizeof *matrix / sizeof **matrix;
    printMatrix(rows, columns, *matrix);
}
  1. Another option is define matrix as an array of pointers but it's a different thing (each row can can have different number of columns).
Allan Wind
  • 23,068
  • 5
  • 28
  • 38
  • Your second example strictly speaking invokes undefined behavior for out-of-bounds access. `matrix` is an array of 3 `int [4]` arrays. It is not an `int [3*4]` array, so the function will access it out of bounds. – Lundin Apr 27 '23 at 07:45
  • @Lundin Yes, which is why I pointed it out including the reason for it, and how to address it. Do you have a sense of where it doesn't work in practice? – Allan Wind Apr 27 '23 at 08:28
  • 1
    The compiler is in theory free to assume that `matrix[1]` and `[2]` aren't modified by the function. Suppose the function had written `matrix[columns * i + j]=0;` inside the inner loop and the caller had code like `if(matrix[1][0]==5)` after the function call, then the caller is free to optimize that `if` statement as always true. I don't know of any compiler which actually does things like that though. – Lundin Apr 27 '23 at 08:57