dynamic allocation of 2d array function

江枫思渺然 提交于 2019-12-13 10:05:12

问题


So I have a program in C structured in 3 files: main.c, alloc.h and alloc.c. In the main.c function, I have the declaration of a pointer to another pointer to which I intend to alloc an n * m array:

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

int main() {
   int **mat, n, m;
   alloc_matrix(&mat, int &n, int &m);
   return 0;
}

In alloc.c I have the following declarations:

#ifndef ALLOC_H_INCLUDED
#define ALLOC_H_INCLUDED
#include <stdio.h>
#include <stdlib.h>
void alloc_matrix(int***, int*, int*);
#endif

In alloc.c I have the function:

void alloc_matrix(int ***mat, int *n, int *m) {
    printf("\nn = "); scanf("%d", n);
    printf("\nm = "); scanf("%d", m);
    *mat = (int**)calloc(*n, sizeof(int*));
    int i;
    for (i = 0; i < *n; i++)
        *(mat + i) = (int*)calloc(*m, sizeof(int));
}

But the program doesn't work. It enters some kind of loop and doesn't end. If I allocate it in main it would work but I have no idea what I am doing wrong in the alloc function.


回答1:


Here is the correct code. Your error was that in the definition of alloc_matrix, you used *(mat+i) in the allocation loop, which should be *(*mat+i) as, mat is a int*** so the base address for the 2D array would be in *mat. Then you need to move by offset i and then de-reference that memory location for the 1D array.

Main:

#include <stdio.h>
#include <stdlib.h>
#include "alloc.h"
int main()
{
   int **mat,n,m;
   alloc_matrix(&mat,&n,&m);
   return 0;
}

alloc.h

#ifndef ALLOC_H_INCLUDED
#define ALLOC_H_INCLUDED
#include <stdio.h>
#include <stdlib.h>
void alloc_matrix(int***,int*,int*);

#endif

alloc.c :

void alloc_matrix(int ***mat,int *n,int *m)
{
    printf("\nn = "); scanf("%d", n);
    printf("\nm = "); scanf("%d", m);
    *mat = (int**)calloc(*n,sizeof(int*));
    int i;
    for(i = 0; i < *n; i++)
    *(*mat+i) = (int*)calloc(*m,sizeof(int));
}

The code for the read function :

void read_matrix(int ***mat,int n,int m)
    {
      int i,j;
      for(i = 0; i < n; i++)
       for(j = 0; j < m; j++)
        {
          printf("mat[%d][%d] = ", i, j);
          scanf("%d", (*(*mat+i))+j);
        }
    }

The problem with it is that it only reads the first row and the it freezes.




回答2:


void alloc_matrix(int ***mat,int *n,int *m)

There are two problems in this line. Neither is fatal but both are worth fixing.

First problem: A matrix in this program is represented as an int**. Why does alloc_matrix accept an int***? All standard functions that allocate something (malloc and friends) return a pointer to that something. This is an idiomatic way of doing things in C. It reduces your star count (being a three-star C programmer is not an achievement to be proud of) and simplifies the code. The function should be changed to

int** alloc_matrix( // but what's inside the () ?

The second problem is, why should a function called alloc_matrix prompt the user and read values? These things are not related to allocation. A function should do one thing and do it well. Does malloc prompts you to enter the size? Does fopen prompt you to enter the filename? These things would be regarded as nonsense of the first degree, and rightly so. It is advised to read the sizes elsewhere and pass them to alloc_matrix as input arguments. Hence,

int** alloc_matrix(int n, int m) { // but what's inside the {}?

What remains of alloc_matrix is simple:

int** alloc_matrix(int n, int m) {
  int** mat; // that's what we will return
  int i;
  mat = (int**)calloc(n, sizeof(int*));
  for(i = 0; i < n; i++)
     // here comes the important part.

Since we have simplified alloc_matrixand reduced the star count in mat, what should we do with the old body of the loop? It was:

    *(mat+i) = (int*)calloc(...);

but if we remove a star, it becomes

    (mat+i) = (int*)calloc(...);

which is an obvious nonsense. Perhaps the old line was a problem. The fact that it provoked a compiler warning certainly doesn't speak for its correctness. So how to correct it? There aren't too many options. It turns out that in order to restore sanity, we must leave the old left-hand side (written for the three-star mat) intact. Or, better still, use an equivalent but more idiomatic notation:

    mat[i] = (int*)calloc(m, sizeof(int));

So the entire function now becomes

int** alloc_matrix(int n, int m) {
  int **mat;
  int i;
  mat = (int**)calloc(n, sizeof(int*));
  for(i = 0; i < n; i++)
    mat[i] = (int*)calloc(m, sizeof(int));
  return mat; 
}

and it should be called like

mat = alloc_matrix(n, m);

It is often said that one should not cast the result of calloc and friends. But in this case the cast has enabled a warning which helped to find a bug. I'm leaving the casts in place for now.

There is another idiom for the allocation that does not require the cast, but also avoids the problem of types not matching. Instead of using the type for the sizeof, you can use the dereferenced pointer as the type information is available in the variable:

mat = (int**)calloc(n, sizeof(int*));

can be changed to

mat = calloc(n, sizeof *mat); //sizeof is an operator not a function


来源:https://stackoverflow.com/questions/40854155/dynamic-allocation-of-2d-array-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!