无法使用memmem进行字符串搜索

时间:2014-09-15 20:18:44

标签: c

我不喜欢在这里转储大量代码并要求人们为我调试,但我对C有点缺乏经验而且我完全难过了。

总体目标是在非常大的日志文件(11G +)上进行一些清理,我一次读取2048字节,然后扫描各行,将它们写入输出文件。我最初使用strstr来查找行结尾,但是我发现这不适用于读取缓冲区末尾的部分行 - 我认为这是因为我从文件中读取的“字符串”没有a \ 0在它结束时,strstr感到困惑。

所以,经过一段谷歌搜索后,我想我会尝试memmem,这似乎是strstr的“二进制安全”替代品。这就是我被困住的地方,我的程序在调用memmem期间是segfaulting。

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

#define BUFF_LEN 2048

int main (void)
{
    char file_buff[BUFF_LEN], prev_line[BUFF_LEN], curr_line[BUFF_LEN];
    char *p_line_start, *p_lf;
    int bytes_consumed, bytes_read;
    FILE *in_fp, *out_fp;

    in_fp = fopen("208.log", "r");
    out_fp = fopen("expanded.log", "w+");

    int sane = 0;
    while (1) {
        bytes_read = fread(file_buff, 1, BUFF_LEN, in_fp);
        if (bytes_read == 0) {
            break;
        }

        // Set the pointer to the beginning of the file buffer
        p_line_start = file_buff;
        bytes_consumed = 0;

        // Chomp lines
        while (bytes_consumed < bytes_read) {
            printf("Read to go with bytes_read = %d, bytes_consumed = %d\n",
                bytes_read, bytes_consumed);
            p_lf = (char *) memmem(p_line_start, bytes_read - bytes_consumed,
                "\n", 1);
            if (p_lf == NULL) {
                // No newline left in file_buff, store what's left in
                // curr_line and break out to read more from the file.
                printf("At loop exit I have chomped %ld of %d\n",
                    p_line_start - file_buff, bytes_read);
                //break;
                goto cleanup;
            }
            // Copy the line to our current line buffer (including the newline)
            memcpy(curr_line, p_line_start, p_lf - p_line_start + 1);
            printf("Chomped a line of length %ld\n", p_lf - p_line_start + 1);
            fwrite(curr_line, 1, p_lf - p_line_start + 1, out_fp);
            p_line_start = p_lf + 1;
            bytes_consumed += p_lf - p_line_start + 1;
        }

有人可以在这里给我打电话吗?!
关于如何更好地为自己调试这个的提示也是受欢迎的。

1 个答案:

答案 0 :(得分:2)

您的一条评论:

  

我投出了返回值,因为gcc正在发出警告:   &#34;警告:赋值从整数中生成指针而不使用强制转换&#34;。

您只是通过转换返回值来隐藏问题。

memmem 会返回一个指针。通常今天指针是64位。如果您还没有声明该函数,编译器不会知道它返回一个指针,而是假设它返回一个整数。通常今天整数是32位。生成的代码将查找返回该整数的位置,并从那里获取32位。实际得到的是一半返回的指针。

尝试在调用memmem之后添加此行,并在声明或不声明memmem时查看打印输出是否有所不同:

printf("[p_lf = %p]\n", (void*)p_lf);

当我使用原始程序(没有声明)运行它时,它打印0xffffffffffffda67,然后崩溃,因为那是一个无效的指针。通过声明(使用#define _GNU_SOURCE),它打印了0x7fffffffda67,并没有崩溃。 请注意,如果仅使用0x7ffffffda67的32位低位,则获得0xffffda67,如果将其扩展为64位,则会获得0xffffffffffffda67,即原始程序的指针。 (地址空间布局随机化已关闭。)

这就是为什么你不应该投出回报值。