二维数组函数的动态分配

dynamic allocation of 2d array function

所以我有一个 C 语言的程序,分为 3 个文件:main.calloc.halloc.c。在 main.c 函数中,我声明了一个指向另一个指针的指针,我打算将其分配给一个 n * m 数组:

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

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

alloc.c中我有以下声明:

#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));
}

但是程序不工作。它进入某种循环并且不会结束。 如果我在 main 中分配它,它会起作用,但我不知道我在 alloc 函数中做错了什么。

这是正确的代码。你的错误是在 alloc_matrix 的定义中,你在分配循环中使用了 *(mat+i),它应该是 *(*mat+i) 因为,mat 是一个 int*** 所以基地址为二维数组将在 *mat 中。然后你需要移动偏移量i,然后取消引用一维数组的内存位置。

主要:

#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));
}

读取函数的代码:

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);
        }
    }

它的问题是它只读取第一行并且它冻结了。

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

这一行有两个问题。两者都不是致命的,但都值得修复。

第一个问题:这个程序中的矩阵表示为int**。为什么 alloc_matrix 接受 int***?所有分配东西的标准函数(malloc 和朋友)return 一个指向那个东西的指针。这是在 C 语言中惯用的做事方式。它减少了您的星数(成为三星级 C 程序员并不是什么值得骄傲的成就)并简化了代码。函数应该改为

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

第二个问题是,为什么一个名为 alloc_matrix 的函数要提示用户并读取值?这些东西与分配无关。一个函数应该做一件事并且把它做好。 malloc 是否提示您输入尺寸? fopen 是否提示您输入文件名?这些事情将被视为一流的胡说八道,这是正确的。建议阅读别处的大小并将它们作为输入参数传递给alloc_matrix。因此,

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

alloc_matrix 剩下的很简单:

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.

既然我们简化了 alloc_matrix 并减少了 mat 中的星数,我们应该如何处理旧的循环体?它是:

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

但是如果我们去掉一颗星,它就会变成

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

这明显是胡说八道。也许旧线是个问题。它引起编译器警告的事实当然不能说明它的正确性。那么如何纠正呢?没有太多选择。原来,为了恢复理智,我们必须保持旧的左手边(为三星级mat写的)完好无损。或者,更好的是,使用等效但更惯用的表示法:

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

所以整个函数现在变成了

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; 
}

应该这样称呼

mat = alloc_matrix(n, m);

常说不投calloc和朋友的结果。但在这种情况下,演员表启用了警告,这有助于找到错误。我暂时将演员表留在原地。

分配还有一个成语,不需要强制转换,也避免了类型不匹配的问题。 您可以使用解除引用的指针,而不是使用 sizeof 的类型,因为类型信息在变量中可用:

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

可以改成

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