speedyTeh
speedyTeh

Reputation: 257

How to declare pointer and allocate memory a two-dimensional array and pass to a function

I want to declare the correct pointer and allocate memory for a two-dimensional array, and correctly pass to a function. I am having trouble getting this to work properly and need help.

Here is my code:

    double **podrucje;
    podrucje=(double **) malloc (sizeof (double *) *123);
    for (i=0;i<(123);i++)
    {                       
        podrucje[i]=(double *) malloc (sizeof (double) * 11);
    }
    for (i=0;i<(123);i++)
    {   
        memset (podrucje[i], 0, 10);
    }

But this code doesnt work, it messes up whole my program. So i decided to give up on dynamic allocation and use this:

    double podrucje[123][11]={0};

But i dont know how to send it and use it in function...

Upvotes: 2

Views: 2223

Answers (7)

RoyalJai
RoyalJai

Reputation: 86

int print_func(char((*p)[26])[10])
{
    int i = 0;
    for (i=0; i < 26 ; i++) {
        fprintf(stderr, "%02d:%.*s\n", i, 10, p[0][i]);
    }
    return (0);
}

int main(void)
{
    int nrow = 26;
    int ncol = 10;
    char((*p)[26])[10] = (char((*)[26])[10])(0);
    char(*q)[10];
    char c = 'a';
    int i = 0;

    p = (char((*)[26])[10])malloc(sizeof(char) * nrow * ncol);
    if ((char((*)[26])[10])0 == p) {
            return (-1);
    }
    for (i=0, q=p[0]; i < nrow ; i++) {
        memset(q, c, sizeof(char) * ncol);
        c++;
        q++;
    }
    for (i=0,q=p[0] ; i < nrow ; i++) {
        fprintf(stderr, "%.*s\n", 10, q);
        q++;
    }

    p[0][8][0]='z';
    getchar();
    print_func(p);
    return (0);
}

Upvotes: 0

John Bode
John Bode

Reputation: 123468

There are several ways to dynamically allocate memory for an NxM array. Here are two:

You can declare a pointer to an M-element array, and then malloc N instances of it:

double (*podrucje)[11] = malloc(sizeof *podrucje * 123);

As of C89, you don't need to cast the result of malloc, and the practice is discouraged. Also, note that the operand to sizeof is the expression *podrucje; this gives me the same result as sizeof (double) * 11.

You would index this array as podrucje[i][j] like any other 2D array. podrucje[i] implicitly dereferences the pointer (remember that a[i] is equivalent to *(a + i)) so you don't have to do anything funky with it.

You would use it in a function as follows:

void init(double (*podrucje)[11], size_t rows)
{
  size_t i, j;
  for (i = 0; i < rows; i++)
    for (j = 0; j < 11; j++)
      podrucje[i][j] = 0.0;
}

which would be called as

init(podrucje, 123);

The drawback to this method is that the function can only operate on Nx11 arrays; if you're using a C99 compiler or a C2011 compiler that supports variable length arrays, you could specify the number of columns as a runtime variable:

void foo(void)
{
  size_t rows = 123, cols = 11;
  double (*podrucje)[cols] = malloc(sizeof *podrucje * rows);
  if (podrucje)
    init(cols, podrucje, rows);
  ...
}

// cols must be declared before it can be used
// in an array declarator
//
void init(size_t cols, double(*podrucje)[cols], size_t rows)
{
  size_t i, j;
  for (i = 0; i < rows; i++)
    for (j = 0; j < cols; j++)
      podrucje[i][j] = 0.0;
}

When you're done with the array, deallocate it as follows:

free(podrucje);

The other approach is to allocate each row separately, as follows:

size_t rows = 123, cols = 11;
double **podrucje = malloc(sizeof *podrucje * rows);
if (!podrucje)
{
  // malloc failed; handle allocation error here
}
else 
{
  size_t i;
  for (i = 0; i < rows; i++)
  {
    podrucje[i] = malloc(sizeof *podrucje[i] * cols);
    if (!podrucje[i])
    {
      // malloc failed; handle allocation error here
    }
  }
}

