【问题标题】:Remove the last new line in C删除 C 中的最后一个新行
【发布时间】:2011-08-07 10:39:35
【问题描述】:

我想从以下函数中删除最后一个新行:

void WriteToFile(node *tree)
{
    void Write(node*);
    fp = fopen("dictionary.txt","w");
    if(fp==NULL)
    {
        printf("Cannot open file for writing data...");
    }
    else //if(tree==NULL)
    {
        if(tree!=NULL)
        {
            Write(tree);
        }
        fclose(fp);  
    }
}
void Write(node *tree)
{
    if(tree!=NULL)
    {
        fprintf(fp,"%s:%s\n",tree->word,tree->meaning);
        Write(tree->left);
        Write(tree->right);
    }
}

我正在使用此函数将 BST 的内容写入文本文件,并且我不希望它写入最后一个新行,如何删除它?

【问题讨论】:

  • 我很好奇。你为什么不想在最后一行写一个换行符?按照惯例,文本文件的所有行都应以换行符结束,包括最后一行。

标签: c file


【解决方案1】:

在像您这样的递归例程中,您无法轻易知道哪个是最后一个调用,但您可以知道第一个调用是什么。

与其写入数据和可选的换行符,不如考虑写入可选的换行符后跟数据:

void FirstWrite(node *tree, FILE *fp)
{
    if (tree)
    {
        fprintf(fp, "%s%s", tree->word, tree->meaning);
        Write(tree->left, fp);
        Write(tree->right, fp);
    }
}
void Write(node *tree, FILE *fp)
{
    if (tree)
    {
        fprintf(fp, "\n%s%s", tree->word, tree->meaning);
        Write(tree->left, fp);
        Write(tree->right, fp);
    }
}

但考虑一下文本模式文件中最常用的行定义是:一个由 0 个或多个字符组成的序列,后跟并包括一个换行符。根据这个定义,所有行都有换行符;并且文件中的最后一条数据不是一行。

我用过的至少一个写得不好的程序因此无法处理整个输入。我的猜测是它做了类似

fgets(buf, sizeof buf, inf);
inlen = strlen(buf);
if (buf[inlen - 1] == '\n') processline(buf);

如果最后一条数据包含换行符,这个写得不好的程序会起作用。

【讨论】:

    【解决方案2】:

    修改你的函数如下:

    void Write(node *tree, int isFarRight)
    {
        if(tree!=NULL)
        {
            fprintf(fp,"%s:%s",tree->word,tree->meaning);
            if (!isFarRight || tree->left || tree->right)
            {
                fprintf(fp, "\n");
            }
            Write(tree->left, 0);
            Write(tree->right, isFarRight);
        }
    }
    
    ...
    
    Write(tree, 1);
    

    isFarRight 变量会跟踪您当前是否位于树的最右侧。如果当前节点有子节点,或者您不在最右侧,则仅打印 '\n'

    【讨论】:

      【解决方案3】:

      一旦您已经写入文件,您可以使用 ftruncate 将文件截断为大小 - 1

      size_t size = ftell(fp);
      ftruncate(fp, size - 1);
      

      在 Windows 上,使用 _chsize 而不是 ftruncate

      _chsize(fd, size - 1);
      

      【讨论】:

      • 您的回答应该指出这仅适用于符合 POSIX 的系统。
      • 谢谢奥利,我已经修改了我的答案
      【解决方案4】:

      你可以这样做:

      void Write(node *tree, int first) {
        if (tree!=NULL) {
          if (!first)
            fprintf(fp, "\n");
          fprintf(fp,"%s:%s",tree->word,tree->meaning);
          Write(tree->left, 0);
          Write(tree->right, 0);
        }
      }
      

      并在您的主目录中调用Write(tree, 1);。不漂亮,但应该可以。

      【讨论】:

      • 我建议为 first (= 1) 设置一个默认值以使其更漂亮。调用者不应该关心 Write 的实现细节
      • 那很好,但需要第二个函数——我认为你不能像在 C++ 中那样在 C 中拥有默认值。 pmg 发布了类似的内容。
      【解决方案5】:

      在写入整棵树后,您可以将文件截断 1 个字节。 How to truncate a file in C 可能会帮助您。

      通常,您可以通过知道您在最后一个节点中来尝试不写最后一个 \n,但是考虑到树的这种实现,您必须对代码进行一些更改,所以通常,第一种方法对您来说可能更快。 - Oli Charlesworth 给出了如何做到这一点的示例,我认为这种方法比截断更好(不造成伤害,而不是修复它),但两者都可以。

      【讨论】:

        【解决方案6】:

        请注意,在您的代码中,您输入了两次文本以使树的根为 NULL。因此,无需更改您的函数定义:

        void WriteToFile(node *tree)
        {
          void Write(node*);
          fp = fopen("dictionary.txt","w");
          if(fp==NULL)
          {
            printf("Cannot open file for writing data...");
          }
          else //if(tree==NULL)
          {
            if(tree!=NULL)
            {
              fprintf(fp,"%s:%s",tree->word,tree->meaning);
              Write(tree);
            }
            fclose(fp);  
          }
        }
        void Write(node *tree)
        {
          if (tree->left)
          {
            fprintf(fp,"\n%s:%s",tree->left->word,tree->left->meaning);
            Write(tree->left);
          }
        
          if (tree->right)
          {
            fprintf(fp,"\n%s:%s",tree->right->word,tree->right->meaning);
            Write(tree->right);
          }
        }
        

        【讨论】:

          【解决方案7】:

          这是否按顺序打印树,即从左到右?

          我认为递归写树应该定义如下:

          write(tree *node)
          {
              write(node->left);
              printf(.....);
              write(node->right);
          }
          

          您确定您的函数按顺序打印树吗?

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-11-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多