【问题标题】:I tried decomposing my function, but I'm not sure if I did it right我尝试分解我的函数,但我不确定我是否做对了
【发布时间】:2013-05-28 00:49:58
【问题描述】:

本来这个函数是嵌入到main函数中的,造成了一个非常杂乱的main函数。该程序用空格数替换制表符。我仍然对我的函数的参数列表中的内容以及如何将 argc/argv 从 main 传递到这些函数感到困惑。我这样做对吗?

文件顶部有一些已定义的变量:

#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;
}

我需要帮助的是弄清楚函数的参数列表中的内容。我认为让我感到困惑的是如何让我的参数类型匹配,以便我可以将变量从一个函数传递给另一个函数。

【问题讨论】:

  • 函数的存在是为了以后重用代码sn-ps。如果你的函数只被调用一次,我认为这可能是一个未成熟的优化。
  • @Summer_More_More_Tea No.
  • @H2CO3 谢谢,看看。

标签: c file space decomposition


【解决方案1】:

注意:此答案是针对问题的早期编辑给出的。同时它已经发生了变化,所以这个答案可能不再相关。

来自 OOP 背景,我将专注于一个名为 Single Responsibility Principle (SRP) 的问题。我认为 detab(以及所有其他函数)应该只做一件特定的事情,但要把那件事做好。

但它不仅仅是“detab”,正如它的名字所暗示的那样;它还必须从argcargv 的命令行变量中提取其实际 参数,这是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?
   }
   …
}

将所有命令行验证和值提取逻辑集中在一个地方,而将 detabbing 集中在另一个地方似乎更合理;也就是划清责任界限。不要让一个功能的逻辑溢出到另一个功能!

对我来说,detab 的签名应该更像例如这个:

void detab(FILE *in, FILE *out);

【讨论】:

  • 如果我有两个函数(就像我上面提到的那样),并且我想在第二个函数中调用第一个函数,我将如何构造参数列表?我在尝试匹配参数类型时遇到了麻烦,如果我在顶部有这些定义的变量,我的代码将如何变化?谢谢!
  • 您已将原始问题更改为其他问题。这通常会导致以前的答案变得过时,并开始一个开放式问答乒乓球,这不是 Stack Overflow 应该如何工作的。如果您有后续问题,请将其作为一个新问题提出,这样人们就不必在这里一遍又一遍地修改他们的答案。谢谢!
【解决方案2】:

分解不是你最大的问题。错误检查比较粗心,使用旧的超重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 循环 - 这样做留给你作为练习。

【讨论】:

  • 那么如果我这样做,那么在主函数中,我将如何将 argc 和 argv 传递给 detab 函数? (由于参数类型不匹配/detab 有三个参数)
  • @Karen void other_function(FILE *inf, FILE *outf, int tabstop)
  • 所以其他函数只包含while循环对吗?但我遇到的问题是 main 在它的参数列表中只有 argc 和 argv 。那么在主函数内部,当我调用这个其他函数时,如何处理其他函数的参数列表中的三个参数?
  • @Karen detab 的签名是void detab(const char *in, const char *out, int tabstop)。您以某种方式获得了这些论点,对吗?例如,您从 main 调用它,例如 detab(argv[1], argv[2], 8)
  • 谢谢!所以为了澄清,我可以把它分成两个不同的功能。在第一个函数中,我所做的只是打开文件,检查我是否能够打开文件,然后关闭这两个文件。而在我的第二个函数中,我只有 while 循环,这就是我的程序实际 detab 的地方吗?
猜你喜欢
  • 1970-01-01
  • 2019-10-19
  • 2014-03-23
  • 1970-01-01
  • 1970-01-01
  • 2021-06-25
  • 2021-08-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多