C中未知矩阵的动态分配 [英] Dynamic allocation of an unknown matrix in C

查看:37
本文介绍了C中未知矩阵的动态分配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要将用户输入的文件乘以另一个文件.我知道该怎么做.

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

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

这是我目前所拥有的:

#include #include #include <math.h>#include int main(){int row1, col1;//这些值需要从第一个文件中拉取//字符文件名1[100];//设置入口的文件名并设置限制为100//文件* fp1;//FILE 必须设置为指针(FILE 也必须大写)//printf("请输入包含文件扩展名的文件名:\n");//这将拉入用户输入的名称//scanf("%s", 文件名 1);//扫描第一个文件名//fp1 = fopen(filename1, "r");//这将打开用户输入的文件//如果(fp1 == NULL){printf("\n错误,找不到文件\n");退出(0);}//这是第一个文件//字符文件名2[100];//设置入口的文件名并设置限制为100//文件* fp2;//FILE 必须设置为指针(FILE 也必须大写)//printf("请输入包含文件扩展名的文件名:\n");//这将拉入用户输入的名称//scanf("%s", filename2);//扫描第一个文件名//fp2 = fopen(filename2, "r");//这将打开用户输入的文件//如果(fp2 == NULL){printf("\n错误,找不到文件\n");退出(0);}//这是第二个文件////**我现在需要动态分配输入文件**//返回0;}

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

这是我目前所有的截图,包括将要读取的文件在.

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

解决方案

我的建议是考虑你的矩阵有一些 您要实现的抽象数据类型.

一种常见的方法可能是使用指针数组(指向表示矩阵行的数组).但我觉得这很混乱,而且效率低下.

那么您想要对矩阵进行哪些操作?

  • 创建给定维度的矩阵

  • 销毁之前创建的矩阵

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

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

  • 等等....

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

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

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