And you would use it in a function as follows:

void foo()
{
  double **podrucje;
  // allocate array as above
  init(foo, rows, cols);
  ...
}

void init(double **podrucje, size_t rows, size_t cols)
{
  size_t i, j;
  for (i = 0; i < rows; i++)
    for (j = 0; j < cols; j++)
      podrucje[i][j] = 0.0;
}

When you're finished with the array, deallocate it as follows:

for(i = 0; i < rows; i++)
  free(podrucje[i]);
free(podrucje);

The first method allocates memory as a single, contiguous block; the second allocates it in a series of smaller, discontinuous chunks. If your array is especially big or your heap especially fragmented, the first method may fail where the second will succeed. If you're working with a compiler that doesn't support variable-length arrays, the first method is much less flexible, because the number of columns must be specified at compile time.

How could the same indexing method work for both forms?

In the first case, each podrucje[i] is an 11-element array of double; indexing it with j works like any other array. In the second case, each podrucje[i] is a pointer to double. Since a[i] is evaluated as *(a + i), array indexing works on pointer expressions just as well as array expressions.

Upvotes: 0

Jens Gustedt
Jens Gustedt

Reputation: 78923

If you have a modern C compiler (C99 would do) you can even declare real 2D matrices with variable sizes. You don't need to fall back to this awful emulation with pointers.

void myfunc(size_t n, size_t m, double podrucje[n][m])
{
    ...
}

double (*podrucje)[n] = malloc(sizeof(double[n][m]));
myfunc(n, m, podrucje);

For the function you just have to ensure that the declarations of n and m come first, before the matrix.

Upvotes: 0

Nathan
Nathan

Reputation: 672

In the following code snippet,

podrucje[i]=(double *) malloc (sizeof (double) * 11);
for (i=0;i<(123);i++)
{   
    memset (podrucje[i], 0, 10);
} 

1) You dont need the extra parenthesis against the numbers 123 and 11 The for loop can be as follows,

for (i = 0; i < 123; i++)

2) Instead of using 123 and 11. Try to define a MACRO and use that instead.

Advantage: The code becomes independent of special numbers and is easily maintainable. Especially in the cases of larger code base.

3) If you read the code, podrucje[i] is allocated a memory of 11 doubles But when you memset you are setting it for only 10 doubles while the last one may or may not consist of garbage. Use calloc here, It not only allocated memory but also initializes the same.

podrucje[i]=(double *) calloc(11,sizeof(double));

Also It could be more helpful if you could tell How exactly is it screwing up your code ? Example, Code Snippet could help more than just stating its screwing up. It helps others to investigate and solve the issue.

Upvotes: 0

lxop
lxop

Reputation: 8595

You're best off to use malloc, but allocate the whole array on your second line, so it all gets allocated in contiguous memory. So

podrucje = (double*) malloc (sizeof (double) * 123 * 11);

Then the first loop can go away too. And it looks like you're initializing the array to 0 -- in that case, use calloc instead of malloc, eliminating the second loop.

To index into the array, use things like

double myitem = podrucje [11 * row + col];

You should of course use a define or similar to keep the use of 11 consistent, but that's not the point of this answer.

Upvotes: 1

Samy Vilar
Samy Vilar

Reputation: 11130

memset works on per byte basis.

double **podrucje = (double **) malloc (sizeof (double *) * 123);
for (i = 0; i < 123; i++)
{                       
    podrucje[i] = (double *) malloc (sizeof (double) * 11);
    memset(podrucje[i], 0, sizeof(double) * 11);
}

if you want to pass it just declare it as such

void function(double podrucje[123][11]) {
    ...
}

Upvotes: 2

dave
dave

Reputation: 13280

Write the function argument the same way you wrote the variable definition:

void myfunc(double podrucje[123][11])
{
    ...
}

double podrucje[123][11];
myfunc(podrucje);

Note that the array is passed "by reference" rather than being copied.

Upvotes: 0

Related Questions