【问题标题】:Weird characters saved in my text file我的文本文件中保存的奇怪字符
【发布时间】:2018-03-15 22:19:14
【问题描述】:

我正在尝试制作一个可以将某些信息存储在文本文件中的程序。我遇到的问题是,到目前为止我编写的代码中,存储的信息是一堆奇怪的符号和字符。我已经设法找出它发生在哪里,但我似乎无法解决它。似乎在我的 register_item 函数中,由于某种原因,项目编号和余额都得到了奇怪的值。如果有人能看到我犯了什么错误,那将不胜感激。

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

    #define MAX 20

    struct vara
    {
        int itemnumber[20];
        char name[30];
        int balance[20];
    };

    open_file(FILE *ange_filnamn, char filnamn[], struct vara varor[], int *antal_varor)
    {
        int mainmenu = 0;
        while (mainmenu != 1 && mainmenu != 2)
        {
            printf("Do you want to open an existing file (1) or create a new one (2)?\n");
            scanf("%d", &mainmenu);
            //system("CLS");
            if(mainmenu==1)
            {
                printf("Choose filename (ex. .txt).\n");
                scanf("%s", filnamn);
                ange_filnamn=fopen(filnamn, "r+");         

                while(!feof(ange_filnamn))
                {

                    fread(&varor[*antal_varor], sizeof(struct vara), 1, ange_filnamn);
                    if(!feof(ange_filnamn))
                    {
                        *antal_varor=*antal_varor + 1;        
                    }
                }
                printf("\nNumber of items: %d \n",*antal_varor);
                fclose(ange_filnamn);              
            }

            if(mainmenu==2)
            {
                printf("What name do you want for your new file?\n");
                scanf("%s", filnamn);
                ange_filnamn=fopen(filnamn, "w+");
                printf("File is created!\n");
                *antal_varor = 0;                 
                fclose(ange_filnamn);               
            }
        }
    }

    register_item(struct vara *varor, int *antal_varor)
    {
        printf("Item number:\n");                             
        scanf("%d", varor[*antal_varor].itemnumber);    
        printf("Name:\n");
        scanf("%s", varor[*antal_varor].name);
        printf("Balance:\n");
        scanf("%d", varor[*antal_varor].balance);   
        *antal_varor+=1;
    }

    print_item(struct vara varor[], int antal_varor)
    {
        int i;
        for (i=0; i < antal_varor; i++)
        {
            printf("%d. Item number: %d Name: %s Balance: %d\n", i, varor[i].itemnumber, varor[i].name, varor[i].balance);         
        }
    }

    quit_program(char filnamn[], struct vara varor[], int *antal_varor)
    {
        FILE *fil;
        //printf("%s", filnamn);
        fil=fopen(filnamn, "w+");                                             
        fwrite(varor, sizeof(struct vara), *antal_varor, fil);
        fclose(fil);
    }

    int main(void)
    {
        FILE *ange_filnamn;
        struct vara varor[MAX];
        int mainmenu, menu, antal_varor=0;
        char filnamn[20], filen[30]; 

        open_file(ange_filnamn,filnamn, varor, &antal_varor);

        //Second menu
        while(menu!=7)
        {
            printf("\n");
            printf("1. Register new items to inventory.\n");
            printf("2. Print all items from inventory.\n");
            printf("3. Search for item.\n");
            printf("4. Change inventory.\n");
            printf("5. Sort inventory.\n");
            printf("6. Deregister item from inventory.\n");
            printf("7. Quit.\n");
            scanf("%d", &menu);

            if(menu==1)
            {
                register_item(varor, &antal_varor);
            }

            if (menu==2)
            {
               print_item(varor, antal_varor); 
            }

            if (menu==3)
            {
                printf("test");
            }

            if (menu==4)
            {
                printf("test");
            }

            if (menu==5)
            {
                printf("test");
            }

            if(menu==6)
            {
                printf("test");
            }
            if (menu==7)
            {
                quit_program(filnamn, varor, &antal_varor);
            }
        }
    }

