C 无法使用memmem进行字符串搜索
我不喜欢把一堆代码放在这里,让别人帮我调试,但我对C语言有点缺乏经验,我完全被难倒了 总体目标是对一个非常大的日志文件(11G+)进行一些清理,我一次读取2048字节,然后扫描单独的行,将它们写入一个输出文件。我最初使用strstr查找行结尾,但是我发现这不适用于读取缓冲区末尾的部分行-我认为这是因为我从文件中读取的“字符串”末尾没有\0,strstr会被混淆 所以,在谷歌搜索了一段时间后,我想我应该试试memmem,它似乎是strstr的“二进制安全”替代品。这就是我被卡住的地方,我的程序在调用memmem时出错了C 无法使用memmem进行字符串搜索,c,C,我不喜欢把一堆代码放在这里,让别人帮我调试,但我对C语言有点缺乏经验,我完全被难倒了 总体目标是对一个非常大的日志文件(11G+)进行一些清理,我一次读取2048字节,然后扫描单独的行,将它们写入一个输出文件。我最初使用strstr查找行结尾,但是我发现这不适用于读取缓冲区末尾的部分行-我认为这是因为我从文件中读取的“字符串”末尾没有\0,strstr会被混淆 所以,在谷歌搜索了一段时间后,我想我应该试试memmem,它似乎是strstr的“二进制安全”替代品。这就是我被卡住的地方,我的程序在调
#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;
}
#包括
#包括
#定义BUFF_LEN 2048
内部主(空)
{
字符文件buff[buff\u LEN],上一行[buff\u LEN],当前行[buff\u LEN];
字符*p\u行\u开始,*p\u lf;
消耗的整数字节,读取的字节;
文件*in\u fp,*out\u fp;
in_fp=fopen(“208.log”,“r”);
out_fp=fopen(“expanded.log”,“w+”);
int sane=0;
而(1){
字节读取=fread(文件buff,1,buff,in fp);
如果(字节数_读取==0){
打破
}
//将指针设置为文件缓冲区的开头
p_line_start=file_buff;
消耗的字节数=0;
//咀嚼线
while(消耗的字节数<读取的字节数){
printf(“与字节一起读取\%d,消耗的字节\%d\n”,
字节(读取,消耗的字节);
p_lf=(char*)memmem(p_line_start,bytes_read-bytes_consumered,
“\n”,1);
if(p_lf==NULL){
//文件中没有换行符。\u buff,存储文件中剩余的内容
//curr_line和break out从文件中读取更多内容。
printf(“在循环出口处,我选择了%ld个%d\n”,
p_行_开始-文件_buff,字节_read);
//中断;
去清理;
}
//将行复制到当前行缓冲区(包括换行符)
memcpy(当前行、p\u行、p\u lf-p\u行、p\u开始+1);
printf(“选择了长度为%ld\n的行”,p\u lf-p\u line\u start+1);
写入(当前线路,1,左前-线路,起始+1,输出fp);
p_line_start=p_lf+1;
字节消耗+=p_lf-p_行开始+1;
}
谁能在这里给我一句台词?!也欢迎提供如何更好地为自己调试的提示。来自您的评论之一: 我正在强制转换返回值,因为gcc正在踢出警告: “警告:赋值从整数生成指针而不进行强制转换” 您只是通过强制转换返回值来隐藏问题 memmem返回一个指针。通常今天的指针是64位。如果您没有声明函数,编译器不知道它返回一个指针,而是假设它返回一个整数。通常今天的整数是32位。生成的代码将查找该整数返回的位置,并取3它实际得到的是返回指针的一半 尝试在调用memmem后添加这一行,看看如果您声明或不声明memmem,打印输出是否不同:
printf("[p_lf = %p]\n", (void*)p_lf);
当我使用您的原始程序(没有声明)运行它时,它打印了0xFFFFFFFFDA67,然后崩溃,因为这是一个无效的指针。使用声明(使用#define"GNU"SOURCE)时,它打印了0x7fffffffda67,但没有崩溃。
请注意,如果只取0x7fffffffda67的32个低位,则得到0xffffda67,然后将其扩展到64位,则得到0xFFFFFFFFDA67,即原始程序的指针。(地址空间布局随机化已关闭。)
这就是为什么您不应该强制转换返回值。如果您可以使用
mmap
,您可能希望使用它将整个文件映射到内存中。这样,您就不必担心部分文件。(mmap
延迟加载内存页,因此您也不必担心在11GB文件上耗尽RAM)。您是否尝试过在调试器中运行此程序?然后您可以确切地看到它崩溃的位置,并可以查看变量的值。您使用fread
而不是fgets
来读取文件,这会使事情变得过于复杂。当然,在使用fgets
时,您可能仍然需要处理行截断问题。这段时间有多长输入文件中最长的一行?或者这是未知的?我希望文件I/O驱动程序正在读取大量的文件,因此您是否会看到fread
和fgets
之间的主要性能差异是值得怀疑的。至于最长的一行,使用5MB的行缓冲区(例如char*buffer)并不是不合理的=malloc(5000000);while(fread(buffer,5000000,fp_in)!=NULL){…}
所以我想我的问题是,你认为日志文件的行数会超过5MB吗?@indiv:这是可能的,并且它可以使用至少与搜索字符串一样长的缓冲区(可能更短——不过,我的思维会从处理那个字符串开始收缩),但簿记开销巨大,容易出错,而且很难调试。我也会选择一个大的单行输入缓冲区。然后为了安全起见,将其大小增加一倍。有趣的是,man memmem指示定义\u GNU SOURCE
,但事实上,只有定义了\u USE\u GNU
时才声明该函数。符号高亮显示IDE中的提示和弹出式语法提示让用户误以为一切都很好,这让人更加困惑。