1

I'm new to C programming and I've run into a problem when creating 2D array printing function. When I try to execute the code below I get:

points.c:13: error: unknown array element size

As I've checked there are very similar codes online, which are supposed to work. I've tried to initialize function as

int print2DArray( int arrayLen, int elementLen, int array[arrayLen][elementLen])

but it raises:

points.c:3: error: 'arrayLen' undeclared

Could somebody tell me what's wrong with this code and how to fix it? I also don't understand why very similar function for 1D arrays works just fine. It has to be in pure C.

#include <stdio.h>
//supposed to print 2D array:
int print2DArray(int array[][], int arrayLen, int elementLen)
{
    int i;
    int j;

    for (i = 0; i < arrayLen; i++)
    {
        for (j=0; j < elementLen; j++)
        {
            printf("%5d", array[i][j]);
        }
        printf("\n");
    }
}

//prints 1D array:

int printArray( int array[], int arrayLen)
{
    int i;
    for (i = 0; i < arrayLen; i++)
    {
        printf("%d", array[i]);
    }
}

--- edit ---

I undestand most of you pointed out that the function has to be called like that:

#include <stdio.h>

int print2DArray( int arrayLen, int elementLen, int array[arrayLen][elementLen])
{
    int i;
    int j;

    for (i = 0; i < arrayLen; i++)
    {
        for (j=0; j < elementLen; j++)
        {
            printf("%5d", array[i][j]);
        }
        printf("\n");
    }
}

This raises an error:

points.c:3: error: 'arrayLen' undeclared

I'm using tcc for windows and according to documentation it is supposed to support C99 VLA.

