Reputation: 21
For my programming class we have to make a program that calls on sub functions (saved as .h). I am able to do this with simple functions but when passing 2 dimensional arrays (and higher) it gets hard. I have tried multiple times and have had no luck.
Here is the segment from my main calling on the function:
switch (selection)
{
case 1:
determinant = det(m[0],n[0],Mat_1);
printf("\nDeterminant of Matrix 1 is: %f\n",determinant);
break;
and here is my .h file finding the Determinant of a 2x2 matrix:
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;
}
Basically what I gather is that the sub function (det.h) does not seem to receive the 2 dimensional array.
I know it's a bit lengthy but here is my whole code for the .c (main) file.
Thanks so much for your time.
Kindest Regards, Tom
#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;
}
Upvotes: 1
Views: 862
Reputation: 51274
First of all, you should probably put your definitions in a .c file, and declarations in a .h file. Meaning that the body of your det
function shouldn't be in a .h file.
Second, you need to check if your compiler supports variable length arrays. Otherwise, you can either pass a pointer, or a fixed size (dimensions known at compile time) array, or an unsized array to your function, and then pass array bounds as separate parameters.
Using statically allocated arrays, it would look something like:
You have a matrices.h
file which contains declarations and is meant to be included by other compile units. It should also make sure that you don't include it twice from anywhere:
// 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
Then create a separate .c file (matrices.c
), which will include the header and provide actual implementation (and can optionally contain private functions and fields):
// 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]
}
}
}
Your main.c
only needs to include the header file. This will enable compiler to compile the main
translation unit separately from the matrices
translation unit, simply by knowing the signature of det
:
// main.c
#include "matrices.h"
void main(void)
{
...
}
Update
You can place functions in .h files, and perhaps your teacher really had this in mind, but it's not the correct location to place them in.
The way C builds your app is that it compiles each .c file separately, before linking the intermediate files into the final executable. This notion is often unclear to novice programmers, but understanding this process is really important if you plan to program anything more than a homework assignment in C.
I am also presuming you know the difference between declaring a function (writing its signature), and defining it (writing its implementation, i.e. body). The point of declarations is to have method signatures ready for the compiler (even if they are in different .c files) when a certain function calls a different function (defined elsewhere, or even below that caller function). For the compiler, these declarations are a promise that these functions exists somewhere, and that the linker will be able to provide their exact locations once every translation unit is compiled.
Note also that declarations alone have no "weight" in the final executable. If you include a huge header file (e.g. standard headers) with hundreds of declarations, and only use a single function, only the referenced function's code will end up being included in the final executable (along with any code needed for that function to run, of course).
So the compiler first takes a single .c file and runs it through the preprocessor. Preprocessor is pretty dumb: it merely replaces all #includes
with actual .h files (inserts their textual contents), replaces #defines
with their values, and removes those #ifdef
s which evaluate to false, until the starting .c file is turned into a single .c file (textual), which has no markup and is ready for compilation.
So, as mentioned above, while compiling this single .c file (which has now grown), compiler has signatures (declarations) of all functions that are referenced from withing this .c file, but reside in other compilation units. This is the purpose of header files, to avoid having to declare all these external signatures in each and every .c file. They are, in a way, a "public interface" of other translation units, because other .c files will only know about functions they got by including header files.
At this point, you may note two things:
If a .c file includes several header files, which also include other header files, it's pretty easy for the preprocessor to get stuck in recursion, or that symbols end up being defined multiple times. This is the reason why all header files (usually) start with #ifndef (some-unique-symbol)
, followed by #define (some-unique-symbol)
because it ensures that, as soon as this unique symbol is defined for the first time, preprocessor will skip it on next inclusion attempt. A non-standard (but widely supported) directive that does the same thing in a simpler way is pragma once
(meaning "include this header only once per compilation unit"). Keep in mind: compiler will include the header file again when it starts compiling the next .c file - meaning that all #defines
only "live" within a single translation unit.
If a function is defined (not declared, but actually defined, with its entire body) inside a header file (instead of a .c file), then each translation unit gets its own separate copy of the entire function whenever it includes that header - meaning that code gets physically duplicated in the final executable. This is probably not what you want - the point of functions is to extract common functionality to a single place and reduce duplication. The only time you will actually want to place a function inside a header, is when you want to define an inline
function - a function which should (for performance reasons) be optimized away and inserted in place (similarly to what a preprocessor would do with a macro define) - in which case it's obvious you really actually want each .c file to get its own copy.
Actual linking between translation units happens at the end, when all the units are compiled into intermediate files. In this last phase, linker will replace each function call to a promised (declared, external) function with an actual address of the function (or throw an error if it is unable to resolve it).
So, each compilation unit (a .c file with its corresponding header file) serves as a (kind of a) module in C. You define certain struct/data types in this header file, declare functions which operate on them, and them write their implementations in the .c file. This .c file will usually include its own header file (simply to get forward declarations of its own functions), and any header files it needs to do its job.
The funny thing about your problem is, if you only have a single main.c
which is including each header file only once, then these functions won't actually be duplicated anywhere else. In this case, it will work without issues, but it's the wrong thing to do - and the correct alternative is not much more complex: simply move these functions to .c files and you are back to "doing it right".
Or alternatively, you don't even need .h files. You can declare all functions inside the main.c
, and have their definitions in other .c files. That would be a much more correct way to do it:
// 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
}
In a real project, you would create a Matrix module with a header similar to:
// 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);
Then the .c file would provide actual implementations:
// matrix.c
// include whatever headers you need
#include "matrix.h"
#include <math.h>
// actual implementatinos
float Matrix_det(Matrix m)
{
// calculate the determinant
}
And you would then include matrix.h
wherever you need to perform matrix calculations.
You will only need to include <stdio.h>
in those files where you interact with the user (in your case, the main.c
file).
Upvotes: 3