如何确保从main.c调用的unit.c中的函数需要在main.c函数中声明的数组?
有没有办法在.c文件中全局声明变量?有没有使用全局变量的智能方法?
示例:
#include <stdio.h>
#include "sub.c"
int main(void)
{
int matrix[5][5];
matrix[5][1] = 5;
Range();
}
现在为sub.c:
int Range()
{
printf("Your Range is: %i",Matrix[5][1])
}
现在出现的问题是,在编译时会出现错误,说明
"In file included from main.c:
"sub.c:3:15: Error: Matrix not declared"
或类似的东西。
答案 0 :(得分:1)
所以,有几件事:
#include
.c文件(即源代码);这是一个坏习惯。对于像这样的小型简单程序来说,这不是什么大问题,但随着程序变得越来越大,越来越复杂,它将导致构建和维护问题。你要做的是定义一个只包含你的函数的声明的头文件,而不是它的定义(正文),如下所示:{ {2}}
您然后/**
* sub.h - declaration for Range function
*/
#ifndef SUB_H // include guards; prevents this file from being processed
#define SUB_H // more than once for the same translation unit
/**
* Changing the type of Range to void since you aren't returning anything, and you
* aren't using the result of the function in your main function
*/
void Range( /* parameter declarations, which we'll get into below */ );
#endif
将此文件#include
#include <stdio.h>
#include "sub.h"
int main( void )
{
int Matrix[5][5];
Matrix[5][1] = 5; // this is an error; your array dimensions only go from 0 to 4
Range( /* parameters, including Matrix, which we'll get into below */ );
}
并单独编译sub.c
并将生成的目标文件链接在一起。
Matrix
作为参数传递给Range
函数,以及数组大小的参数,以及函数执行其工作所需的任何其他信息。由于您要打印单个元素的值,因此您也应该传递该元素的行号和列号。sizeof
或一元&
运算符的操作数,或者是用于初始化声明中的另一个数组的字符串文字,否则为表达式,类型为&# 34; T
&#34;的N元素数组;将被转换(&#34;衰减&#34;)到类型为&#34的表达式;指向T
&#34;的指针,并且表达式的值将是第一个元素的地址。阵列点。Range(Matrix);
那么表达式的类型 Matrix
是&#34; 5元素阵列int
&#34;的5元素数组。由于此表达式不是sizeof
或一元&
运算符的操作数,因此它将转换为类型为#34的表达式;指向int
&#34的5元素数组的指针;和,值是数组第一行的地址(与数组本身的地址相同)。这意味着您的Range
函数将被声明为类似void Range( int m[][5] )
的内容
或void Range( int (*m)[5] )
(第二个声明中的括号;没有它们,m
将被声明为指向int
的指针数组,这不是我们想要的。)T a[]
和T a[N]
都被解释为T *a
;也就是说,a
被声明为指向T
的指针,而不是T
的数组。
Range
更改m[4][0]
的值,您会在Matrix[4][0]
中看到更改后的值。
m
的声明中指定了列数,因此我们希望传递一个指定行数的附加参数。 C不会对数组访问进行任何边界检查,这意味着您可以编写类似x = m[20][1];
的内容,而无需在编译时收到警告或保证运行时崩溃。因此,您需要自己进行边界检查,这意味着除了列数之外,您还需要知道数组有多少行。您将为行数传递一个单独的参数:void Range(int m[][5], size_t rows);
意思是你的函数声明看起来像code>Range(Matrix, 5);
m
中的列数固定为5;这个函数不能用于其他大小的矩阵。如果你是
使用支持可变长度数组 1 的编译器,您可以使用变量来指定数组维度,而不是编译时常量。由于变量需要在可以在数组声明中使用之前声明,因此您必须将原型编写为void Range( size_t rows, size_t cols, int m[][cols] );
并将该函数调用为Range(5, 5, Matrix);
这样您就可以在不同大小的矩阵上使用Range
函数,例如:void Range( int *m, size_t rows, size_t cols )
{
printf("Your range is: %d\n", m[4 * cols + 1]);
}
现在,如果您只打算使用此函数来处理5x5矩阵,那么对维度进行硬编码不是问题。如果您打算将此函数用于任何大小的矩阵,那么它只是一个问题。
int M1[5][5]; int M2[9][9]; int M3[20][20]; ... Range(5, 5, M1); Range(9, 9, M2); Range(20, 20, M3);你会把它称为
Range(&Matrix[0][0], 5, 5);
Matrix[5][1]
处存在元素;但是,C中的数组是0原点,这意味着两个维度都是从0到4的索引。因此,要访问第5行的第1个元素,您需要引用Matrix[4][0]
。 Matrix[5][1]
超出了数组的范围。
m[4][0]
以外的元素。如果希望函数访问数组的任意元素,则需要将行号和列号作为单独的参数传递;这一点,结合将数组的维度作为参数传递,为您提供了一种方法,可以确保您不会尝试访问数组边界之外的元素。因此,您的Range
函数看起来像void Range(int m[][5] size_t rows, size_t i, size_t j)
{
if ( i < rows && j < 5 )
printf("Your range is: %d\n", m[i][j];
}
,您可以将其称为Range(Matrix, 5, 4, 0);
5
,而是定义符号常量(预处理器宏)来表示矩阵中的行数和列数。首先,如果您决定更改数组维度,则只需更新常量定义,而不是追踪文字5
的每个匹配项,并确定它是否用于检查数组访问。将上述所有内容放在一起(假设您只使用Range
只使用特定大小的数组),我们得到:/**
* sub.h - declaration for Range function
*/
#ifndef SUB_H // include guards; prevents this file from being processed
#define SUB_H // more than once for the same translation unit
/**
* Since these macros are going to be used by both the main function
* and the Range function, it makes sense to define them in the
* sub.h file, as it will be included in both main.c and sub.c
*/
#define ROWS 5
#define COLS 5
/**
* Prints the value at index i,j of m; if i or j are out of
* range, prints nothing.
*/
void Range( int m[][COLS], size_t rows, size_t i, size_t j );
#endif
/**
* sub.c - implementation of Range function
*/
#include <stdio.h>
#include "sub.h"
void Range( int m[][COLS], size_t rows, size_t i, size_t j )
{
if ( i < rows && j < COLS )
printf("Your range is: %d\n", m[i][j]);
}
/**
* main.c
*/
#include <stdio.h>
#include "sub.h"
int main( void )
{
int Matrix[ROWS][COLS];
Matrix[4][0] = 5; // assumes we know 4 and 0 are within
Range( Matrix, ROWS, 4, 0 ); // the array bounds.
}
那么,你彻底感到困惑了吗?
<小时/> 1。 C99编译器或C2011编译器,其中宏__STDC_NO_VLA__未定义或为0.某些C89编译器可能支持VLA作为扩展。
答案 1 :(得分:0)
良好的编程习惯要求将它们用作参数,因此选项为:
#include <stdio.h>
#include "sub.h"
int main(void)
{
int matrix[5][5];
matrix[5][1] = 5;
Range(matrix);
}
其中sub.h仅包含函数的原型。
现在为sub.c:
int Range(int matrix[][5])
{
printf("Your Range is: %i",matrix[5][1]);
return 0;
}
答案 2 :(得分:0)
您应该有一个头文件,其中包含您需要调用并包含它的函数的原型。我不认为你包含.c文件
您还需要将参数传递给函数。
如果需要跨文件访问变量,则需要使用extern变量。