【问题标题】:C Programming output text fileC 编程输出文本文件
【发布时间】:2017-03-01 03:36:39
【问题描述】:

您好,我刚开始编程,有一个初学者问题: 我想更好地理解 fprint() 函数是如何工作的,因为有时当我用它创建一个文本文件时,我意识到有各种类型的文件,例如(只读、追加和写入)。当我想在循环创建的文件上写入内容时,添加内容的顺序似乎发生了变化

file = fopen(name,"a+");

如果是,我不能在循环中添加所有内容

file = fopen(name,"w");

那么创建文本文件最方便的方法是什么? 谢谢!

假设我想写出 trie 树中的所有单词,文本文件中的顺序与将 fprint() 替换为 print() 不同 我有一个树的全局节点和一个指向它的节点指针以用于其他功能

struct node *root = (struct node *)malloc(sizeof(struct node));

而功能是:

void printResult(struct node* r){
struct node *p = r;
FILE *file;
sprintf(name, "man%d.txt", num);
file = fopen(name,"a+");
int i=0;
int temp;
while(i!=26){
 if(p->child[i]==NULL){
  i++;
  continue;}
 if(p->child[i]->isword==1&&p->child[i]->leaf==1){
  word[k]=i+'a';
  word[k+1]='\0';
  fprintf(file,"%s", word);fprintf(file,"%s"," " );
  fprintf(file,"%d", p->child[i]->occurrence);fprintf(file,"%s"," " );
  fprintf(file,"%d\n", p->child[i]->super);
  i++;
  continue;} 
 if(p->child[i]->isword==0){
  word[k]=i+'a';
  temp=k;
  k++;
  p=p->child[i];
  printResult(p);
  k=temp;
  p=p->parent;
  }
 if(p->child[i]->isword==1&&p->child[i]->leaf==0){
  word[k]=i+'a';
  word[k+1]='\0';
  temp=k;
  k++;
  p->child[i]->isword=0;
  fprintf(file,"%s", word);fprintf(file,"%s"," " );
  fprintf(file,"%d", p->child[i]->occurrence);fprintf(file,"%s"," " );
  fprintf(file,"%d\n", p->child[i]->super);
  p=p->child[i];
  printResult(p);
  k=temp;
  p=p->parent;
}
 i++;
}fclose(file);
}

还有节点:

struct node{   
struct node * parent;
int noempty;
int isword;
int super;
int occurrence;
int leaf;
struct node * child[26];
};

最后是插入函数

struct node* insert(struct node *root,char *c){
int i=0;
struct node *temp=root;
int l=length(c);
while(i!=l){
int index=c[i]-'a';
if(temp->child[index]==NULL){
//New Node
struct node *n=(struct node *)malloc(sizeof(struct node)); 
n->parent=temp;
temp->child[index]=n;
temp->noempty=1;}
//Node Exist
if(i!=l&&temp->leaf==1){temp->leaf=0;}
temp=temp->child[index];
i++;}
if(temp->noempty==0){
temp->leaf=1;}
temp->isword=1;
return root;
 };

【问题讨论】:

  • 我不明白你的问题。如果您以“a”模式打开文件,则所有写入都将转到文件末尾。如果您以“w”模式打开,那么所有写入都将转到您执行写入时的当前位置。如果您以“r”模式打开,则写入将失败。创建文件的“最方便”的方式取决于您希望写入的行为方式。可能fopen(name, "w") 最方便。
  • @WilliamPursell 如果我想创建一个文件并写入文件顶部怎么办?我正在尝试编写一个函数,当我使用 print() 时,顺序是正确的,但是当我使用 fprint() 以相同的顺序将它们写入文件时,它不起作用,而且顺序似乎真的很随机​​。
  • “写入文件顶部”是什么意思?如果您的意思是“重复更改第一行”,这是可行的(但不适用于"a" 模式)。如果您的意思是“在文件开头插入一行(将前面的行向下推到文件中)”,那么它是不可行的;它很快变得非常昂贵。
  • 对不起,我在评论中写错了,我的意思是逐行写内容
  • 五个调用——fprintf(file,"%s", word);fprintf(file,"%s"," " ); fprintf(file,"%d", p->child[i]->occurrence);fprintf(file,"%s"," " ); fprintf(file,"%d\n", p->child[i]->super);——应该是一个调用:` fprintf(file,"%s %d %s\n", word, p->child[i]->occurrence, p->child[i]->super);`

标签: c file output


【解决方案1】:

chat讨论后,我们提出:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define length(x) strlen(x)

struct node
{
    struct node *parent;
    int noempty;
    int isword;
    int super;
    int occurrence;
    int leaf;
    struct node *child[26];
};

static struct node *root = 0;
static char word[1024];
static int k = 0;

