【问题标题】:Returning a matrix from a fuction in C从 C 中的函数返回矩阵
【发布时间】:2016-12-06 01:58:12
【问题描述】:

我正在编写一个程序,我必须在函数中不断使用矩阵,这是众多函数之一,该函数应该打开一个外部文件,该文件是一个数据集,其中数据与表格,它打开文件并将数据保存在矩阵 M 中,我知道这个矩阵由 6 列组成,但行号未知,我知道错误是我声明矩阵的地方,它必须用指针声明因为函数返回矩阵。

//type float** since it will return a matrix
float **carga_archivo(char *nombre_archivo)       
{
  float **M=(float **)malloc(6*sizeof(float*));  //error should be here
  int i=0;
  FILE *archivo;                      //FILE type pointer to open the external file
  archivo=fopen(nombre__archivo,"r"); //Opens the file in the address indicated
                                      //"nombre_de_archivo" is a variable
  while(!feof(archivo))               //Browses the file row per row till the end of it
  {
      //saves the data in its corresponding place in the matrix
      fscanf(archivo,"%f\t%f\t%f\t%f\t%f\t%f\n",
          &M[0][i],&M[1][i],&M[2][i],&M[3][i],&M[4][i],&M[5][i]);
      i++;
  }
  tam=i;
  fclose (archivo);                  //closes the file
  return M;
}

我需要的是正确的方式来声明矩阵。

附:我记录了代码中的主要内容,以防它可以帮助需要类似内容的人。

欢迎大家指正。

更新: 应用了 cmets 中提出的一些更改,并且效果更好,这是我为该功能编写的新代码

float **carga_archivo(char *nombre_archivo)
{
int i=0;
float P[300][6];
FILE *archivo;
archivo=fopen(nombre_archivo,"r");
 while(!feof(archivo))
{
i++;
       //this was just so the feof function could browse row per row 
       //instead of character per character
    scanf("%f\t%f\t%f\t%f\t%f\t%f\n",
               &P[0][i],&P[1][i],&P[2][i],&P[3][i],&P[4][i],&P[5][i]);
    printf("%i\n",i);
}
tam=i;
printf("%i",tam);
int filas = 6;
int columnas = tam;
float **M;

M = (float **)malloc(filas*sizeof(float*));

for (i=0;i<filas;i++)
    M[i] = (float*)malloc(columnas*sizeof(float));

for (i = 0; i < columnas; ++i)
    fscanf(archivo,"%f\t%f\t%f\t%f\t%f\t%f\n",
             &M[0][i],&M[1][i],&M[2][i],&M[3][i],&M[4][i],&M[5][i]);
fclose (archivo);
return M;
}

新的问题是当函数被调用时,程序实际上可以编译,但是当它运行并且函数被调用时,程序崩溃并停止。 这是调用该函数的代码部分。

int main()
{
int i,j;
char *nombre_archivo="Agua_Vapor.txt";
float **agua_vapor=carga_archivo(nombre_archivo);
for (i = 0; i < 6; i++)
{
    for (j = 0; i < tam; i++)
        printf("%f   ", agua_vapor[i][j]);
    printf("\n");
}
return 0;
}

【问题讨论】:

  • char nombre_archivo 是错误的。一个文件名有多个字符。此外,如果行数未知 - 您需要将该信息返回给调用者,可能作为返回值(同时传递一个指向函数的指针,该函数将在函数返回后指向浮点数组。跨度>
  • 谢谢,我刚刚编辑了你提到的第一个问题,但我想我在第二部分没有关注你,我对指针不是很熟悉,也许一个例子可以帮助我小
  • 如果您事先不知道行数,则需要至少扫描文件一次以获得该数字,然后分配 total 需要存储数据的内存量,然后将文件中的数据读取到矩阵中。这需要通读文件两次。
  • 要添加到 Evert 的答案中,您可以读取文件一次,但必须将数据存储在本地存储中。您可以定义一个单独的函数,该函数可以将值添加到动态增长的数组中。一旦从文件复制完成。分配一个二维数组 [row][column] 并复制内容。
  • 注意:对于矩阵,您可能希望将 N x M 内存单元分配为 linear 数组,而不是 N 列,每列都指向单行 (产生一个指向指针的指针)。

标签: c matrix


【解决方案1】:

您的程序具有未定义的行为,因为您正在填充未初始化指针引用的内存。

由于您知道总是有 6 列,因此一种简单的方法是将矩阵存储为行优先而不是列优先(您的示例是列优先)。这意味着您可以将矩阵数据存储为一大块内存,并在必要时使用realloc。您可能也想为此制作一个简单的结构。

struct matrix {
    int rows, cols;
    float ** data;
};

然后动态创建。

struct matrix * matrix_alloc( int rows, int cols )
{
    int i;

    struct matrix * m = malloc(sizeof(struct matrix));
    m->rows = rows;
    m->cols = cols;
    m->data = malloc(rows * sizeof(float*));
    m->data[0] = malloc(rows * cols * sizeof(float));

    for( i = 1; i < rows; i++ ) {
        m->data[i] = m->data[i-1] + cols; 
    }
    return m;   
}

void matrix_free( struct matrix * m )
{
    free( m->data[0] );
    free( m->data );
    free( m );
}

现在,当您决定需要为更多行添加存储空间时:

void matrix_set_row_dimension( struct matrix * m, int rows )
{
    float **new_index, *new_block;
    new_index = realloc(m->data, rows * sizeof(float**));
    new_block = realloc(m->data[0], rows * m->cols * sizeof(float));
    if( new_index && new_block )
    {
        int i = m->rows;
        m->rows = rows;
        m->data = new_index;

        /* if block address changed, prepare to reindex entire block */
        if( m->data[0] != new_block )
        {
            m->data[0] = new_block;
            i = 1;
        }

        /* reindex */
        for( ; i < rows; i++ ) {
            m->data[i] = m->data[i-1] + cols;
        }
    }
}

所以,现在当您填充矩阵时...

struct matrix * m = matrix_alloc( 10, 6 );  /* Start with 10 rows */
int row = 0;
while( 1 ) {
    /* Double matrix row count if not large enough */
    if( row == m->rows )
    {
        matrix_set_row_dimension( m, m->rows * 2 );

        /* Check for error here */
    }

    /* Now the matrix has enough storage to continue adding */
    m->data[row][0] = 42;
    m->data[row][1] = 42;
    m->data[row][2] = 42;
    m->data[row][3] = 42;
    m->data[row][4] = 42;
    m->data[row][5] = 42;

    row++;     
}

【讨论】:

  • 注意:这不是硬化代码。需要正确处理所有重新分配失败的情况,以及处理初始分配失败。这里的代码纯粹是为了说明一种合理的方法。
  • 注意:m-&gt;data[0] = malloc(sizeof(float) * rows * cols);m-&gt;data[0] = malloc(rows * cols * sizeof(float)); 有一个小的优势,因为 sizeof(float) * rows * cols 通常不会在 rows * cols * sizeof(float) 时立即溢出。
猜你喜欢
  • 1970-01-01
  • 2021-05-11
  • 1970-01-01
  • 2012-12-14
  • 2013-03-30
  • 2018-02-25
  • 2013-04-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多