C二进制文件工作不正常

C二进制文件工作不正常,c,struct,C,Struct,我有一个问题。这是一个家庭作业,无法理解。这个简单的程序要求用户将其姓名和电话号码写入一个文件,如果它找到RDS电话号码ex(0*3*12415324),则将其所有者和电话号码写入一个二进制文件。 问题是程序没有将任何内容写入二进制文件(output.dat) 到目前为止,我做到了: #include <stdio.h> #include <stdlib.h> typedef struct { char name[50]; char tel[50];

我有一个问题。这是一个家庭作业,无法理解。这个简单的程序要求用户将其姓名和电话号码写入一个文件,如果它找到RDS电话号码ex(
0*3*12415324
),则将其所有者和电话号码写入一个二进制文件。 问题是程序没有将任何内容写入二进制文件(output.dat)

到目前为止,我做到了:

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


typedef struct
{
    char name[50];
    char tel[50];

} PERSON;



int main()
{
    FILE *fin,*fout;
    int n, i;
    PERSON p[50];
    fin = fopen("input.txt","rt");
    fout = fopen("output.dat","wb");
    fscanf(fin,"%i", &n);
    for (i=0; i<n; ++i)
    {
        fscanf (fin,"%s%s", p[i].name, p[i].tel);
    }
    for (i=0; i<n; ++i){
        if (p[i].tel[1]=='3'){
            fwrite(p[i].name,sizeof(PERSON),n,fout);
            fwrite(p[i].tel,sizeof(PERSON),n,fout);
        }
    }

    fclose(fin);
    fclose(fout);

    return 0;
}
#包括
#包括
类型定义结构
{
字符名[50];
电话[50];
}人;
int main()
{
文件*fin,*fout;
int n,i;
人p[50];
fin=fopen(“input.txt”、“rt”);
fout=fopen(“output.dat”、“wb”);
fscanf(fin、%i、&n);

对于(i=0;i当我运行你的代码时,我得到一个segfault。运行揭示了问题

==75112== Invalid read of size 8
==75112==    at 0x1001D0C5F: flockfile (in /usr/lib/system/libsystem_c.dylib)
==75112==    by 0x1001D303C: fscanf (in /usr/lib/system/libsystem_c.dylib)
==75112==    by 0x100000D42: main (test.c:21)
==75112==  Address 0x68 is not stack'd, malloc'd or (recently) free'd
==75112== 
==75112== 
==75112== Process terminating with default action of signal 11 (SIGSEGV)
==75112==  Access not within mapped region at address 0x68
==75112==    at 0x1001D0C5F: flockfile (in /usr/lib/system/libsystem_c.dylib)
==75112==    by 0x1001D303C: fscanf (in /usr/lib/system/libsystem_c.dylib)
==75112==    by 0x100000D42: main (test.c:21)
fscanf
被传递了一个伪造的文件句柄,因为
fopen
失败。在这种情况下,我没有
input.txt
。请始终检查
fopen
的结果。我使用包装器函数确保这种情况始终发生

#include <errno.h>
#include <string.h>

FILE *open_file(const char *filename, const char *mode) {
    FILE *fp = fopen(filename, mode);
    if( fp == NULL ) {
        fprintf(stderr, "Could not open %s: %s.\n", filename, strerror(errno));
        exit(errno);
    }

    return fp;
}

好的,
触摸input.txt
并再次运行。再次执行另一个segfault.Valgrind

==75478== Conditional jump or move depends on uninitialised value(s)
==75478==    at 0x100000D0F: main (test.c:32)
==75478== 
==75478== Conditional jump or move depends on uninitialised value(s)
==75478==    at 0x100000D91: main (test.c:36)
==75478== 
==75478== Conditional jump or move depends on uninitialised value(s)
==75478==    at 0x100000DB9: main (test.c:37)
前两个是关于
n
,因为input.txt是空的,所以它没有初始化。本来应该填充它的
fscanf
失败了,所以
n
包含它开始时使用的任何垃圾。循环根据
n
中的垃圾运行随机次数。它尝试从input.txt读取,但失败了
p
未初始化,也包含垃圾

第三个错误是关于尝试读取
p
n
中包含垃圾的垃圾,因此for循环尝试从未初始化的
p
数组中读取

这一切都可以通过初始化
n
和之前一样,检查
fscanf
是否工作来解决。同样,包装函数确保检查错误

int scan_check(FILE *restrict stream, const char *restrict format, ...) {
    va_list args;
    va_start(args, format);
    int ret = vfscanf(stream, format, args);

    if( ret <= 0 ) {
        fprintf(stderr, "Could not match input to '%s'.\n", format);
        exit(errno);
    }

    return ret;
}
这说明
fwrite
调用有问题

fwrite(p[i].name,sizeof(PERSON),n,fout);
fwrite(p[i].tel,sizeof(PERSON),n,fout);
这意味着要编写
n
项,每个项的大小与
PERSON
结构相同。如果您编写所有
p
,这将很好。但您只编写一个姓名和一个电话号码。相反,您希望编写与字符串长度相等的字符,加上一个表示空字节的字符

fwrite(p[i].name, sizeof(char), strlen(p[i].name)+1, fout);
fwrite(p[i].tel,  sizeof(char), strlen(p[i].tel)+1 , fout);

最后,综上所述,valgrind没有抱怨

int main()
{
    int n = 0;
    PERSON p[50];

    FILE *fin = open_file("input.txt","rt");
    FILE *fout = open_file("output.dat","wb");

    scan_check(fin,"%i", &n);

    for (int i=0; i<n; ++i)
    {
        scan_check(fin,"%s%s", p[i].name, p[i].tel);
    }

    for (int i=0; i<n; ++i){
        if (p[i].tel[1]=='3'){
            fwrite(p[i].name, sizeof(char), strlen(p[i].name)+1, fout);
            fwrite(p[i].tel,  sizeof(char), strlen(p[i].tel)+1 , fout);
        }
    }

    fclose(fin);
    fclose(fout);

    return 0;
}

n
同样是不必要的。没有必要用
input.txt
来告诉您有多少条记录,而是读取文件直到
eof(fin)
。这避免了
n
不准确。

您必须检查所有系统调用的返回值。(如fopen、fwrite等)使用调试器或在代码的关键位置放置一些
printf
s,以便查看发生了什么。顺便说一句:您的程序不会向用户询问任何问题。作为旁注,您的
fwrite
的第二个和第三个参数毫无意义;
p[i]。name
p[i].tel
是50个字符的数组,而不是
n
PERSON
@altermann C没有将
“rt”
定义为无效,而是未定义。在OP的平台上
“rt”
可以很好地定义。C:\Users\zsombi\Desktop\Egyetem\Programozas II\Labor 3\RDSbinarisan\main.C | 42 |错误:应为“;”、“,”或“)'在'stream'| |===生成失败之前:1个错误,4个警告(0分钟,0秒))====我知道这个错误,但它不需要更改。@Zsombi抱歉,我不知道第42行是什么,但我想我知道发生了什么。我故意遗漏了一些包含,所以你不能直接剪切和粘贴。。。)
fwrite(p[i].name, sizeof(char), strlen(p[i].name)+1, fout);
fwrite(p[i].tel,  sizeof(char), strlen(p[i].tel)+1 , fout);
int main()
{
    int n = 0;
    PERSON p[50];

    FILE *fin = open_file("input.txt","rt");
    FILE *fout = open_file("output.dat","wb");

    scan_check(fin,"%i", &n);

    for (int i=0; i<n; ++i)
    {
        scan_check(fin,"%s%s", p[i].name, p[i].tel);
    }

    for (int i=0; i<n; ++i){
        if (p[i].tel[1]=='3'){
            fwrite(p[i].name, sizeof(char), strlen(p[i].name)+1, fout);
            fwrite(p[i].tel,  sizeof(char), strlen(p[i].tel)+1 , fout);
        }
    }

    fclose(fin);
    fclose(fout);

    return 0;
}
PERSON p;

....

for (int i=0; i<n; ++i)
{
    scan_check(fin,"%s%s", p.name, p.tel);

    if (p.tel[1]=='3'){
        fwrite(p.name, sizeof(char), strlen(p.name)+1, fout);
        fwrite(p.tel,  sizeof(char), strlen(p.tel)+1 , fout);
    }
}