所以我建议使用灵活的数组成员(作为最后一个<struct 的/em> 元素).这是我的 matrix_st 结构:

 struct matrix_st {无符号 m_h, m_w;//矩阵的高度和宽度双 m_v[];//矩阵内的值,有 m_h*m_w 个};

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

的指针

 typedef struct matrix_st 矩阵;

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

 Matrix* matrix_create(无符号高度,无符号宽度);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/* 千万 */矩阵* matrix_create(无符号高度,无符号宽度){如果(高度> MATRIX_MAXDIM || 宽度> MATRIX_MAXDIM){fprintf(stderr, "太大的矩阵高度=%u 宽度=%u\n",高度宽度);退出(EXIT_FAILURE);};矩阵* res =calloc(1, sizeof(Matrix) + height*width*sizeof(double));如果(!res){perror("矩阵调用");退出(EXIT_FAILURE);};res->m_h = 高度;res->m_w = 宽度;返回资源;}//结束 matrix_create

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

这是访问某些元素的函数.它会做一些错误检查.

double matrix_access(Matrix*mat, unsigned i, unsigned j){如果(!垫){ fprintf(stderr, "没有可访问的矩阵\n");退出(退出失败;};无符号 h = mat-> m_h;无符号 w = mat-> m_w;如果 (i >= h || j >= w){ fprintf(stderr, "out-of-bound matrix access\n");退出(EXIT_FAILURE);};返回 mat->m_v [i*h + j];}

因为我只做了一个 calloc,所以销毁代码很简单:

 void matrix_destroy(Matrix*mat) {if (!mat) { fprintf(stderr, "没有要销毁的矩阵\n");退出(EXIT_FAILURE);};断言(mat-> m_h  m_w 

assert 语句在原则上是无用的(它们检查一些应该总是是真的).但我喜欢防御性编程(这将帮助我捕捉其他中的错误em> 地方滥用我的 Matrix).它们可以被禁用(阅读 assert(3))在编译时间.

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

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

<小时>

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

不要忘记编译所有警告和调试信息,所以 gcc -Wall -Wextra -gGCC.使用调试器 gdb (以及valgrind 来寻找内存泄漏).阅读每个使用过的函数的文档(例如,您的代码不检查scanf 但它确实应该).运行多个测试用例.试着说服自己你的代码是好的(通过证明它的一部分).也许使用一些静态源代码分析器(例如Frama-C,它需要 ACSL).如果您需要基准您的程序,请启用优化 在编译时(例如通过将 -O2 -march=native 传递给 gcc代码> ....).

<小时>

在您询问的代码注释中:

<块引用>

//我现在需要动态分配输入文件

您不分配输入文件(操作系统 正在管理它们),您分配一些内存区域.阅读 C 动态内存分配.请注意,内存分配可能会失败(例如,malloc(3)),因为您的虚拟地址空间不能无限增长.

顺便说一句,调用堆栈是有限的(通常为一兆字节或几个在台式计算机上),因此您通常希望避免大型自动变量,这是另一个好处避免在调用框架中放置矩阵并更喜欢为它们分配动态内存的原因.

I need to take a file that is inputted by the user and multiply it by another file. That much I know how to do.

The problem is one file is an array and the other is a matrix.

I need to scan in the first line of the matrix to find the size of the matrix and I then need to dynamically allocate the matrix and array from the files.

This is what I have so far:

#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;
} 

Also sorry for seeming like I just left after posting my question as some members have shared in the comments saying that I was code fishing. I'm not; I just didn't realize how active this community is. Thanks for the input so far.

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

Thanks for the suggestions. I was able to figure out the "fgets" function and I used that to pull in the size of the matrix from the first file. After I had that, dynamically allocating that was easy.

解决方案

My recommendation is to consider your matrix as having some abstract data type that you want to implement.

A common way might be to use an array of pointers (to arrays representing rows of your matrix). But I feel it is confusing and inefficient.

So what are the operations you want on your matrixes?

  • create a matrix of given dimensions

  • destroy a previously created matrix

  • access some element in a given matrix with given row and column indexes

  • change the value of an element in a given matrix with given row and column indexes

  • etc....

BTW, you might have several variants of them. For example, you could do error checking (e.g. reject a negative index) or you could have unsafe (but slightly faster) functions capable of undefined behavior (and this is very scary). Of course you could define more operations (using other ones), for example matrix multiplication etc.

You should list -on paper or board- all the operations you want on your matrixes and explain them in your documentation (or your comments). In practice you might have many dozens -or even hundreds- of operations on your abstract data type. Document also what happens in error cases.

I usually recommend keeping the dimensions with the matrix (unless you know that some of the dimension is a constant). A common way of implementing abstract data types in C is to encapsulate them in some struct and use pointers to these.

So I suggest to use a flexible array member (as the last element of your struct). Here is my matrix_st structure:

  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
  };

so my abstract data type is just pointers to

  typedef struct matrix_st Matrix;

Here are the declarations of the functions implementing my abstract data type:

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

Here are some implementations (since I don't want to deal with pathologically huge matrixes, I define some maximal dimension; computer resources are always finite!):

  #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

I am using calloc not malloc because I really want some zero-ed memory. So the returned matrix contains all zeros. BTW on some computers (not mine, a PC/Linux/Debian/x86-64 desktop) the height*width*sizeof(double) could overflow.

Here is the function to access some element. It does some error checking.

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];
}

Since I made only one calloc the destruction is simple to code:

  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);
  }

The assert statements are in principle useless (they check something which should always be true). But I love defensive programming (this would help me catching bugs in some other places misusing my Matrix). They could be disabled (read assert(3)) at compilation time.

BTW, you could declare these functions as inline or static inline (and define them in some included header file). An optimizing compiler is likely to produce efficient code (e.g. compile with gcc -O2 -Wall -march=native when benchmarking).

Since you are reading a matrix from some file, you should define your file format (using, in your documentation, some EBNF notation to describe the syntax in that file is useful) and you could define and implement a function reading and creating a matrix from some opened file handle.


Coding the other functions is left as an exercise to the reader.

Don't forget to compile with all warnings and debug info, so gcc -Wall -Wextra -g with GCC. Use the debugger gdb (and also valgrind to hunt memory leaks). Read the documentation of every used function (for example your code don't check the return count of scanf but it really should). Run several test cases. Try to convince yourself that your code is good (by proving parts of it). Perhaps use some static source code analyzer (e.g. Frama-C, which wants extra annotations in ACSL). If you need to benchmark your program, enable optimizations at compile time (e.g. by passing -O2 -march=native to gcc ....).


In a code comment you are asking:

 // I need to now dynamically allocate the input files

You don't allocate input files (the operating system is managing them), you allocate some memory zone. Read about C dynamic memory allocation. Notice that memory allocation can fail (e.g. as documented in malloc(3)), because your virtual address space cannot grow indefinitely.

BTW, the call stack is limited (typically to a megabyte or a few of them on desktop computers), so you generally want to avoid large automatic variables, so that is another good reason to avoid putting matrixes in your call frame and to prefer dynamic memory allocation for them.

这篇关于C中未知矩阵的动态分配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