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?

6
  • 2
    What version of clang, and how exactly are you calling it? Commented Apr 26, 2023 at 22:37
  • 6
    Remove -Wvla when calling clang. Commented Apr 26, 2023 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. Commented Apr 26, 2023 at 23:53
  • 1
    <O/T> no need for if (j == columns - 1) printf("\n"); just do printf("\n"); after the inner loop. Commented Apr 27, 2023 at 0: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? The answer is simply to disable complaints about VLAs as Allan Wind suggests (or, less ideally, to compile against the C99 standard). Commented Apr 27, 2023 at 3:04

1 Answer 1

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).
Sign up to request clarification or add additional context in comments.

3 Comments

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 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?
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.