【问题标题】:using memcmp to compare buffers with 0 bytes使用 memcmp 比较 0 字节的缓冲区
【发布时间】:2026-01-05 08:50:01
【问题描述】:

我正在尝试使用 memcmp 逐字节比较文件中的 2 个文本,在我将它们都读入内存后,将一个文件读入缓冲区(char* 或 char[],两者都尝试过)。问题是,我读入缓冲区的文件有很多 0 字节,这使他在第一个 0 字节处停止,认为它是一个以零结尾的空值,这会导致分段错误。即使有 0 个字节,如何让函数保持比较字节?

我已经尝试检查缓冲区是否已满,我逐字节打印它,它显示了所有字节,包括 0 字节。当我使用 printf("%s", buffer) 完全打印它时,我只得到第一个字节(第二个字节是 0 字节)。

void detect_virus(char *buffer, unsigned int size){
    link* l = (link*) malloc(sizeof(link));
    load(l);
    unsigned int location = 0;
    while(l != NULL){
        location = 0;
        while(location < size - l->vir->SigSize){
            int isVirus = memcmp(buffer + location, l->vir->sig, l->vir->SigSize);
            if(isVirus == 0)
                printf("%d, %s, %d\n", location, l->vir->virusName, l->vir->SigSize);
            location++;
        }
    }
    free(l);
}

void detect(link* list){
    char filename[50];
    fgets(filename, 50, stdin);
    sscanf(filename, "%s", filename);
    FILE* file = fopen(filename, "rb");
    char* buffer = (char*) malloc(10000);
    fseek(file, 0, SEEK_END);
    unsigned int size = ftell(file);
    fseek(file, 0, SEEK_SET);
    fread(buffer, 1, size, file);
    detect_virus(buffer, size);
    fclose(file);
}

我在第一次调用 memcmp 函数时遇到分段错误,而不是完全比较文本。任何想法如何解决这个问题?

编辑 load函数代码:

void load(link* list){
    printf("Enter Viruses file name: \n");
    char* filename = (char*) malloc(100);
    fgets(filename, 100, stdin);
    sscanf(filename, "%s", filename);
    FILE* file = fopen(filename, "r");

    while(!feof(file)){
        short length = 0;
        fread(&length, 2, 1, file);
        if(length == 0)
            break;
        struct virus* v = (struct virus*)malloc(length);
        fseek(file, -2, SEEK_CUR);
        fread(v, length, 1, file);
        v->SigSize = v->SigSize - 18;
        list_append(list, v);
    }
    list = list->nextVirus;
    free(filename);
    fclose(file);
}

作为说明,我之前测试过该功能并且它有效。

编辑 我找到了问题,谢谢大家!

【问题讨论】:

  • 你能添加“加载”功能的代码吗?您的代码是“正确的”(使用我不理解的 sscanf)并且您认为您的问题不是 '0' 字节,因为 memcmp 比较的是缓冲区而不是字符串。但我怀疑“加载”功能是原因,因为分配是由“l”完成的。
  • 该问题与memcmp无关。
  • @MeherKhiari 已编辑
  • 我没有看到任何可能产生影响的东西(尽管我建议删除那些 sscanf,因为它们无用并且可能导致如下所述的未定义行为)。你必须用调试符号编译它,获取核心转储并分析回溯,至少你会有崩溃点。然后你可以打破它并检查你的变量的值。祝你好运:)
  • @MeherKhiari 核心转储发生在我调用 memcmp 函数的那一行。缓冲区的值是“b”,但是当我逐字节打印缓冲区时,我得到了预期的所有文件。 b 是文件中的第一个字节,第二个是 0 字节,我认为它会因为 0 字节而停止,但我不知道为什么或如何改变它。

标签: c


【解决方案1】:

7.21.6.7 The sscanf function, paragraph 2 of the C standard(我的粗体字):

sscanf 函数等效于fscanf,除了输入是从字符串(由参数s 指定)而不是从流中获取的。到达字符串末尾等同于遇到fscanf 函数的文件结尾。 如果复制发生在重叠的对象之间,则行为未定义。

注意粗体部分。

在您的代码中:

sscanf(filename, "%s", filename);

filename 数组肯定与filename 数组重叠,因此会调用未定义的行为。

删除那行代码。

您还需要添加错误检查,尤其是检查来自fopen() 的返回不是NULL

【讨论】:

  • 实际上我改变了它并且我更早地得到了分段错误,但这不是我的问题。找到该文件并将其读入缓冲区,但是当我尝试比较它时,它在 0 字节处停止,然后出现分段错误。关于错误检查你是对的,我会添加它们。
  • @OrelVaknin 问题很可能出在您未发布的代码中。您的 while(l != NULL){ 看起来可能有问题,因为您从未在循环中修改 l
  • 你说得对,我忘了我在这里修复了一些东西。但问题仍然发生在第一次迭代时,这是我现在遇到的主要问题