Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/71.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 strstr中的微妙之处?_C_String_Strstr - Fatal编程技术网

C strstr中的微妙之处?

C strstr中的微妙之处?,c,string,strstr,C,String,Strstr,我有一个二进制数据文件,其中散布着各种字符串。我正试图编写一个C代码来查找文件中第一个出现的用户指定字符串。(我知道这可以用bash实现,但出于其他原因,我需要一个C代码。)目前的代码是: #include <stdio.h> #include <string.h> #define CHUNK_SIZE 512 int main(int argc, char **argv) { char *fname = argv[1]; char *tag = ar

我有一个二进制数据文件,其中散布着各种字符串。我正试图编写一个C代码来查找文件中第一个出现的用户指定字符串。(我知道这可以用bash实现,但出于其他原因,我需要一个C代码。)目前的代码是:

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

#define CHUNK_SIZE 512

int main(int argc, char **argv) {
    char *fname = argv[1];
    char *tag = argv[2];
    FILE *infile;
    char *chunk;
    char *taglcn = NULL;
    long lcn_in_file = 0;
    int back_step;
    fpos_t pos;

    // allocate chunk
    chunk = (char*)malloc((CHUNK_SIZE + 1) * sizeof(char));

    // find back_step
    back_step = strlen(tag) - 1;

    // open file
    infile = fopen(fname, "r");

    // loop
    while (taglcn == NULL) { 
        // read chunk
        memset(chunk, 0, (CHUNK_SIZE + 1) * sizeof(char));
        fread(chunk, sizeof(char), CHUNK_SIZE, infile);
        printf("Read %c\n", chunk[0]);
        // look for tag
        taglcn = strstr(chunk, tag);
        if (taglcn != NULL) {
            // if you find tag, add to location the offset in bytes from beginning of chunk
            lcn_in_file += (long)(taglcn - chunk);
            printf("HEY I FOUND IT!\n");
        } else {
            // if you don't find tag, add chunk size minus back_step to location and ...
            lcn_in_file += ((CHUNK_SIZE - back_step) * sizeof(char)); 
            // back file pointer up by back_step for next read 
            fseek(infile, -back_step, SEEK_CUR);
            fgetpos(infile, &pos);
            printf("%ld\n", pos);
            printf("%s\n\n\n", chunk);
        }
    }
    printf("%ld\n", lcn_in_file);

    fclose(infile);
    free(chunk);
}
#包括
#包括
#定义块大小512
int main(int argc,字符**argv){
char*fname=argv[1];
char*tag=argv[2];
文件*填充;
字符*块;
char*taglcn=NULL;
_文件中的长lcn_=0;
int后退步;
FPO_t pos;
//分配块
chunk=(char*)malloc((chunk_SIZE+1)*sizeof(char));
//后退一步
后退步=strlen(标签)-1;
//打开文件
infle=fopen(fname,“r”);
//环路
而(taglcn==NULL){
//读块
memset(chunk,0,(chunk_SIZE+1)*sizeof(char));
fread(块,大小(字符),块大小,填充);
printf(“读取%c\n”,块[0]);
//寻找标签
taglcn=strstrstr(块,标记);
如果(taglcn!=NULL){
//若您找到标记,则将从块开始的偏移量(以字节为单位)添加到位置
lcn_in_file+=(long)(taglcn-chunk);
printf(“嘿,我找到了!\n”);
}否则{
//若你们并没有找到标签,那个么将区块大小减去返回步骤添加到位置,然后。。。
lcn_in_file+=((块大小-后退步)*大小(字符));
//通过后退步骤将文件指针向上备份,以便下次读取
fseek(填充、后退、搜索);
fgetpos(填充和pos);
printf(“%ld\n”,位置);
printf(“%s\n\n\n”,chunk);
}
}
printf(“%ld\n”,lcn\u在\u文件中);
fclose(infle);
自由(块);
}
如果您想知道,
back\u步骤
是为了处理不太可能发生的情况,即所讨论的字符串被
边界分割

我试图检查的文件大小约为1Gb。问题是出于某种原因,我可以在前9000个左右字节内找到任何字符串,但除此之外,
strstr
不知何故没有检测到任何字符串。也就是说,如果我在文件中查找超过9000字节的字符串,
strstr
不会检测到它。代码读取整个文件,但从未找到搜索字符串

我尝试过将区块大小从128变为50000,结果没有变化。我也尝试过改变
后退步骤
。当
strstr
找不到字符串时,我甚至输入了诊断代码来逐字打印
chunk
,果然,字符串就在它应该在的地方。
pos
的诊断输出始终正确


谁能告诉我哪里出了问题?
strstr
在这里使用的工具是否错误?

二进制数据文件将包含用作字符串结尾的“\0”字节。里面的东西越多,搜索的区域就越短。注释<代码> STRSTR 将在它击中0字节后考虑它的工作。 你可以像这样间隔扫描内存

while (strlen (chunk) < CHUNKSIZE) 
   chunk += strlen (chunk) + 1;
