对于我的编程类,我们必须创建一个调用子函数的程序(保存为.h)。 我可以用简单的函数做到这一点,但是当传递二维数组(和更高)时,它变得很难。 我已多次尝试并且没有运气。
以下是我主要调用该函数的段:
switch (selection)
{
case 1:
determinant = det(m[0],n[0],Mat_1);
printf("\nDeterminant of Matrix 1 is: %f\n",determinant);
break;
这是我的.h文件找到2x2矩阵的行列式:
float det(int a, int b, float Mat[a][b])
{
printf("%f\n%f\n%f\n%f\n",Mat[0][0],Mat[0][1],Mat[1][0],Mat[1][1]);
float det;
det = ((Mat[0][0]*Mat[1][1])-(Mat[0][1]*Mat[1][0]));
return det;
}
基本上我收集的是子函数(det.h)似乎没有接收二维数组。
我知道它有点冗长,但这是我的.c(主)文件的完整代码。
非常感谢你的时间。
最基本的问候, 汤姆
#include <stdio.h>
#include "det.h"
int main(void)
{
int m[3],n[3],number,i,j,selection;
float determinant;
printf("Enter number of matrices you wish to deal with:");
scanf("%d",&number);
while ((number<1.0)||(number>2))
{
printf("1 or 2 matrices only please.\n");
scanf("%d",&number);
}
for (i=0;i<number;i++)
{
printf("Enter dimensions (m x n) of Matrix [%d]:\n",i+1);
scanf("%d %d",&m[i],&n[i]);
}
float Mat_1[m[0]][n[0]],Mat_2[m[1]][n[1]];
for (i=0;i<m[0];i++)
{
for (j=0;j<n[0];j++)
{
printf("Enter Data for Matrix 1 [%d][%d]:",i+1,j+1);
scanf("%d",&Mat_1[i][j]);
}
}
if (number=2)
for (i=0;i<m[1];i++)
{
for (j=0;j<n[1];j++)
{
printf("Enter Data for Matrix 2 [%d][%d]:",i+1,j+1);
scanf("%d",&Mat_2[i][j]);
}
}
printf("\nSELECT ONE OF THE FOLLOWING:\n1. Determinant\n2. Addition\n3. Subtraction\n4. Multiply\n5. Transpose\n6. Scale\n7. Print");
scanf("%d",&selection);
while ((selection<1)||(selection>7))
{
printf("Invalid selectoin, try again (1-7):");
scanf("%d",&selection);
}
switch (selection)
{
case 1:
determinant = det(m[0],n[0],Mat_1);
printf("\nDeterminant of Matrix 1 is: %f\n",determinant);
break;
default:
printf("\nAn Error has occured.\n");
}
system("pause");
return 0;
}
答案 0 :(得分:2)
首先,您应该将定义放在.c文件中,并在.h文件中声明。这意味着det
函数的正文不应该位于.h文件中。
其次,您需要检查您的编译器是否支持variable length arrays。否则,您可以将指针或固定大小(编译时已知的维度)数组或未大小的数组传递给函数,然后将数组边界作为单独的参数传递。
使用静态分配的数组,它看起来像:
您有一个matrices.h
文件,其中包含声明,并且包含在其他编译单元中。它还应该确保你不会在任何地方包括它两次:
// matrices.h
#ifndef _MATRICES_H_
#define _MATRICES_H_
#define MAXROWS 10
#define MAXCOLS 20
// calculates the determinant
float det(float array[MAXROWS][MAXCOLS], int rows, int cols);
#endif
然后创建一个单独的.c文件(matrices.c
),它将包含标头并提供实际实现(并且可以选择包含私有函数和字段):
// matrices.c
#include "matrices.h"
float det(float array[MAXROWS][MAXCOLS], int rows, int cols)
{
int i;
for (i=0; i < rows; i++)
{
int j;
for (j=0; j < cols; j++)
{
// do stuff with array[i][j]
}
}
}
您的main.c
只需要包含头文件。这将使编译器能够单独从main
翻译单元编译matrices
translation unit,只需知道det
的签名:
// main.c
#include "matrices.h"
void main(void)
{
...
}
<强>更新强>
你可以将功能放在.h文件中,也许你的老师真的考虑到了这一点,但它并不是放置它们的正确位置。
C构建应用程序的方式是在将中间文件链接到最终可执行文件之前,它单独编译每个.c文件。对于新手程序员来说,这个概念通常是不明确的,但是如果你计划编写的东西不仅仅是C语言中的家庭作业,那么理解这个过程非常重要。
我还假设您知道声明一个函数(编写其签名)和定义它(编写它的实现,即正文)之间的区别。声明的目的是为某个函数调用不同的函数(在别处定义,甚至低于该调用函数)时,为编译器准备好方法签名(即使它们位于不同的.c文件中)。对于编译器,这些声明是 promise ,这些函数存在于某处,并且链接器将能够在编译每个转换单元后提供其精确位置。
另请注意,声明本身没有&#34;权重&#34;在最后的可执行文件中如果你包含一个包含数百个声明的巨大头文件(例如标准头文件),并且只使用一个函数,那么只有引用函数的代码才会被包含在最终的可执行文件中(以及所需的任何代码)当然要运行的功能。
因此编译器首先获取单个.c文件并通过预处理器运行它。预处理器非常愚蠢:它只是用实际的.h文件替换所有#includes
(插入它们的文本内容),用它们的值替换#defines
,并删除那些评估为false的#ifdef
,直到起始的.c文件变成单个.c文件(文本),它没有标记,可以编译。
因此,如上所述,在编译这个单个.c文件(现在已经增长)时,编译器具有使用此.c文件引用的所有函数的签名(声明),但驻留在其他编译单元中。这是头文件的目的,以避免必须在每个.c文件中声明所有这些外部签名。在某种程度上,它们是一个公共界面&#34;其他翻译单元,因为其他.c文件只会通过包含头文件来了解他们获得的功能。
此时,您可能会注意到两件事:
如果.c文件包含多个头文件,其中也包含其他头文件,预处理器很容易陷入递归状态,或者符号最终被多次定义。这就是为什么所有头文件(通常)都以#ifndef (some-unique-symbol)
开头,后跟#define (some-unique-symbol)
的原因,因为它确保首次定义此唯一符号时,预处理器将在下一个时间跳过它包容性尝试。一个非标准(但广泛支持)的指令以更简单的方式执行相同的操作是pragma once
(意思是&#34;每个编译单元只包含一个头文件#34;)。请记住:编译器将在开始编译下一个.c文件时再次包含头文件 - 这意味着所有#defines
仅生成&#34;生存&#34;在一个翻译单元内。
如果在头文件(而不是.c文件)中定义了一个函数(未声明,但实际定义了它的整个主体),那么每个翻译单元都会获得自己独立的副本< / em>整个函数,只要它包含该标题 - 意味着代码在最终的可执行文件中实际上是重复的。这可能不是您想要的 - 功能的重点是将常用功能提取到单个位置并减少重复。实际上你想要在一个标题中放置一个函数的唯一时间就是你要定义一个inline
函数 - 一个应该(出于性能原因)被优化掉并插入到位的函数(类似于预处理器可以用宏定义) - 在这种情况下,显然你实际上想要每个.c文件来获得它自己的副本。
翻译单元之间的实际链接发生在最后,当所有单元都被编译成中间文件时。在最后一个阶段,链接器将使用函数的实际地址替换对承诺(声明的,外部)函数的每个函数调用(如果无法解析它,则抛出错误)。
因此,每个编译单元(带有相应头文件的.c文件)在C中用作(一种)模块。在此头文件中定义某些结构/数据类型,声明对它们进行操作的函数,然后他们在.c文件中编写实现。这个.c文件通常包含它自己的头文件(只是为了获得它自己的函数的声明),以及它完成它所需要的任何头文件。
关于你的问题很有趣的是,如果你只有一个main.c
只包含一个头文件一次,那么这些功能实际上不会在其他任何地方重复。在这种情况下,它可以毫无问题地工作,但这是错误的做法 - 正确的替代方案并不复杂:只需将这些函数移动到.c文件,然后你又回到了&#34;做它是对的&#34;。
或者,您甚至不需要.h文件。您可以在main.c
中声明所有函数,并在其他.c文件中定义它们。这将是一个更正确的方法:
// main.c
#include <stdio.h>
// no need to include any headers, because you will write
// declarations here:
// (extern keyword can be omitted, it just makes it more
// obvious that this function is defined elsewhere)
extern float def(float[R][C] x, int rows, int cols);
void main(void)
{
// you can now call def, as long as it is defined
// in a single .c file included in this project
}
在实际项目中,您将创建一个Matrix模块,其标题类似于:
// matrix.h
// In an actual library, you would use dynamic
// allocation (since statically preallocating a large
// matrix is a waste of space)
struct Matrix
{
float **Cells;
int Rows;
int Cols;
};
// allocation/freeing
Matrix Matrix_create(int numRows, int numCols);
void Matrix_free(Matrix m);
// actual operators
Matrix Matrix_add(Matrix a, Matrix b);
Matrix Matrix_mul(Matrix a, Matrix b);
// this is a good place for this declaration also
float Matrix_det(Matrix m);
然后.c文件将提供实际的实现:
// matrix.c
// include whatever headers you need
#include "matrix.h"
#include <math.h>
// actual implementatinos
float Matrix_det(Matrix m)
{
// calculate the determinant
}
然后,您可以在需要执行矩阵计算的任何位置包含matrix.h
。
您只需要在与用户交互的文件中包含<stdio.h>
(在您的情况下为main.c
文件)。