您好我想弄清楚将程序拆分为多种文件格式,以便拥有 .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;
}
答案 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]);
。这表明那里没有数据了。
但是,正如评论1和2 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.c
,bar.c
,dingo.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)的来源,并且在编程语言中你是练习 - 会让你受益匪浅。