gpt4 book ai didi

c - 使用#include“unit.c”使包含的任何子单元均可访问数组吗?

转载 作者:行者123 更新时间:2023-11-30 15:40:22 25 4
gpt4 key购买 nike

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


或类似的规定。

最佳答案

因此,几件事:


不要#include .c文件(即源代码);这是一个坏习惯。对于这样的小型,简单程序来说,这没什么大不了的,但是随着您的程序变得越来越大,越来越复杂,它将导致构建和维护的麻烦。您要做的是定义一个仅包含函数声明而不是其定义(主体)的头文件,如下所示:

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

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

现在,这里变得有些头痛了-C对数组表达式的处理有点不直观。除非它是 sizeof或一元 &运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,否则将转换类型为“ T的N个元素的数组”的表达式(“ decay”)类型为“指向 T的指针”的表达式,该表达式的值将是数组第一个元素的地址。

如果像这样将数组作为参数传递:
Range(Matrix);

则表达式 Matrix的类型为“ int的5元素数组的5元素数组”。由于此表达式不是 sizeof或一元 &运算符的操作数,因此将其转换为类型为“指向 int的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];
之类的内容而无需在编译时得到警告或在运行时保证崩溃。因此,您需要检查自己的边界,这意味着除了列数之外,您还需要知道数组有多少行。您将为行数传递一个单独的参数:
code>Range(Matrix, 5);
meaning your function declaration would look something like
void Range(int m[][5], size_t rows);



上述方法的一个缺陷是 m中的列数固定为5。此功能将无法在其他尺寸的矩阵上使用。如果你是
与支持可变长度arrays1的编译器一起使用时,可以使用变量来指定数组尺寸,而不是使用编译时常量。由于需要先声明变量才能在数组声明中使用它,所以您必须将原型写为
void Range( size_t rows, size_t cols, int m[][cols] );

并将函数调用为
Range(5, 5, Matrix);

这将允许您在不同大小的矩阵上使用 Range函数,例如:
int M1[5][5]; int M2[9][9];int M3[20][20];...Range(5, 5, M1);Range(9, 9, M2);Range(20, 20, M3);
Now, if you only intend for this function to work with 5x5 matrices, then hardcoding the dimension isn't a problem; it's only an issue if you intend to use this function for any sized matrix.
  • If you are using a compiler that doesn't support VLAs, you'll need a different approach. Instead of passing the array expression as a parameter, we pass a pointer to the first element of the array. We'll treat this pointer as though it were a 1-d array instead of a 2-d array, like so:
    void Range( int *m, size_t rows, size_t cols )
    {
    printf("Your range is: %d\n", m[4 * cols + 1]);
    }

    并且您将其称为
    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作为扩展。

  • 关于c - 使用#include“unit.c”使包含的任何子单元均可访问数组吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21049411/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com