最初,这个函数嵌入到main函数中,创建了一个非常混乱的main函数。该程序用空格数替换选项卡。我仍然对我的函数的参数列表中的内容以及如何将main中的argc / argv传递给这些函数感到困惑。我这样做了吗?
文件顶部有一些已定义的变量:
#define OUTFILE_NAME "detabbed"
#define TAB_STOP_SIZE 8
#define NUM_ARGS 2
#define FILE_ARG_IDX 1
这是我的第二次尝试:
void open_file(FILE *inf, FILE *outf, char *in[]) /*I feel like the arguments aren't right
{ and this function is just opening
and reading files*/
inf = fopen(in[1], "r");
outf = fopen(OUTFILE_NAME, "w");
if (inf == NULL)
{
perror(in[1]);
exit(1);
}
else if (outf == NULL)
{
perror(OUTFILE_NAME);
exit(1);
}
fclose(inf);
fclose(outf);
}
void detab(FILE *infile, FILE *outfile, char *argument[]) /* Confused about argument list
{ and this function actually
char c; does the detabbing */
int character_count = 0, i, num_spaces;
open_file(infile, outfile, argument); /* I want to call the previous
function but again, confused
while (fscanf(infile, "%c", &c) != EOF) about the argument list */
{
if (c == '\t')
{
num_spaces = TAB_STOP_SIZE - (character_count % TAB_STOP_SIZE);
for (i = 0; i < num_spaces; i++)
{
fprintf(outfile, " ");
}
character_count += num_spaces;
}
else if (c == '\n')
{
fprintf(outfile, "\n");
character_count = 0;
}
else
{
fprintf(outfile, "%c", c);
character_count++;
}
}
}
int main(int argc, char *argv[])
{
if (argc < 1)
{
fprintf(stderr, "usage: prog file\n");
exit(1);
}
else if (argc < NUM_ARGS)
{
fprintf(stderr, "usage: %s file\n", argv[0]);
exit(1);
}
detab(argc, argv); /* I want to pass argc and argv to the detab function, but I'm
having trouble with the argument list */
return 0;
}
我需要帮助的是,弄清楚函数的参数列表中的内容。我觉得让我感到困惑的是如何让我的参数类型匹配,以便我可以将变量从一个函数传递给另一个函数。
答案 0 :(得分:3)
分解不是你最大的问题。相当粗心的错误检查,使用旧的超重fscanf()
和fprintf()
以及全局变量。此外,输入文件名中缺少const正确性,过长且冗长的变量名称以及您对+=
和++
运算符的不了解只是奖励。我想这就是为什么你的代码看起来很臃肿(实际上是这样)。
我会改写这样的函数:
void detab(const char *in, const char *out, int tabstop)
{
FILE *inf = fopen(in, "r");
if (!inf) return;
FILE *outf = fopen(out, "w");
if (!outf) {
fclose(inf);
return;
}
int n = 0;
int c;
while ((c = fgetc(inf)) != EOF) {
if (c == '\t') {
int pad = tabstop - n % tabstop;
for (int i = 0; i < pad; i++)
fputc(' ', outf);
n += pad;
} else if (c == '\n') {
fputc('\n', outf);
n = 0;
} else {
fputc(c, outf);
n++;
}
}
fclose(inf);
fclose(outf);
}
如果你想进一步分解它,那么你可以编写一个函数,取两个FILE *
并将制表位作为参数,它应包含while
循环只是 - 这样做是留给你的练习。
答案 1 :(得分:3)
注意:此答案是针对该问题的早期编辑提供的。它在此期间发生了变化,因此这个答案似乎不再具有相关性。
来自OOP背景,我将专注于一个称为Single Responsibility Principle (SRP)的问题。我认为 detab
(以及其他所有功能)应该只做一件具体的事情,但要做得好。
但正如其名称所暗示的那样,它不仅仅是“扣留”;它还必须从命令行变量argc
和argv
中提取其实际参数,这些变量由main
强制执行:
detab(argc, argv);
main
之前已做过一些验证,但由于命令行只是简单地传递给函数,你显然感觉在detab
继续验证(我还做了一些关于违规的补充说明)下面的SRP):
void detab(int arg_list, char *array[]) // why ask for arg_list if you don't need it?
{
…
infile = fopen(array[1], "r"); // not obvious to caller that only array[1] is relevant
…
if (infile == NULL)
{
perror(array[1]);
exit(1); // should your function really have the power to terminate the program?
}
…
}
将所有命令行验证和值提取逻辑集中在一个地方并将其重新集中在另一个地方似乎更合理;也就是说,明确界定责任。不要让一个函数的逻辑溢出到另一个函数中!
对我而言,detab
的签名应该更像是这样:
void detab(FILE *in, FILE *out);