【问题标题】:Dynamic allocation of an unknown matrix in CC中未知矩阵的动态分配
【发布时间】:2018-04-24 08:53:41
【问题描述】:

我需要获取用户输入的文件并将其乘以另一个文件。我知道该怎么做。

问题是一个文件是数组,另一个是矩阵。

我需要扫描矩阵的第一行以找到矩阵的大小,然后我需要从文件中动态分配矩阵和数组。

这是我目前所拥有的:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int main()
{       
    int row1, col1;
        //These values need to be pulled from the first file//
    char filename1[100];
        //Setting the file name for entry and setting the limit to 100//
    FILE* fp1;
        //FILE must be set as a pointer (FILE must also be capitalized)//

    printf("Enter file name including file extension: \n");
        //This will pull in the name entered by the user//
    scanf("%s", filename1);
        //Scans in the name of the first file//

    fp1 = fopen(filename1, "r");
        //This will open the file as entered by the user//
    if (fp1 == NULL)
    {
        printf("\nError, file not found\n");
        exit(0);
    }
        //This is for the first file//

    char filename2[100];
        //Setting the file name for entry and setting the limit to 100//
    FILE* fp2;
        //FILE must be set as a pointer (FILE must also be capitalized)//

    printf("Enter file name including file extension: \n");
        //This will pull in the name entered by the user//
    scanf("%s", filename2);
        //Scans in the name of the first file//

    fp2 = fopen(filename2, "r");
        //This will open the file as entered by the user//
    if (fp2 == NULL)
    {
        printf("\nError, file not found\n");
        exit(0);
    }
        //This is for the second file//

        //**I need to now dynamically allocate the input files**//

    return 0;
} 

也很抱歉,我似乎在发布我的问题后才离开,因为一些成员在 cmets 中分享说我在钓鱼。我不是;我只是没有意识到这个社区有多活跃。感谢您到目前为止的输入。

Here is the screenshot of all I have so far including the files that are going to be read in.

感谢您的建议。我能够找出“fgets”函数,并用它从第一个文件中提取矩阵的大小。有了它之后,动态分配就很容易了。

【问题讨论】:

  • 显示输入文件的内容
  • 如果你能给出一个最小的可重现的例子会更容易提供帮助。
  • 到目前为止,您已经打开了文件...了解数组不是矩阵矩阵不是数组。 C 中没有 matrix 的定义。您可以选择任何方式来管理和索引存储的数字。通常,如果您在每行动态分配未知数量的元素 - 您将使用指向指针类型的指针,分配 X 指针,然后为每行中的任意数量的值分配存储(验证您从文件中的每一行读取相同的数字),根据需要重新分配指针的数量。
  • @DavidC.Rankin.:我不知道为什么,但我多次观察到 1 个代表用户提出问题 - 然后他们不互动。现在,如果您很幸运能够正确了解问题,那么您将给出解决方案。 OP 将在 3-4 小时后出现 - 将检查哪个提供解决方案(烘焙代码)并使用它。这有时真的非常非常烦人。
  • @coderredoc 我认为这可能与钓鱼代码的历史悠久的闪避有关。这个比大多数人更“填补空白......”。我不知道 - 也许我读错了问题......

标签: c arrays matrix memory-management dynamic-memory-allocation


【解决方案1】:

我的建议是将您的矩阵视为具有您想要实施的一些abstract data type

一种常见的方法可能是使用指针数组(指向表示矩阵行的数组)。但我觉得它是混乱和低效的。

那么您希望对矩阵进行哪些操作?

  • 创建一个给定维度的矩阵

  • 销毁之前创建的矩阵

  • 使用给定的行和列索引访问给定矩阵中的某些元素

  • 使用给定的行和列索引更改给定矩阵中元素的值

  • 等等……

顺便说一句,您可能有几种变体。例如,您可以进行错误检查(例如拒绝负索引),或者您可以使用不安全(但速度稍快)的函数来支持undefined behavior(这非常适合scary)。当然你可以定义更多的操作(使用其他的),例如矩阵乘法等。

您应该在纸上或白板上列出-所有您想要对矩阵进行的操作,并在您的文档(或您的 cmets)中解释它们。在实践中,您可能对抽象数据类型进行数十甚至数百次操作。还要记录在错误情况下会发生什么。

我通常建议将维度与矩阵保持一致(除非您知道某些维度是常数)。在 C 中实现抽象数据类型的一种常见方法是将它们封装在一些 struct 中并使用指向这些的指针。

所以我建议使用flexible array member(作为structlast 元素)。这是我的matrix_st 结构:

  struct matrix_st {
    unsigned m_h, m_w; // height and width of matrix
    double m_v[]; // values inside the matrixes, there are m_h*m_w of them
  };

所以我的抽象数据类型只是指向

的指针
  typedef struct matrix_st Matrix;

以下是实现我的抽象数据类型的函数的声明:

  Matrix* matrix_create(unsigned height, unsigned width);
  void matrix_destroy(Matrix*mat);
  double matrix_access(Matrix*mat, unsigned i, unsigned j);
  void matrix_change_element(Matrix*mat, unsigned i, unsigned j,double v);

