【问题标题】:Implementing chain of responisiblity in C with FILE* and array of structs使用 FILE* 和结构数组在 C 中实现责任链
【发布时间】:2021-05-30 00:57:07
【问题描述】:

我的目标是创建一个从 CMD 直接写入文本文件的程序。

如果输入字符串是以下字符串之一: -exit -count -remove

它将执行退出程序/计算文件中的行数/删除文件的任务。

我编写的代码在我的脑海中基本上看起来“不错”,但在纸上(在显示器上)它很糟糕。

main function 100% 有效(无需调用InputCmp function。 我不明白为什么我不能真正将这些结构相互连接起来。

我想创建一个按以下方式工作的责任链: 假设用户写入字符串:"-exit",但 exit 是 3 结构(数组中的索引 2)。

所以我希望将字符串发送到一个函数(我写的那个叫做InputCmp),它将检查strcmp 与第一个结构内的字符串,即-remove。 如果不匹配,它将与数组中的下一个结构进行比较。 直到找到第 3 个结构体,里面有确切的字符串,然后它会运行一个退出函数。

但是,这里的主要问题是以某种方式将FILE* 从一个函数转移到另一个函数。我的意思是我需要将它从main 转移到InputCmp 并从InputCmp 转移到每个函数,因为countremove 需要该文件才能运行。

我刚刚迷路了。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define BUFF_SIZE 1024

/******************************************************/

struct processor
{
        char *task;
        void (*InputCmp)(char*, size_t);
        void (*RunTask)(char*);
};
 
struct processor handlers[3];

handlers[0].task = "-remove";
handlers[1].task = "-count";
handlers[2].task = "-exit";
handlers[0].RunTask = RemoveFile;
handlers[1].RunTask = CountLines;
handlers[2].RunTask = ExitProgram;

/******************************************************/

int RemoveFile(char *string) /* needs somehow to get filename */
{ 

   if (remove(filename) == 0) 
      printf("Deleted successfully"); 
   else
      printf("Unable to delete the file"); 
  
   return 0; 
   
} 

/******************************************************/

void CountLines(char *string) /* needs somehow to get filename */
{
    FILE *fileptr;

    int count_lines = 0;

    char chr;

    fileptr = fopen(filename, "r");

    chr = getc(fileptr);

    while (chr != EOF)

    {

        if (chr == 'n')

        {

            count_lines = count_lines + 1;

        }

        chr = getc(fileptr);

    }

    fclose(fileptr); //close file.

    printf("Lines: %d",count_lines);

}

/******************************************************/

void ExitProgram(char *string)
{
    exit(1);
}


/******************************************************/

 int InputCmp(char *string, size_t index)
{
    assert(string);
    
    if (0 == strcmp(string, handlers[index].task))
    {
        return handlers[index].RunTask(string);
    }
    return handlers[index+1].InputCmp(string,index+1);
} 

/******************************************************/

int is_file_exists(char *file_name)
{
    
    FILE *file;
    if ((file = fopen(file_name,"r"))!=NULL)    
        {
            /* file exists */
            fclose(file);
            return 1;
        }    
    else  
        {
            /*File not found, no memory leak since 'file' == NULL
            fclose(file) would cause an error */
            return 0;
        }
        
}

/******************************************************/

int main(int argc, char **argv)
{
    char c;
    FILE *file;
    char buffer[BUFF_SIZE];

    if (argc >= 2)
    {
         if (is_file_exists(argv[1]))
         {
             file = fopen(argv[1], "a");
         }
         else
         {
             return 0;
         }
    }
    else
    {
         file = fopen("file.txt", "a");
    }

    while(1)
    {
    size_t i = 0;
    memset(buffer, 0, BUFF_SIZE);
    while ((c = getchar()) != '\n' && i < BUFF_SIZE)
    buffer[i++] = c;
    InputCmp(buffer, 0);
        buffer[i] = '\n';
        fputs(buffer, file); 
    }

    fclose(file);
    return 0;
}

【问题讨论】:

  • 永远不要在 C 程序中说“100% 有效”;)
  • 你总是可以使用getopt 来解析命令行参数。您应该使用stat,而不是打开文件进行阅读。

标签: arrays c file struct chain-of-responsibility


【解决方案1】:

不幸的是你cannot derive the filename from the FILE object

要解决这个问题,您首先必须移动这些:

handlers[0].RunTask = RemoveFile;
handlers[1].RunTask = CountLines;
handlers[2].RunTask = ExitProgram;

在主函数中,并纠正你函数中的小错误(比如\n不是n,\n允许换行):

int RemoveFile(char *filename)
{
   if (remove(filename) == 0)
      printf("Deleted successfully\n");
   else
      printf("Unable to delete the file\n");
   return 0;
}

void (*RunTask)(char*, void*);

/******************************************************/

void CountLines(char *filename)
{
    FILE *file = fopen(filename, "r");
    int count_lines = 0;
    char chr;

    chr = getc(file);

    while (chr != EOF)
    {
        if (chr == '\n')
        {
            count_lines = count_lines + 1;
        }
        chr = getc(file);
    }
    fclose(file); //close file.
    printf("Lines: %d\n",count_lines);
}

/******************************************************/

void ExitProgram(char *s)
{
    (void)s; // to allow compilation with -Wall -Werror
    exit(EXIT_SUCCESS);
}

在您的 main 中,您调用如下函数:

handlers[0].RunTask("file.txt");
handlers[1].RunTask("file.txt");
handlers[2].RunTask("file.txt");

或:

CountLines("file.txt");
RemoveFile("file.txt");
ExitProgram("");

【讨论】:

  • 我想我找到了一个更好的解决方案,它只是将file pointer 定义为一个全局变量,所以我不需要将它从一个函数移动到另一个函数。我将能够按原样使用它。但我仍然坚持定义所有结构并将其连接到一个工作链。
  • 你也可以在函数指针内部使用 (void *),然后将 ptr (void *) 赋值给 FILE 或任何类型:void CountLines(char *filename, void *ptr) { FILE *file = (FILE *)ptr; }
  • 为什么我必须将定义 a.k.a handlers[0].RunTask = RemoveFile 移动到 main 并且不能像我做 structs 数组一样把它放在任何函数之外?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-08
  • 2016-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多