C中未知矩阵的Dynamica分配
我需要获取用户输入的文件并将其乘以另一个文件。 我知道该怎么做。
问题是一个文件是一个数组,另一个是矩阵。
我需要在矩阵的第一行扫描以找到矩阵的大小,然后我需要从文件中动态分配矩阵和数组。
这是我到目前为止:
#include #include #include #include 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; }
也很遗憾看起来像我刚刚发布我的问题后离开,因为一些成员在评论中分享说我是钓鱼码。 我不是; 我只是没有意识到这个社区有多活跃。 感谢您的投入到目前为止。
这是我到目前为止所有内容的截图,包括将要读入的文件。
谢谢你的建议。 我能够找出“fgets”函数,我用它来从第一个文件中提取矩阵的大小。 在我有了之后,动态分配这很容易。
我的建议是将您的矩阵视为具有您想要实现的一些抽象数据类型 。
一种常见的方法可能是使用指针数组(表示矩阵行的数组)。 但我觉得这是令人困惑和低效的。
那么你对矩阵的操作是什么?
-
创建给定尺寸的矩阵
-
销毁先前创建的矩阵
-
使用给定的行和列索引访问给定矩阵中的某个元素
-
使用给定的行和列索引更改给定矩阵中元素的值
-
等等….
顺便说一下,你可能有几种变体。 例如,您可以进行错误检查(例如,拒绝否定索引),或者您可能有不安全(但稍微快一点)的function,这些function具有未定义的行为 (这非常可怕 )。 当然,您可以定义更多操作(使用其他操作),例如矩阵乘法等。
您应该在纸张或纸板上列出您想要在矩阵上执行的所有操作,并在文档(或您的注释)中解释它们。 在实践中,您可能在抽象数据类型上有许多甚至数百个操作。 记录错误情况下会发生什么。
我通常建议使用矩阵保持尺寸(除非你知道某些尺寸是常数)。 在C中实现抽象数据类型的常用方法是将它们封装在某些struct
并使用指向这些struct
指针。
所以我建议使用灵活的数组成员 (作为结构的最后一个元素)。 这是我的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
因为我真的想要一些零内存。 因此返回的矩阵包含全零。 BTW在某些计算机上(不是我的,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
语句原则上是无用的(它们检查的内容应该始终为真)。 但是我喜欢防御性编程 (这可以帮助我在其他地方捕捉到误用我的Matrix
)。 它们可以在编译时被禁用(读取assert(3) )。
顺便说一下,你可以将这些函数声明为inline
或static inline
(并在一些包含的头文件中定义它们)。 优化编译器可能会生成有效的代码(例如,在基准测试时使用 gcc -O2 -Wall -march=native
编译)。
由于您正在从某个文件中读取矩阵,因此您应该定义您的文件格式 (在文档中使用一些EBNF表示法来描述该文件中的语法很有用)并且您可以定义和实现函数读取并从中创建矩阵一些打开的文件句柄。
编码其他function留给读者练习。
不要忘记编译所有警告和调试信息,所以gcc -Wall -Wextra -g
与GCC 。 使用调试器gdb
(以及valgrind
来捕获内存泄漏 )。 阅读每个使用过的函数的文档 (例如,您的代码不检查scanf
的返回计数,但它确实应该)。 运行几个测试用例 。 试着说服自己你的代码是好的(通过certificate它的一部分)。 也许使用一些静态源代码分析器 (例如,在ACSL中需要额外注释的Frama-C )。 如果您需要对程序进行基准测试,请在编译时启用优化 (例如,通过将-O2 -march=native
传递给gcc
....)。
在您要求的代码注释中:
// I need to now dynamically allocate the input files
您没有分配输入文件 ( 操作系统正在管理它们),您分配了一些内存区域 。 阅读C动态内存分配 。 请注意,内存分配可能会失败(例如,如malloc(3)中所述 ),因为您的虚拟地址空间无法无限增长。
顺便说一句, 调用堆栈是有限的(通常是桌面计算机上的兆字节或几个),所以你通常想避免大的自动变量 ,这是避免在调用框架中放置矩阵和偏好动态的另一个好理由他们的内存分配。
我没有看到你实际读取行/列数的位置,但是一旦你拥有它们,分配很简单:
int (*matrix)[columnCount] = malloc(rowCount*sizeof(*matrix));
而已。 这将matrix
声明为columnCount
整数数组的指针*matrix
。 括号是必要的,因为int* matrix[...]
会声明一个指针数组。 malloc()
为rowCount
这样的数组分配空间,在一块内存中提供完整的2D矩阵。 访问与任何2D数组一样:
for(int y = 0; y < rowCount; y++) { for(int x = 0; x < columnCount; x++) { matrix[y][x] = 42; } }
解除分配就像分配一样简单:
free(matrix);