static
void printResult(FILE * file, struct node *r)
{
    struct node *p = r;
    int i = 0;
    int temp;
    while (i != 26)
    {
        if (p->child[i] == NULL)
        {
            i++;
            continue;
        }
        if (p->child[i]->isword == 1 && p->child[i]->leaf == 1)
        {
            word[k] = i + 'a';
            word[k + 1] = '\0';
            fprintf(file, "%s", word);
            fprintf(file, "%s", " ");
            fprintf(file, "%d", p->child[i]->occurrence);
            fprintf(file, "%s", " ");
            fprintf(file, "%d\n", p->child[i]->super);
            i++;
            continue;
        }
        if (p->child[i]->isword == 0)
        {
            word[k] = i + 'a';
            temp = k;
            k++;
            p = p->child[i];
            printResult(file, p);
            k = temp;
            p = p->parent;
        }
        if (p->child[i]->isword == 1 && p->child[i]->leaf == 0)
        {
            word[k] = i + 'a';
            word[k + 1] = '\0';
            temp = k;
            k++;
            p->child[i]->isword = 0;
            fprintf(file, "%s", word);
            fprintf(file, "%s", " ");
            fprintf(file, "%d", p->child[i]->occurrence);
            fprintf(file, "%s", " ");
            fprintf(file, "%d\n", p->child[i]->super);
            p = p->child[i];
            printResult(file, p);
            k = temp;
            p = p->parent;
        }
        i++;
    }
}

static
struct node *insert(struct node *root, char *c)
{
    int i = 0;
    struct node *temp = root;
    int l = length(c);
    while (i != l)
    {
        int index = c[i] - 'a';
        if (temp->child[index] == NULL)
        {
// New Node
            struct node *n = (struct node *)malloc(sizeof(struct node));
            n->parent = temp;
            temp->child[index] = n;
            temp->noempty = 1;
        }
// Node Exist
        if (i != l && temp->leaf == 1)
        {
            temp->leaf = 0;
        }
        temp = temp->child[index];
        i++;
    }
    if (temp->noempty == 0)
    {
        temp->leaf = 1;
    }
    temp->isword = 1;
    return root;
}

int main(void)
{
    root = (struct node *)malloc(sizeof(struct node));
    memset(root, '\0', sizeof(*root));

    char line[1024];

    while (fgets(line, sizeof(line), stdin) != 0)
    {
        line[strcspn(line, "\n")] = '\0';
        printf("[%s]\n", line);
        root = insert(root, line);
    }

    FILE *file;
    char name[1024];
    int num = 0;
    sprintf(name, "man%d.txt", num);
    file = fopen(name, "w");

    printResult(file, root);

    fclose(file);

    return 0;
}

给定输入文件:

elephant
rhinoceros
mouse

man0.txt 的输出是:

elephant 0 0
mouse 0 0
rhinoceros 0 0

这并不令人兴奋;每个单词都从自己的节点开始。

同样,给定输入:

boo
book
booking
john
tex
text

输出是:

boo 0 0
book 0 0
booking 0 0
john 0 0
tex 0 0
text 0 0

似乎指定printResults() 的任务不能接受任何参数。这使得递归函数的生活变得异常困难。显示的代码将一个节点传递给函数 - 以及要写入的文件流。它使用"w" 打开文件而不是"a+"。由于从未读取过该文件,因此不需要+;使用"a" 而不是"w" 意味着该信息已附加到上次运行的文件中。

全局变量太多;我开始的时候还有更多。 k 不应该仍然是全局的,但我还没有删除它。

【讨论】:

    【解决方案2】:

    创建文本文件最方便的方法是什么?

    我想写出 trie 树中的所有单词,文本文件中的顺序将不同于仅将 fprint() 替换为 print() 我有一个树的全局节点和一个指向它的节点指针其他功能

    为了最方便地将 trie 写入磁盘,如果您可以将 整个 trie 引用为数组,将会有很大帮助。即不要只拥有导致单独分配的root;让一切引用同一个数组!然后就像将节点直接从数组写入磁盘一样简单,前提是您不需要为其他实现转换整数,或者为其他实现转换整数......并且您无需担心差异在a+w 之间。

    使用单一分配还有其他好处:

    • 一次分配意味着一次免费,这双重意味着您的代码会更快。 (实际上,不需要分配,如下所示)
    • 缓存一致性;单个分配可能比多个分配更好地缓存为一个条目。这将以可移植的方式减少缓存未命中,从而减少需要的非可移植手动优化。同样,您的代码会更快。
    • 实际上有多少 C 标准函数在后台分配内存?没有,当然除了内存分配函数... 作为这些函数的用户,这对您有什么好处?如果您考虑一下,您可以编写代码@987654326 @-free,所以调用者决定使用什么类型的分配(自动存储持续时间、静态存储持续时间、malloc/realloc)类似于scanfstrcatsprintf 等让您选择...这使得测试更容易,例如您可以检查my PATRICIA trie test codemy PATRICIA library code 以查看我不需要使用mallocfree 进行测试,这使测试看起来更清晰......更不用说,在某些用例中mallocfree 不是最佳选择!

    最后一点特别有用,因为它允许调用者将数据作为扩展存储在 trie 节点中,而不是像您所做的那样在外部指向数据。这使得编写文件变得更加容易,因为从技术上讲,如果所有信息都在那里,您可以一举将整个数组转储到文件中。深思熟虑:您认为使用 RAM 作为缓存级别的基于磁盘的 trie 是否可行?

    【讨论】:

    • 文件函数通常为缓冲区等分配内存。当然,分配的内存由fclose() 释放,无需其他用户干预。
    • 是的,@JonathanLeffler。各种线程相关的函数也分配资源。然而,它们很少而且相距甚远,而且出于这个原因,它似乎设计得不是特别好。谁想要FILE 的数组,嗯? ;)
    猜你喜欢
    • 1970-01-01
    • 2011-08-30
    • 1970-01-01
    • 1970-01-01
    • 2021-01-22
    • 2014-06-11
    • 2023-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多