Chris M
  • 21
  • 5
  • 1
    You say you have written the function as `int print2DArray( int arrayLen, int elementLen, int array[arrayLen][elementLen])`. But you haven't. Instead, you have done `int print2DArray(int array[][], int arrayLen, int elementLen)` which is something completely different (and invalid). – Peter Dec 30 '19 at 14:02
  • `int array[][]` isn't a valid argument, so forget that. And before this goes on, you've already determined your compiler *does* support VLAs (variable-length-arrays) ? It must, or your `int print2DArray( int arrayLen, int elementLen, int array[arrayLen][elementLen])` stands no chance of working. – WhozCraig Dec 30 '19 at 14:02
  • Post the code that causes "I've tried to initialize function as `int print2DArray( int arrayLen, int elementLen, int array[arrayLen][elementLen])`". I suspect you have a transcription error. – chux - Reinstate Monica Dec 30 '19 at 14:17
  • @Peter I know, I've meant that I've tried both methods. – Chris M Dec 30 '19 at 14:17
  • @ChrisM " I've tried both methods." --> yet the post does not show exactly what you tried. Post shows the code of one failed approach, but talks about the other. Post the 2nd code too. Other useful info: what compiler and version are you using.version? – chux - Reinstate Monica Dec 30 '19 at 14:20
  • 1
    ChrisM "I'm using tcc for windows and according to documentation it is supposed to support C99 VLA" --> The compiler appears to be in a mode that simply does not accept VLA. Maybe the compiler options are set for pre-C89, no VLA or "support C99" is only "support most of C99". – chux - Reinstate Monica Dec 30 '19 at 14:32
  • Note that all of your functions are supposed to return an `int` value, but none of them actually does. – Bob__ Dec 30 '19 at 14:46
  • I meant pre-C99 [above](https://stackoverflow.com/questions/59532055/function-for-printing-2d-arrays-of-uknown-size-in-c/59532632#comment105234463_59532055), not pre C89. – chux - Reinstate Monica Dec 30 '19 at 14:47

4 Answers4

4

It appears OP's compiler (or the mode it is used) does not support variable length array (VLA) as a function parameter.

Below is a non-VLA approach.

void print2DArrayX(int arrayLen, int elementLen, const int *array) {
  int i;
  int j;

  for (i = 0; i < arrayLen; i++) {
    for (j = 0; j < elementLen; j++) {
      printf("%5d", array[i*elementLen + j]);
    }
    printf("\n");
  }
}

Call with address of first int, not the 2D array

#define ARRAY_LEN 3
#define ELEMENT_LEN 4
int array[ARRAY_LEN][ELEMENT_LEN] = { 0 };
...
print2DArrayX(ARRAY_LEN, ELEMENT_LEN, array[0]);
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Doesn't this approach cause undefined behavior of the type mentioned in [Annex J.2](http://port70.net/~nsz/c/c11/n1570.html#J.2): "_An array subscript is out of range, even if an object is apparently accessible with the given subscript (as in the lvalue expression a[1][7] given the declaration int a[4][5]) (6.5.6)_" and [discussed here](https://stackoverflow.com/questions/6290956/one-dimensional-access-to-a-multidimensional-array-is-it-well-defined-behaviour)? – ad absurdum Jan 02 '20 at 05:32
  • @exnihilo Interesting: I would say it is not UB given `const int *array` does not carry limitations of the 2 dimensions of `int array[ARRAY_LEN][ELEMENT_LEN]`, only that the overall indexing is limited by `ARRAY_LEN*ELEMENT_LEN` and no [aliasing](https://stackoverflow.com/a/6293364/2410359) in `print2DArrayX()`. – chux - Reinstate Monica Jan 02 '20 at 17:37
1

Unless you are using a C99 compiler,

int print2DArray( int arrayLen, int elementLen, int array[arrayLen][elementLen])

is not possible.

Even if you are using C99 compiler, your code has a problem. You need to pass one of the dimension first.

int print2DArray(int arrayLen, int elementLen, int arr[][elementLen]);

So,

int print2DArray(int arrayLen, int elementLen, int arr[][elementLen]) 
{
    // Your code
    int i;
    int j;

    for (i = 0; i < arrayLen; i++)
    {
        for (j=0; j < elementLen; j++)
        {
            printf("%5d", array[i][j]);
        }
        printf("\n");
    }

    return 0;
}

This can be used as

int main(void) 
{ 
    int i32Array[3][3] = {{-15, 4, 36}, {45, 55, 12}, {-89, 568, -44568}}; 
    int m = 3, n = 3; 
    // I am not sure why 'print2DArray' would return an int 
    // (or anything at all for that matter). 
    // If you can establish a case for it, 
    // modify the function and the value it is supposed to return,
    // And catch it below.

    print2DArray(m, n, i32Array); 

    return 0; 
}

I am not sure how you are calling print2DArray function. Unless you post that piece of code, it is difficult to resolve your problem. Confirm that you are calling the function correctly as shown above.

WedaPashi
  • 3,561
  • 26
  • 42
  • Good first step, yet if `int print2DArray(int arrayLen, int elementLen, int arr[][elementLen]);` works, so should OP's `int print2DArray( int arrayLen, int elementLen, int array[arrayLen][elementLen])` which made a reported error. – chux - Reinstate Monica Dec 30 '19 at 14:24
  • @chux-ReinstateMonica: It should work for C99, right? – WedaPashi Dec 30 '19 at 14:25
  • Yes, `int print2DArray( int arrayLen, int elementLen, int array[arrayLen][elementLen])` would work in C99 - and optionally in C11,C17. – chux - Reinstate Monica Dec 30 '19 at 14:27
  • I guess then problem is with how OP is calling this function. Needs to have a look at that. – WedaPashi Dec 30 '19 at 14:27
  • 1
    Answer has weakness, but not a DV. – chux - Reinstate Monica Dec 30 '19 at 14:58
  • @chux-ReinstateMonica: Thank you. I have edited the code to `return 0` from the `print2DArray` function. The compiler would have warned there unless it returns something. I think in C we are allowed not opting to catch a return value from a function returning something. Apart from these are there any weaknesses that you think that can be improved on? – WedaPashi Jan 02 '20 at 05:15
  • Some ideas: "Unless you are using a C99 compiler," is incorrect as C11,C17 optionally work too. The key attribute is support for VLA (not mentioned here). Example uses a 3x3 matrix. Using a non-square matrix improves clarity as to which dimension is what in example code. OP use `int` for array dimensions, `size_t` would be better, yet perhaps better to deal with OP's primary issues first. Last 2 lines look like they should have been comments to the question. – chux - Reinstate Monica Jan 02 '20 at 17:24
  • @chux-ReinstateMonica: Thanks a lot. That wisdom comes with experience :-) I hope I'll get there. I am not sure if I should make those improvements in the answer just like that, because then it will be unfair with other answers, since it will be a collective effort and not an individual one. – WedaPashi Jan 03 '20 at 05:26
1

Ok, so thanks for all the answers - they were very helpful. I've just tried to use gcc in linux and as you've pointed out this approach works fine:

int print2DArray( int arrayLen, int elementLen, int array[arrayLen][elementLen])

I guess tcc (tiny c compiler, windows version 0.9.27) doesn't support VLA after all. A bit strange since documentation says it does.

Chris M
  • 21
  • 5
  • "A bit strange since documentation says it does." --> best to post the errant tcc quote and the version of tcc. – chux - Reinstate Monica Dec 30 '19 at 14:52
  • Do you mean this doc: https://bellard.org/tcc/tcc-doc.html#Clang ? I haven't found any way to specify a particular standard, though. – Bob__ Dec 30 '19 at 14:58
  • @Bob__ yes, this little document. Since tcc 'help' doesn't show any options for specifying a standard I'd assume that VLA is 'on' by default. To be honest at least I found out that VLA isn't part of ANSI C standard. I have to stay within ANSI C, so it's not a real problem for me. – Chris M Dec 30 '19 at 15:19
  • Not to open that can of worms, but even if it's common to refer to C89 as ANSI C, the [current ANSI C standard](https://webstore.ansi.org/Standards/ISO/ISOIEC98992018) is C18. – Bob__ Dec 30 '19 at 15:45
1

How about you try this solution.

#include <stdio.h>


int print2DArray(int* array, int arrayLen, int elementLen)
{
    int i;
    int j;

    for (i = 0; i < arrayLen; i++)
    {
        for (j=0; j < elementLen; j++)
        {
            printf("%5d ", *(array+j+elementLen*i));
        }
        printf("\n");
    }

}

int main(){
    int arr[2][6] = {   {9,258,9,96,-8,5},
                        {1,1212,-3,45,27,-6}
                      };
    print2DArray(*arr,2,6);
    return 0;
}