我是指针的新手,我正在尝试实现一个简单的代码,我在其中读取和编写一个2D数组,但我不知道为什么这不起作用。有人会提出任何建议吗?
#include<stdio.h>
#include<stdlib.h>
int read_matr(int ***m, FILE *f){
int i,j,length,a;
fscanf(f,"%d",&length);
*m = (int **)malloc(length*sizeof(int));
for(i=0;i<length;++i)
for(j=0;j<length;++j){
fscanf(f,"%d",&a);
*(*(m+i)+j) = a;
}
return length;
}
void write_matr(int *m[][3], int length, FILE *g){
int i,j;
for(i=0;i<length;++i){
for(j=0;j<length;++j)
fprintf(g,"%d ",*(*(m+i)+j));
fprintf(g,"\n");
}
fprintf(g,"\n");
}
int main(){
FILE *f = fopen("datein.txt","r");
FILE *g = fopen("dateout.txt","w");
int **m, n = read_matr(m,f);
write_matr(m,n,g);
free(m);
return 0;
}
答案 0 :(得分:2)
要在现代C中正确分配2D数组,您可以这样做:
int (*array)[x][y] = malloc( sizeof(int[x][y]) );
可以简化为方便起见:
int (*array)[y] = malloc( sizeof(int[x][y]) );
要在古代版本的C(C90 / ANSI-C)中正确分配2D数组,您可以使用&#34;受损阵列&#34;:
int* array = malloc(x*y*z*sizeof(int));
以上是仅方式在C中动态分配真正的2D数组。基于指针指针的任何东西都不是2D数组,也不能用作一个。这是因为这样的指针指向&#34;事物&#34;遍布整个堆。它们很慢而且不必要地复杂。
答案 1 :(得分:1)
我建议您查看编译器警告。这段代码中有很多内容。在这些帮助下,您应该能够自己解决一些问题。
我得不到的。您定义int **m
并将其初始化为函数read_matr(int ***m, FILE *f)
,但在这种情况下您需要的是read_matr(&m, f);
修改强>
所以这里只是你犯的一些错误。
请不强制转换指针malloc返回。
int **m;
*m = malloc(length*sizeof(int));
请注意,您得到的是指向已分配内存的指针。这不等于m[][]
。如果你想以自己的方式分配2D数组,你应该这样做:
int **m;
int rows, cols;
*m = malloc(sizeof(rows) * rows);
for(int i = 0; i < rows; i++){
m[i] = malloc(sizeof(cols) * cols);
}
请参阅:Using malloc for allocation of multi-dimensional arrays with different row lengths
答案 2 :(得分:1)
提供的代码至少存在两个问题。 :
您正在传递一个** int变量作为read_matr的第一个参数,但是此函数正在请求一个*** int参数(一个指向二维数组的指针)。参数似乎是正确的,但是你需要以这种方式将指针传递给你的数组:
int n = read_matr(&m, f);
您的数组应该是二维的,但您只是将其分配为一维数组。分配第一个数组后,您需要独立分配每一行:
*m = (int **) malloc(length * sizeof(int*));
for(i=0; i<length; ++i) {
(*m)[i] = (int*) malloc(length * sizeof(int));
...
}
或者,您可以创建一个大小为*长度的1维数组,然后您将访问m[i][j] by m[i * length + j]
警告本可以为你提供很多帮助。
答案 3 :(得分:0)
我的第一个建议是将内存管理与I / O分开。首先创建矩阵,一旦验证成功,然后读取您的输入。
我的第二个建议是使用常规下标符号(m[i][j]
)而不是显式指针解引用(*(*(m + i) + j)
)。更容易阅读,更难出错。
最后,当你以这种方式分配内存时,你必须分别为每一行分配内存:
void createMatrix( int ***m, size_t length )
{
*m = malloc( sizeof **m * length );
if ( !*m )
{
// memory allocation error, bail out here
return;
}
size_t i;
for ( i = 0; i < length; i++ )
{
/**
* Postfix [] has higher precedence than unary *, so *m[i] will be
* parsed as *(m[i]) - it will index into m and dereference the result.
* That's not what we want here - we want to index into what m
* *points to*, so we have to explicitly group the unary * operator
* with m and index into the result.
*/
(*m)[i] = malloc( sizeof *(*m)[i] * length );
if ( !(*m)[i] )
break;
}
if ( i < length )
{
// memory allocation failed midway through allocating the rows;
// free all previously allocated memory before bailing out
while ( i-- )
free( (*m)[i] );
free( *m );
*m = NULL;
}
}
假设您将其称为
int **m;
createMatrix( &m, 3 ); // note & operator on m
你结束了这样的事情:
+---+ +---+
m[0] | | ---------------------------------------> m[0][0] | |
+---+ +---+ +---+
m[1] | | ---------------------> m[1][0] | | m[0][1] | |
+---+ +---+ +---+ +---+
m[2] | | ----> m[2][0] | | m[1][1] | | m[0][2] | |
+---+ +---+ +---+ +---+
... m[2][1] | | m[1][2] | | ...
+---+ +---+
m[2][2] | | ...
+---+
...
这不是真正的2D数组 - 行不是连续的。紧随m[0][2]
之后的元素不 m[1][0]
。您可以将它索引为它是一个2D数组,但就是它。
有时这不是错误的答案。根据堆的碎片程度,单个N
x M
分配请求可能会失败,但N
M
的单独分配可能会成功。如果您的算法不依赖于所有连续的元素,那么这将起作用,尽管它可能比使用真正的N
x M
数组慢。
如果你想要一个真正的,连续的2D数组,其维度直到运行时才知道,那么你需要一个支持可变长度数组(VLA)的编译器,你可以按如下方式分配它:
size_t length = get_length_from( f );
int (*m)[length] = malloc( sizeof *m * length ); // sizeof *m == sizeof (int [length])
m
是length
- int
元素数组的指针,我们为length
这样的数组分配了足够的内存。假设length
再次为3,你会看到这样的东西:
+---+
m[0][0] | |
+---+
m[0][1] | |
+---+
m[0][2] | |
+---+
m[1][0] | |
+---+
m[1][1] | |
+---+
m[1][2] | |
+---+
m[2][0] | |
+---+
m[2][1] | |
+---+
m[2][2] | |
+---+
如果VGA不可用(早于C99或C2011的版本,其中__STDC_NO_VLA__
已定义)和您希望所有数组元素都是连续的,那么您将不得不分配它作为一维数组:
size_t length = 3;
int *m = malloc( sizeof *m * length * length );
您可以设置一个额外的指针数组假装 m
是一个2D数组:
int *q[] = { &m[0], &m[3], &m[6] };
所以
q[0][0] == m[0];
q[0][1] == m[1];
q[0][2] == m[2];
q[1][0] == m[3];
q[1][1] == m[4];
...
等