【问题讨论】:

  • 写入文件的是vara结构的实际内存表示。特别是整数以二进制表示形式写入(而不是您可能期望的文本)。出现了一些问题,但一般来说你没问题。
  • 您正在编写二进制数据,那么您期望什么?您可能应该使用fprintf 而不是fwrite
  • 对不起,我真的是编程新手。你是什​​么意思我在写二进制数据。那么fwrite是用来写二进制数据的呢?
  • 其他cmets指的是这一行,这就是你的麻烦来源:fwrite(varor, sizeof(struct vara), *antal_varor, fil)。你想用一系列的fprintf 调用来替换它,比如fprintf(fil, "name: %s\n", scanf("%s", varor[i].name);
  • 您将一系列ints 写入文件。 “奇怪的符号”是ints 存储在内存中时的样子。将数据存储为二进制文件并没有错,只是您无法轻松读取。

标签: c file text input


【解决方案1】:

你有一个结构数组。该数组包含antal_varor个结构,每个结构包含成员(元素)itemnumbernamebalance

在我们开始之前,请注意一点:我认为您的结构定义存在一些错误。根据您使用它的方式,我认为您想要

struct vara
{
    int itemnumber;
    char name[30];
    int balance;
};

但你的问题是关于写出文件。当你打电话时

fwrite(varor, sizeof(struct vara), *antal_varor, fil);

您正在以“二进制”的形式一次性写出整个数组,这就是您无法读取它的原因。如果你想以更易于阅读的形式写出来,你可以做这样的事情。在这里,我对数组的元素进行了显式循环,每次循环时,我都会打印出该元素的所有成员:

int i;
for(i = 0; i < *antal_varor; i++ {
    fprintf(fil, "varor %d:\n", i);
    fprintf(fil, " itemnumber: %d\n", varor[i].itemnumber);
    fprintf(fil, " name: %s\n", varor[i].name);
    fprintf(fil, " balance: %d\n", varor[i].balance);
}

所以,首先尝试一下。您应该会发现输出文件完全可读。

现在,问题在于,由于您以这种更好、更易读的格式写出文件,因此您的代码将数据读回,过去使用

fread(&varor[*antal_varor], sizeof(struct vara), 1, ange_filnamn);

不会再工作了。但这里是你可以用来读回新格式文件的代码。这段代码用fgets逐行读取文件,弄清楚每一行是什么,并将数据项一个接一个地插入@ 987654330@ 数组来重建它。

char line[80];
int i = 0;
*antal_varor = 0;

while(fgets(line, sizeof(line), ange_filnamn) != NULL) {
    if(strncmp(line, "varor ", 6) == 0) {
        sscanf(line, "varor %d:", &i);
        if(i >= MAX) {
            fprintf(stderr, "warning: index in file too large\n");
            i = 0;
            continue;
        }
        if(i + 1 > *antal_varor) *antal_varor = i + 1;
    } else if(strncmp(line, " itemnumber:", 12) == 0) {
        sscanf(line, " itemnumber: %d", &varor[i].itemnumber);
    } else if(strncmp(line, " name:", 6) == 0) {
        sscanf(line, " name: %s", varor[i].name);
    } else if(strncmp(line, " balance:", 9) == 0) {
        sscanf(line, " balance: %d", &varor[i].balance);
    } else {
        fprintf(stderr, "warning: unrecognized line in file\n");
    }
}

printf("\nNumber of items: %d \n",*antal_varor);
fclose(ange_filnamn); 

我没有测试过这个,所以可能会有一些小错误,但它应该给你的想法。

(也有更好的方法来编写这类东西,但它们更复杂或需要更多的基础设施,所以我坚持使用非常简单易懂的东西,尽管它不够健壮。)

【讨论】:

  • 我怀疑你打算while(fgets(line, sizeof(line), ange_filnamn) != NULL)...注意fread -&gt; fgets。但否则这是一个很好的答案。
  • 我对您对我的结构的提示有疑问。当我删除方括号时,只要我输入项目编号的值,程序就会崩溃。当我有方括号时,它不会打印出我输入的值。出于某种原因,我得到了其他数字,例如 643829。这发生在 itemnumber 和 balance 上。
  • @Camel 你犯了scanf 最常见的第一个错误。在register_item() 中,当您提示输入itemnumberbalance 时,您需要使用&amp; 以便scanf 收到一个可以填写的指针:scanf("%d", &amp;varor[*antal_varor].itemnumber);。 (你不需要 &amp;name,因为 name 是一个数组。)我知道,这首先令人困惑。
  • @SteveSummit 天哪。当然。为愚蠢的错误道歉。 char 数组让我很困惑。
【解决方案2】:

您问题的评论者说得对。
- 使用 printf 显示的内容(并使用 fprintf 写入文件)是数字的 ASCII 表示。
- 存储在内存中(并使用 fwrite 写入)的是实际的“二进制”值。
在 C 中,一个 int 变量总是在内存中占用相同数量的字节,而不管存储的值是多少。这就是为什么您的 sizeof() 始终如一地工作的原因。阅读和写作可以始终如一地进行。

(请注意,并非所有 C 实现都使用相同大小的 int。在我现在使用的 x86 Linux 中它是 4 个字节)。

显示 ASCII 表示时,所需的 ASCII 数字字符数取决于值。因此,如果读取的值以这种方式存储,您必须“解析”文本并从读取的数字中构建整数值,并且通常是可变位数。 (这就是 scanf 所做的。)因此,可以认为读取和解析 ASCII 比仅读取存储为始终相同大小的二进制 int 的值更复杂。

重要提示:如果要以二进制形式读取文件,则应使用“b”属性打开它,如下所示:

ange_filnamn=fopen(filnamn, "r+b");

类似,打开二进制写入:

fil=fopen(filnamn, "w+b"); 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-31
    • 2017-08-25
    • 2015-02-09
    • 1970-01-01
    • 1970-01-01
    • 2021-01-15
    • 2020-05-24
    • 2021-05-26
    相关资源
    最近更新 更多