while(strlen(chunk)

i、 e.在块中的空字节后重新启动,只要您仍在块中。

因为您说您的文件是二进制文件,将在文件中的第一个空字节处停止扫描

如果希望在二进制数据中查找模式,那么该函数是合适的(如果可用)。它可以在Linux和其他一些平台(BSD、macOS等)上使用,但没有定义为标准C或POSIX的一部分。它与strstr()的关系与与to的关系大致相同


请注意,您的代码应该检测
fread()
读取的字节数,并仅对其进行搜索

char   *tag = …;     // Identify the data to be searched for
size_t  taglen = …;  // Identify the data's length (maybe strlen(tag))
int     nbytes;
while ((nbytes = fread(chunk, 1, (CHUNK_SIZE + 1), infile)) > 0)
{
    …
    tagcln = memmem(chunk, nbytes, tag, taglen);
    if (tagcln != 0)
        …found it…
    …
}
不清楚为什么块大小上有
+1
fread()
函数不会在数据末尾添加空字节或类似的内容。我没有改变这个方面,但可能不会在我自己的代码中使用它


最好注意识别跨越两个块之间边界的标记。

最有可能导致
strstr
在代码中失败的原因是文件中存在空字节。此外,您应该以二进制模式打开文件,以使文件偏移量有意义

要扫描块中的字节序列,请使用
memmem()
函数。如果在您的系统上不可用,以下是一个简单的实现:

#include <string.h>

void *memmem(const void *haystack, size_t n1, const void *needle, size_t n2) {
    const unsigned char *p1 = haystack;
    const unsigned char *p2 = needle;

    if (n2 == 0)
        return (void*)p1;
    if (n2 > n1)
        return NULL;

    const unsigned char *p3 = p1 + n1 - n2 + 1;
    for (const unsigned char *p = p1; (p = memchr(p, *p2, p3 - p)) != NULL; p++) {
        if (!memcmp(p, p2, n2))
            return (void*)p;
    }
    return NULL;
}
#包括
空隙*memmem(恒定空隙*haystack,尺寸为n1,恒定空隙*针形,尺寸为n2){
const unsigned char*p1=haystack;
常量无符号字符*p2=指针;
如果(n2==0)
返回(无效*)p1;
如果(n2>n1)
返回NULL;
常量无符号字符*p3=p1+n1-n2+1;
for(const unsigned char*p=p1;(p=memchr(p,*p2,p3-p))!=NULL;p++){
if(!memcmp(p,p2,n2))
返回(void*)p;
}
返回NULL;
}
您可以通过以下方式修改程序:

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

void *memmem(const void *haystack, size_t n1, const void *needle, size_t n2);

#define CHUNK_SIZE 65536

int main(int argc, char **argv) {

    if (argc < 3) {
        fprintf(sderr, "missing parameters\n");
        exit(1);
    }

    // open file
    char *fname = argv[1];
    FILE *infile = fopen(fname, "rb");
    if (infile == NULL) {
        fprintf(sderr, "cannot open file %s: %s\n", fname, strerror(errno));
        exit(1);
    }

    char *tag = argv[2];
    size_t tag_len = strlen(tag);
    size_t overlap_len = 0;
    long long pos = 0;

    char *chunk = malloc(CHUNK_SIZE + tag_len - 1);
    if (chunk == NULL) {
        fprintf(sderr, "cannot allocate memory\n");
        exit(1);
    }

    // loop
    for (;;) { 
        // read chunk
        size_t chunk_len = overlap_len + fread(chunk + overlap_len, 1, 
                                               CHUNK_SIZE, infile);
        if (chunk_len < tag_len) {
            // end of file or very short file
            break;
        }
        // look for tag
        char *tag_location = memmem(chunk, chunk_len, tag, tag_len);
        if (tag_location != NULL) {
            // if you find tag, add to location the offset in bytes from beginning of chunk
            printf("string found at %lld\n", pos + (tag_location - chunk));
            break;
        } else {
            // if you don't find tag, add chunk size minus back_step to location and ...
            overlap_len = tag_len - 1;
            memmove(chunk, chunk + chunk_len - overlap_len, overlap_len);
            pos += chunk_len - overlap_len;
        }
    }

    fclose(infile);
    free(chunk);
    return 0;
}
#包括
#包括
#包括
void*memmemmem(const void*haystack,尺寸为n1,const void*pine,尺寸为n2);
#定义块大小65536
int main(int argc,字符**argv){
如果(argc<3){
fprintf(sderr,“缺少参数”);
出口(1);
}
//打开文件
char*fname=argv[1];
文件*infle=fopen(fname,“rb”);
if(infle==NULL){
fprintf(sderr,“无法打开文件%s:%s\n”,fname,strerror(errno));
出口(1);
}
char*tag=argv[2];
尺寸标签长度=标准长度(标签);
尺寸重叠长度=0;
长位置=0;
char*chunk=malloc(chunk\u SIZE+tag\u len-1);
if(chunk==NULL){
fprintf(sderr,“无法分配内存”\n);
出口(1);
}
//环路
对于(;){
//读块
大小块长度=重叠长度+fread(块+重叠长度,1,
int main( int argc, char **argv )
{
    // put usable names on command-line args
    char *fname = argv[ 1 ];
    char *tag = argv[ 2 ];

    // mmap the entire file
    int fd = open( fname, O_RDONLY );
    struct stat sb;
    fstat( fd, &sb );
    char *contents = mmap( NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
    close( fd );

    size_t tag_len = strlen( tag );

    size_t bytes_to_check = 1UL + sb.st_size - tag_len;

    for ( size_t ii = 0; ii < bytes_to_check; ii++ )
    {
        if ( !memcmp( contents + ii, tag, tag_len ) )
        {
             // match found
             // (probably want to check if contents[ ii + tag_len ]
             //  is a `\0' char to get actual string matches)
        }
    }

    munmap( contents, sb.st_len );

    return( 0 );
}