Удалить последнюю новую строку в C - PullRequest
2 голосов
/ 07 августа 2011

Я хочу удалить последнюю новую строку из следующей функции:

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, и я не хочу, чтобы он записывалпоследняя новая строка, как я могу удалить ее?

Ответы [ 7 ]

5 голосов
/ 07 августа 2011

В такой рекурсивной процедуре, как ваша, вы не можете легко узнать, какой последний вызов, но вы можете знать, какой первый вызов.

Вместо записи данных и, необязательно, новой строки, рассмотрите возможность написания необязательного символа новой строки, за которым следуют данные:

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);

Эта плохо написанная программа сработает, если последний фрагмент данных будет содержать символ новой строки.

3 голосов
/ 07 августа 2011

Как только вы уже записали в файл, вы можете использовать ftruncate для усечения файла до размера - 1

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

В Windows используйте _chsize вместо ftruncate

_chsize(fd, size - 1);
3 голосов
/ 07 августа 2011

Измените вашу функцию следующим образом:

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' только в том случае, если у текущего узла есть дочерние элементы или если вы не находитесь в крайней правой части.

1 голос
/ 07 августа 2011

Вы можете сделать это следующим образом:

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); на свой основной.Не красиво, но должно работать.

1 голос
/ 07 августа 2011

Вы можете обрезать файл на 1 байт после записи всего дерева. Как обрезать файл в C может помочь вам в этом.

Обычно вы можете попытаться не писать последний \ n, зная, что вы находитесь в последнем узле, , но, учитывая эту реализацию дерева, вам придется внести несколько изменений в код, поэтому, как правило, 1-й подход может быть более быстрым для вас. - пример того, как это было сделано Оли Чарльзвортом, этот подход, мне кажется, более приятен, чем усечение (не причиняя вреда, а не исправляя его), хотя оба сработают.

0 голосов
/ 07 августа 2011

Обратите внимание, что в вашем коде вы дважды пишете, чтобы корень дерева был 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);
  }
}
0 голосов
/ 07 августа 2011

Печатает ли это дерево по порядку, то есть слева направо?

Я думаю, что рекурсивное дерево записи должно быть определено следующим образом:

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

Вы уверены, что ваша функция печатает дерево по порядку?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...