指针和2D数组的问题(内存的动态分配)

时间:2017-01-27 14:43:12

标签: c arrays pointers

我是指针的新手,我正在尝试实现一个简单的代码,我在其中读取和编写一个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;
}

4 个答案:

答案 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);

修改

所以这里只是你犯的一些错误。

  1. 强制转换指针malloc返回。

    int **m;
    *m = malloc(length*sizeof(int));
    
  2. 请注意,您得到的是指向已分配内存的指针。这不等于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])

mlength - 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];
...