二维数组函数的动态分配
dynamic allocation of 2d array function
所以我有一个 C 语言的程序,分为 3 个文件:main.c、alloc.h 和 alloc.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
所以我有一个 C 语言的程序,分为 3 个文件:main.c、alloc.h 和 alloc.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