-1

I want my array to be global but i get my variables with scanf().

#include <stdio.h>

int m, n;

int main (void){

    scanf("%d", &m);
    scanf("%d", &n);

    int array[m][n];
    make_arr(array); //initializes array with random numbers
}

So what is the solution?

Edit: i use the solution of Farbod Shahinfar but i can't use it with my function:

void  make_arr (int  array[m][n] ){
    int i , j ;
    srand(time(NULL));

    for(i=0;i<m;i++)
        for(j=0;j<n;j++)
            array[i][j] = rand() % 2;

What should i do?

  • 3
    Global pointer, allocate space with `malloc()`. – Nate Eldredge Mar 06 '20 at 05:41
  • @NateEldredge Well, i've never wrote/read such a thing before and i am really new to pointers so can you show it to me? –  Mar 06 '20 at 05:43
  • 2
    Standard practice is to make `m` and `n` local variables. Pass them to any function that needs to know the array size: `make_arr(m, n, array)`. And declare the function like this: `void make_arr(int m, int n, int array[m][n])` – user3386109 Mar 06 '20 at 05:53
  • 1
    Why a _global_ array? – ad absurdum Mar 06 '20 at 05:53
  • 1
    @exnihilo 1. Makes my job way easier. 2. To learn something new. –  Mar 06 '20 at 06:27
  • [C11 6.7.6.2p2](http://port70.net/~nsz/c/c11/n1570.html#6.7.6.2): *If an identifier is declared as having a variably modified type, it shall be an ordinary identifier (as defined in 6.2.3), have no linkage, and have either block scope or function prototype scope. If an identifier is declared to be an object with static or thread storage duration, it shall not have a variable length array type.*. **Short answer: you cannot have a VLA at file scope.** – pmg Mar 07 '20 at 08:53

3 Answers3

2

You can declare a global pointer to an array and set it when you have scanned the input.

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

int **array;
int m,n;

int main(void)
{
    scanf("%d", &m);
    scanf("%d", &n);
    array = malloc(sizeof(int *) * m);
    for (int i = 0; i < m; i++)
         array[i] = malloc(sizeof(int) * n);
    make_array(array);
    // your other codes
    // ....
    
    for (int i = 0; i < m; i++)
        free(array[i]);
    free(array);
}

Memory allocated using malloc must be freed otherwise your program will have memory leakage problem.

Answer to the edit section: You have declared a parameter for your make_arr function with the same name of the global variable this parameter will hide the global variable. For clarification, if you declare a global variable you do not need to pass it as argument to a function.

void  make_arr ()
{
    int i , j ;
    srand(time(NULL));

    for(i=0;i<m;i++)
        for(j=0;j<n;j++)
            array[i][j] = rand() % 2;
    // ....
}

Another approach is to pass the array to your function. This way you do not need the global variable at all. A possible function signature can be as below

void  make_arr (int **array)
{
    int i , j ;
    srand(time(NULL));

    for(i=0;i<m;i++)
        for(j=0;j<n;j++)
            array[i][j] = rand() % 2;
    // ....
}

As Andrew Henle pointed out there is an awesome post on StackOverflow showing the right way of allocating multi-dimensional arrays. I have to confess that I did not knew about it.

Correctly allocating multi-dimensional arrays

Thanks to Andrew Henle for his constructive and useful comment


A note about malloc (Do read man page) Malloc allocates memory from heap. You should check the man page of malloc for more information.

The malloc() function allocates size bytes and returns a pointer to the allocated memory. The memory is not initialized. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().

The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.

Community
  • 1
  • 1
Farbod Shahinfar
  • 777
  • 6
  • 15
  • 2
    `int **array;` is **not** a pointer to a 2-dimensional array. It's a pointer to an array of pointers to multiple separate one-dimensional arrays. See [**Correctly allocating multi-dimensional arrays**](https://stackoverflow.com/questions/42094465/correctly-allocating-multi-dimensional-arrays) – Andrew Henle Mar 06 '20 at 10:19
  • @AndrewHenle you are completely correct and I did not meant to imply it is a pointer to 2d-array. Thanks for the link you have shared. – Farbod Shahinfar Mar 07 '20 at 08:21
1

First, given the variable-length array

int array[m][n];

your void make_arr( int array[m][n] ) won't work with int **array because int **array is not an actual 2-dimensional array. int **array is a pointer to an array of pointers to multiple and completely separate one-dimensional arrays. Such a construct is simply incompatible with being treated as an actual array.

And you can't give int array[m][n]; global scope because it's variable-length, and global variables are static (unchanging, not necessarily C's static) and have to be fixed-size.

And you can't use something like a typedef to create an "array type", because that's a compile-time definition and the array is "sized" at run time.

So you need to allocate the array dynamically, but the global variable use to access the array won't have sizing information associated with it.

The global variable pretty much has to be a void *.

To access the array, you have to create a pointer at run-time to a VLA and assign the global void * to that pointer.

This would work (note that the local pointer has to be dereferenced to access the array):

#include <stdlib.h>

void *array;
int m;
int n;

// create the array, assumes both
// m and n are already set
void createArray()
{
    int ( *localArrayPtr )[m][n] = malloc( sizeof( *localArrayPtr ) );
    array = localArrayPtr;
}

void fillArray( void )
{
    int ( *localArrayPtr )[m][n] = array;
    for ( int ii = 0; ii < m; ii++ )
    {
        for ( int jj = 0; jj < n; jj++ )
        {
            ( *localArrayPtr )[ ii ][ jj ] = rand();
        }
    }
}

void someOtherFunc( void )
{
    int ( *localArrayPtr )[m][n] = array;

    ( *localArrayPtr )[ x ][ y ] = ...;
}

As an exercise, it works. Forcing a VLA to have global scope, though, causes accessing the array to be more complex than necessary, adding to existing problems with using globally-scoped variables.

It's probably a lot better from both a scope and code complexity perspective to just pass the array to functions via arguments, such as void someFunc( int m, int n, int array[ m ][ n ] ) { ... }. Accessing elements would then just be in the form array[ x ][ y ].

You could create "getter" and "setter" functions to hide the complexity:

int getElement( int x, int y )
{
    int ( *localArrayPtr )[m][n] = array;
    return( ( *localArrayPtr )[ x ][ y ] );
}

void setElement( int x, int y, int value )
{
    int ( *localArrayPtr )[m][n] = array;
    ( *localArrayPtr )[ x ][ y ] = value;
}

A good optimizing compiler would likely inline those.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
0

As mentioned by Nate you can create a global pointer and then allocate memory to it using "malloc()"

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

int *array;

int main() {
  int m, n;
  scanf("%d", &m);
  scanf("%d", &n);

  array = malloc(sizeOf(int) * m * n);
  return 0;
}

And you can also ref this blog here:

A. KUMAR
  • 330
  • 1
  • 9