使用#include“unit.c”为包含的任何子单元创建一个数组?

时间:2014-01-10 16:26:31

标签: c global-variables

如何确保从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"

或类似的东西。

3 个答案:

答案 0 :(得分:1)

所以,有几件事:

  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并将生成的目标文件链接在一起。

  2. 如果可以提供帮助,请不要使用全局变量;理想情况下,函数及其调用者应该通过参数,返回值和异常进行通信(支持异常的语言,无论如何,C不会这样做)。您应该将Matrix作为参数传递给Range函数,以及数组大小的参数,以及函数执行其工作所需的任何其他信息。由于您要打印单个元素的值,因此您也应该传递该元素的行号和列号。

    现在,事情变得令人头疼--C对数组表达式的处理有点不直观。除非它是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]中看到更改后的值。

  3. 由于我们只在m的声明中指定了列数,因此我们希望传递一个指定行数的附加参数。 C不会对数组访问进行任何边界检查,这意味着您可以编写类似
    x = m[20][1];
    的内容,而无需在编译时收到警告或保证运行时崩溃。因此,您需要自己进行边界检查,这意味着除了列数之外,您还需要知道数组有多少行。您将为行数传递一个单独的参数:
    void Range(int m[][5], size_t rows);
    意思是你的函数声明看起来像
    code>Range(Matrix, 5);

  4. 上述方法的一个缺陷是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矩阵,那么对维度进行硬编码不是问题。如果您打算将此函数用于任何大小的矩阵,那么它只是一个问题。

  5. 如果您使用的是不支持VLA的编译器,那么您需要采用不同的方法。我们不是将数组表达式作为参数传递,而是将指针传递给数组的第一个元素。我们将这个指针视为1-d数组而不是2-d数组,如下所示:
    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);

  6. 您假设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);

  7. 这将我们带到最后一个项目(最后);不要使用&#34;魔术数字&#34;在你的代码中。不要在整个地方放置文字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变量。