如何使用.h和.c文件将程序拆分成多种文件格式?

时间:2018-05-08 05:43:01

标签: c multiple-files

您好我想弄清楚将程序拆分为多种文件格式,以便拥有 .h 文件和2个 .c 文件。我有一个完整的程序,但只是为了这个例子,我希望打印输出的功能是在一个单独的.c文件中。我知道如何制作基本算术的功能,如

int Sum(int a, int b) 
{ 
    return a+b; 
}

但是如何使用for循环和下面的代码创建一个函数?

for (i = 0; i < count; i++)
{
    printf("\n%s", ptr[i]->name);
    printf("%s", ptr[i]->street);
    printf("%s", ptr[i]->citystate);
    printf("%s", ptr[i]->zip);
    free(ptr[i]);    
}

我得到它的工作方式是这样的,只是不知道如何将for循环变成函数。

Functions.h:

#ifndef FUNCTIONS_H_INCLUDED
#define FUNCTIONS_H_INCLUDED
/* ^^ these are the include guards */

/* Prototypes for the functions */
/* Sums two ints */
int Sum(int a, int b);

#endif

Functions.c:

/* In general it's good to include also the header of the current .c,
   to avoid repeating the prototypes */
#include "Functions.h"

int Sum(int a, int b)
{
    return a+b;
}

MAIN.C

#include "stdio.h"
/* To use the functions defined in Functions.c I need to #include Functions.h */
#include "Functions.h"

int main(void)
{
    int a, b;
    printf("Insert two numbers: ");
    if(scanf("%d %d", &a, &b)!=2)
    {
        fputs("Invalid input", stderr);
        return 1;
    }
    printf("%d + %d = %d", a, b, Sum(a, b));
    return 0;

}

2 个答案:

答案 0 :(得分:2)

最简单的是,您将循环片段转换为:

void print_and_destroy(size_t count, SomeType ptr[count])
{
    for (size_t i = 0; i < count; i++)
    {
        printf("\n%s", ptr[i]->name);
        printf("%s", ptr[i]->street);
        printf("%s", ptr[i]->citystate);
        printf("%s", ptr[i]->zip);
        free(ptr[i]);
    }
    free(ptr);
}

最终免费是因为数组现在不包含任何有用的指针(它们都已被释放)。您可以在ptr[i] = NULL;之后添加free(ptr[i]);。这表明那里没有数据了。

但是,正如评论12 SergeyA所述,以及笨拙但准确的函数名称,这并不是代码的良好细分。你需要两个功能:

void destroy(size_t count, SomeType ptr[count])
{
    for (size_t i = 0; i < count; i++)
    {
        free(ptr[i]);
        ptr[i] = NULL;  // Option 1
    }
    free(ptr);          // Option 2
}

如果您使用选项2,则不会使用选项1(尽管它不会造成实际伤害)。如果您不使用选项2,则应使用选项1。

void print(size_t count, const SomeType ptr[count])
{
    for (size_t i = 0; i < count; i++)
    {
        printf("%s, ", ptr[i]->name);
        printf("%s, ", ptr[i]->street);
        printf("%s, ", ptr[i]->citystate);
        printf("%s\n", ptr[i]->zip);
    }
}

请注意,您可能需要在地址字段之间留出空格。您可能想要也可能不想要一行代表名称,一行代表街道地址,一行代表城市,州和邮政编码 - 选择适合您的格式。通常,在输出结束时输出换行符,而不是在开头,除非你想要双倍行距。

  

那么这将是我单独的function.c文件,我的头文件看起来像…code omitted…对吗?主程序中的函数调用如何?

标题的大纲是:

#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED

#include <stddef.h>      // Smallest header that defines size_t

typedef struct SomeType
{
    char name[32];
    char street[32];
    char citystate[32];
    char zip[11];        // Allow for ZIP+4 and terminal null
} SomeType;

extern void print_and_destroy(size_t count, SomeType ptr[count]);

#endif /* HEADER_H_INCLUDED */

请注意,标题不包含<stdio.h>;接口的任何部分都不依赖于<stdio.h>特定的任何内容,例如FILE *(尽管<stdio.h> 定义的标头之一size_t)。标题应该是最小的,但是自包含且幂等。不包括<stdio.h>是最小的一部分;包括<stddef.h>在内是自足的一部分;标题守卫是幂等的关键部分。这意味着您可以包含标题,而不必担心它是否已经间接包含在内,或者在以后间接再次包含,并且您不必担心必须包含哪些标题 - 标题是独立的,处理它。

main()中,您有类似的内容:

enum { MAX_ADDRESSES = 20 };
SomeType *data[MAX_ADDRESSES];

…memory allocation…
…data loading…

print_and_destroy(MAX_ADDRESSES, data);

答案 1 :(得分:2)

涉及两个不同的问题(如果需要,我建议在第二个问题之前解决第一个问题):

  • 如何在单个{/ 3>中拆分单个translation unit,但保持相同的功能

  • 如何重构代码以使其更具可读性并由更小的&#34;更小的&#34;并且&#34;更好&#34;功能。在您的情况下,这是主要问题。

第一个问题,例如将一个小的单个程序拆分成几十万行的单个myprog.c文件,非常容易。真正的问题是巧妙地组织(然后变得更难,基于意见)。您只需要在头文件中放置声明,并将 definitions 放在几个翻译单元中,当然也可以改进您的构建过程使用并将它们链接在一起。因此,您首先会有一个公共头文件myheader.h 声明您的类型,宏,函数,全局变量。如果需要,您还可以在那里定义一些简短的static inline函数。那么你将拥有几个C文件(技术上的翻译单元)foo.cbar.cdingo.c,并且你最好在每个文件中放置几个​​相关的函数他们每个此类C文件都有#include "myheader.h"。您最好使用一些build automation工具,可能GNU make(或something其他,例如ninja),您可以使用Makefile进行配置。您以后可能会有几个头文件,但是对于一个只有几十个可能不需要的源代码行的小项目。在some cases中,您可以从更高级别的描述中生成一些C文件(例如,使用简单的metaprogramming技术)。

第二个问题(code refactoring)真的很难,而且没有简单的通用答案。这真的取决于项目。一个简单的(也是非常有争议的,过度简化的)经验法则是你需要有一些功能而且只做一件事&#34;每个最多几十行。因此,只要一个函数执行多个操作或者有一个或两个以上的行,您就应该考虑拆分和重构它(但是你不会总是去做)。显然,你的main应该分成几个部分。

最后,不要过度习惯每个*.c文件只放一个函数,或者每个文件只有一百行的*.c个文件。这通常是无用的,并且可能会增加您的构建时间(因为预处理器会工作很多),甚至可能会略微降低可执行文件的运行时性能(因为您的optimizing compiler无法内联,除非你使用链接时优化)。我的建议(基于意见,如此有争议)是拥有几千行的源文件,每行包含几个(十几个)函数。

在您的情况下,我相信您的计划(在您的问题中)非常小,您不需要将其分成几个翻译单元(除非您的老师要求您)。但实际上你需要重构它,也许定义一些支持它的abstract data type和例程(参见this)。

研究与您的项目相关的现有free software (例如github)的源代码,以获取灵感,因为您将会这样做我需要定义和遵循许多coding conventions(和编码规则),这些规则对C编程很重要。在你的新手案例中,我相信在你正在理解或感兴趣的领域中研究任何小型自由软件程序(几十万行,见this)的来源,并且在编程语言中你是练习 - 会让你受益匪浅。