这里有一些实现(因为我不想处理病态的巨大矩阵,所以我定义了一些最大维度;计算机资源总是有限的!):

  #define MATRIX_MAXDIM 10000000 /* ten millions */
  Matrix* matrix_create(unsigned height, unsigned width) {
     if (height>MATRIX_MAXDIM || width>MATRIX_MAXDIM) {
        fprintf(stderr, "too huge matrix height=%u width=%u\n",
                height, width);
        exit(EXIT_FAILURE);
     };
     Matrix* res = 
        calloc(1, sizeof(Matrix) + height*width*sizeof(double));
     if (!res) {
         perror("matrix calloc");
         exit(EXIT_FAILURE);
     };
     res->m_h = height;
     res->m_w = width;
     return res; 
  } // end matrix_create

我使用的是calloc 而不是malloc,因为我真的想要一些零内存。所以返回的矩阵包含全零。顺便说一句,在某些计算机上(不是我的,PC/Linux/Debian/x86-64 桌面)height*width*sizeof(double) 可能会溢出。

这是访问某些元素的函数。它会进行一些错误检查。

double matrix_access(Matrix*mat, unsigned i, unsigned j) 
{ 
   if (!mat) 
      { fprintf(stderr, "no matrix to access\n"); exit(EXIT_FAILURE; };
   unsigned h = mat->m_h;
   unsigned w = mat->m_w;
   if (i >= h || j >= w)
      { fprintf(stderr, "out-of-bound matrix access\n"); 
        exit(EXIT_FAILURE); };
   return mat->m_v [i*h + j];
}

由于我只制作了一个calloc,因此销毁代码很简单:

  void matrix_destroy(Matrix*mat) {
    if (!mat) { fprintf(stderr, "no matrix to destroy\n"); exit(EXIT_FAILURE); };
    assert (mat->m_h < MATRIX_MAXDIM);
    assert (mat->m_w < MATRIX_MAXDIM);
    free (mat);
  }

assert 语句原则上是无用的(它们检查应该始终为真的东西)。但我喜欢defensive programming(这将有助于我在一些其他地方误用我的Matrix 来捕捉错误)。它们可以在编译时被禁用(阅读assert(3))。

顺便说一句,您可以将这些函数声明为inlinestatic inline(并在某些包含的头文件中定义它们)。 optimizing compiler 可能会产生高效的代码(例如,在进行基准测试时编译 with gcc -O2 -Wall -march=native)。

由于您正在从某个文件中读取矩阵,因此您应该定义您的 file format(在您的文档中使用一些 EBNF 符号来描述该文件中的语法很有用)并且您可以定义和实现一个函数从一些打开的文件句柄中读取和创建矩阵。


编写其他函数作为练习留给读者。

不要忘记编译with所有警告和调试信息,所以gcc -Wall -Wextra -gGCC使用调试器gdb(以及valgrind 寻找memory leaks)。阅读每个使用函数的documentation(例如,您的代码不检查scanf 的返回计数,但它确实应该检查)。运行几个test cases。试着说服自己你的代码是好的(通过证明它的一部分)。也许使用一些static source code analyzer(例如Frama-C,它需要在ACSL 中添加额外的注释)。如果您需要benchmark 您的程序,请在编译时启用optimizations(例如,通过将-O2 -march=native 传递给gcc ....)。


在您询问的代码注释中:

 // I need to now dynamically allocate the input files

您不分配输入 filesoperating system 正在管理它们),您分配了一些 内存区域。阅读C dynamic memory allocation。请注意,内存分配可能会失败(例如,如 malloc(3) 中所述),因为您的 virtual address space 不能无限增长。

顺便说一句,call stack 是有限的(在台式计算机上通常为 1 MB 或几个),因此您通常希望避免使用大的automatic variables,这是避免在调用中放置矩阵的另一个好理由框架并更喜欢为它们分配动态内存。

【讨论】:

    【解决方案2】:

    我看不到您实际读取行/列计数的位置,但是一旦有了它们,分配就很简单了:

    int (*matrix)[columnCount] = malloc(rowCount*sizeof(*matrix));
    

    就是这样。这将matrix 声明为指向columnCount 整数数组的指针*matrix。括号是必要的,因为int* matrix[...] 将声明一个指针数组。 malloc()rowCount 这样的数组分配空间,在一块内存中为您提供完整的二维矩阵。访问与任何二维数组一样:

    for(int y = 0; y < rowCount; y++) {
        for(int x = 0; x < columnCount; x++) {
            matrix[y][x] = 42;
        }
    }
    

    释放就像分配一样简单:

    free(matrix);
    

    【讨论】:

    • 顺便说一句,你的第一行代码值得解释一下。
    • @BasileStarynkevitch 是的。我写这篇文章的时候有点着急。我现在添加了一个简短的解释,希望它足够了。
    猜你喜欢
    • 2023-03-03
    • 1970-01-01
    • 2021-10-13
    • 1970-01-01
    • 2018-01-29
    • 2016-09-12
    • 2011-12-15
    • 2013-01-11
    • 1970-01-01
    相关资源
    最近更新 更多