Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C'的怪异行为;s文件IO_C_File Io_Undefined Behavior - Fatal编程技术网

C'的怪异行为;s文件IO

C'的怪异行为;s文件IO,c,file-io,undefined-behavior,C,File Io,Undefined Behavior,我一直在写一个虚拟机,我注意到发生了一些奇怪的事情,尽管我很久以前写过这个函数。无论如何,我的虚拟机读取的文件如下: 0002 000A 0001 0004 0000 但是,当我在0000或新行之后没有任何空格时。。。它崩溃了。另一件非常奇怪的事情,让我相信它不是文件加载,是当你从文件中删除0000和空白。。。行吗?!我试着通过GDB运行它,但它实际上是有效的——显然这被称为海森堡或其他什么。我认为这是由于文件的加载方式,您可以在中看到,或者只是阅读下面的片段 void load_progra

我一直在写一个虚拟机,我注意到发生了一些奇怪的事情,尽管我很久以前写过这个函数。无论如何,我的虚拟机读取的文件如下:

0002 000A 0001 0004 0000
但是,当我在0000或新行之后没有任何空格时。。。它崩溃了。另一件非常奇怪的事情,让我相信它不是文件加载,是当你从文件中删除
0000
和空白。。。行吗?!我试着通过GDB运行它,但它实际上是有效的——显然这被称为海森堡或其他什么。我认为这是由于文件的加载方式,您可以在中看到,或者只是阅读下面的片段

void load_program(vm *self) {
    FILE *file = fopen("testing.ayy", "r");

    if (file != NULL) {
        if (fseek(file, 0, SEEK_END) == 0) {
            long file_size = ftell(file);
            if (file_size == -1) {
                perror("could not read filesize\n");
                exit(1);
            }
            self->source = malloc(sizeof(char) * file_size);

            if (fseek(file, 0, SEEK_SET) != 0) {
                perror("could not reset file index\n");
                exit(1);
            }

            size_t file_length = fread(self->source, sizeof(char), file_size, file);
            if (file_length == 0) {
                perror("given file is empty\n");
                exit(1);
            }
            self->source[file_size] = '\0';
        }
        fclose(file);
    }
    else {
        perror("could not read file: \n");
        exit(1);
    }

    self->source_compact = strdup(self->source);
    self->source_compact = deblank(self->source_compact);

    // here we divide because strlen is in characters,
    // whereas each instruction code should be 4 characters
    // so we're converting char size to num of instructions
    self->instructions_size = strlen(self->source_compact) / INSTRUCTION_LENGTH;

    int i;
    for (i = 0; i < self->instructions_size; i++) {
        char *instr = substring(self->source_compact, i);

        if (strcmp(instr, ERROR_CODE)) { // not equal to NOPE
            if (self->instructions != NULL) {
                self->instructions = add_instructions(self->instructions, strtol(instr, NULL, 16));
            }
            else {
                self->instructions = create_instructions(strtol(instr, NULL, 16));
            }
        }
    }

    self->instructions = reverse(self->instructions);
}
void load_程序(vm*self){
FILE*FILE=fopen(“testing.ayy”、“r”);
如果(文件!=NULL){
if(fseek(文件,0,SEEK_END)==0){
长文件大小=ftell(文件);
如果(文件大小==-1){
perror(“无法读取文件大小\n”);
出口(1);
}
self->source=malloc(sizeof(char)*文件大小);
if(fseek(文件,0,搜索集)!=0){
perror(“无法重置文件索引\n”);
出口(1);
}
size\u t file\u length=fread(self->source,sizeof(char),file\u size,file);
如果(文件长度==0){
perror(“给定文件为空\n”);
出口(1);
}
self->source[文件大小]='\0';
}
fclose(文件);
}
否则{
perror(“无法读取文件:\n”);
出口(1);
}
self->source\u compact=strdup(self->source);
self->source\u compact=deblank(self->source\u compact);
//在这里我们分开,因为斯特伦是以人物为单位的,
//而每个指令代码应为4个字符
//所以我们将字符大小转换为指令数
self->instructions\u size=strlen(self->source\u compact)/指令长度;
int i;
对于(i=0;iinstructions\u size;i++){
char*instr=子字符串(self->source\u compact,i);
if(strcmp(instr,错误代码)){//不等于NOPE
如果(自我->指令!=NULL){
self->instructions=添加_指令(self->instructions,strtol(instr,NULL,16));
}
否则{
self->instructions=创建_指令(strtol(instr,NULL,16));
}
}
}
自->指令=反向(自->指令);
}
但是我添加了一个GitHub链接,因为我不确定它是否是这个函数;或者,如果这是由于整个源代码中发生的任何事情——因此,如果任何C大师能够帮助我,那将是非常棒的:)。我肯定它是在
vm.c
vm.h
中,我为这糟糕的代码感到抱歉;在我学习的时候,我从来没有认真研究过文件IO(大错误)

您需要为终止零再分配一个字节。索引
源[文件大小]
实际上超出了分配内存的末尾一个字节。写入该位置可能会破坏其他变量或
malloc()
使用的内部结构。让它:

self->source = malloc(sizeof(char) * (file_size + 1));
或者只是:

self->source = malloc(file_size + 1);
sizeof(char)
始终是
1
,因此它是冗余的

如果您想在
self->source
类型发生变化时保护自己,您可以使用:

self->source = malloc ((file_size+1) * sizeof *self->source);
它会自动分配正确的大小


在尝试访问内存之前,还应检查分配是否成功。

self->source[file_size]='\0'超出访问范围。它应该是
文件大小-1
,还是我应该在malloc时执行(文件大小+1)?
malloc(大小(字符)*(文件大小+1))此行:self->source=malloc(sizeof(char)*文件大小);可能由于多种原因而失败,因此在使用该指针之前,应检查返回的指针以确保其有效性。原因包括:1)简单的malloc故障2)文件大小大于可用堆内存。此行:perror(“无法读取文件:\n”);应为:perror(“fopen”);perror写入stderr,并输出从strerror()函数获得的消息。很好,我只保留sizeof(char),因为人们说这样做是为了可移植性还是为了不可移植性。使用sizeof*self->source(这意味着self->source指向的大小(在代码中,这是未定义的)如果sizeof*self->source大于1,那么内存分配量将增加2或3,或者是sizeof表达式返回值的任意倍。将该sizeof表达式添加到malloc中可能是一个非常糟糕的主意parameter@user3629249:
sizeof
运算符只关心其参数的类型,并且该类型具有分配的大小必须是分配内存的类型大小的倍数。
self->source = malloc ((file_size+1) * sizeof *self->source);