strtok(我想)我无法理解的bug

时间:2013-11-20 14:51:31

标签: c strtok

编辑:复制行为的最小编译代码。

这段代码读取了一个糟糕的字典文件,以便尝试从中提取一些有趣的信息。每行转换为结构条目。始终提取一个单词,因此newentry()不会检查其单词参数的有效性。

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

typedef struct entry {
char *word;
char *cat;
char *gen;
} entry;

entry *newentry(char *word, char *cat, char *gen) {
entry *w = malloc(sizeof(entry));
w->word = malloc(sizeof(strlen(word)) + 1);
strcpy(w->word, word);
if (cat) {
    w->cat = malloc(sizeof(strlen(cat)) + 1);
    strcpy(w->cat, cat);
}
else {
    w->cat = "";
}
if (gen) {
    w->gen = malloc(sizeof(strlen(gen)) + 1);
    strcpy(w->gen, gen);
}
else {
    w->gen = "";
}
return w;
}


int main() {
FILE *original = fopen("French.txt", "r");
char *line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, original)) != -1) {
    char *word = strtok(strdup(line), "\t");
    char *tmp = strtok(NULL, "[\n");
    char *cat = strtok(NULL, "]\n");
    newentry(word, cat, tmp);           //bugs here
}
return 0;
}

此代码在其行(代码)行上失败,我完全不知道为什么。如果我用word,cat或常量替换tmp,它每次都有效。 如果我要更改newentry()的参数的顺序,它每次都会失败,只要tmp是一个参数。 我试着通过打破时间进行调试。正在解析的文件大约是4千行,所以我想象某些行(它是一个非常糟糕的文件)以某种方式被破坏了,我尝试继续1000,并得到一个例外。所以我重新启动并尝试了其他值继续 - 但是通过继续100次11次,我能够超过前1000次。

我的结论是tmp在某种程度上被以下strtok损坏了。所以我试过了 char * tmp = strdup(strtok(NULL,“[\ n”));它没有更好的效果。

用printf替换newentry()失败行(“%s%s%s”,word,tmp,cat);虽然我无法通过眼睛检查4000个值,但100%的时间都有效。

我真的不知道如何摆脱这种混乱,并且会感激任何指针。

编辑:数据文件中的几行:

courthouse  palais de justice[Noun]
courtier    courtisan[Noun]
courtliness e/le/gance[Adjective]
courtly e/le/gant[Adjective]
courtmartial    conseil de guerre[Noun]
courtroom   salle d'audience[Noun]

感谢。

整个输入文件,以防有人真正好奇:http://pastebin.com/VPp8WpuK

2 个答案:

答案 0 :(得分:3)

这是错误的:

entry *w = malloc(sizeof(entry *));

你想:

entry *w = malloc( sizeof *w );

或:

entry *w = malloc( sizeof( entry ))

答案 1 :(得分:2)

您可能需要调整为strtok选择的解析字符串。使用示例输入文件。我在第二行strtok上得到一个null,因为在第一次调用strtok时读取整行(即行中没有“\ t”

char *word = strtok(StrDup(line), "\t");//reads entire line of input
char *tmp = strtok(NULL, "[\n");//NULL is returned here
char *cat = strtok(NULL, "]\n");

因此,您将null传递给函数newentry(,,)

可行吗 将解析字符串更改为:

char *word = strtok(StrDup(line), "\t ");//added space  

以下行

w->word = malloc(sizeof(strlen(word)) + 1);  
w->cat = malloc(sizeof(strlen(cat)) + 1);
w->gen = malloc(sizeof(strlen(gen)) + 1);

w->word = malloc(strlen(word) + 1);
w->cat = malloc(strlen(cat) + 1);
w->gen = malloc(strlen(gen) + 1);  

另一件事 ,您需要释放newentry()中分配的内存,如果您需要返回结构w,这将是一个问题。建议在main()中分配全部,将结构作为指针传递,然后在它返回时释放所有结构。

这是怎么做的......
创建一个struct entry的数组:

typedef struct {
    char *word;
    char *cat;
    char *gen;
} ENTRY;  
ENTRY entry[linesInFile], *pEntry;  

然后 main()初始化它:

int main(void)
{
    pEntry = &entry[0];
    //allocate memory 
    //call redefined newentry() function
    //use results of newentry() function
    //free memory
}  

现在,因为pEntry是entry整个数组的指针 ,所以在为char *成员调用malloc之后,它可以很容易地作为参数传递进入(回归时不要忘记free()

以下是我必须进行的编辑才能使其运行(不包括重写以获取free()调用)

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

typedef struct entry {
    char *word;
    char *cat;
    char *gen;
} entry;

entry *newentry(char *word, char *cat, char *gen) 
{
    entry *w = malloc(sizeof(entry));
    w->word = malloc(strlen(word) + 1);
    strcpy(w->word, word);
    if (cat) 
    {
        w->cat = malloc(strlen(cat) + 1);
        strcpy(w->cat, cat);
    }
    else 
    {
        w->cat = "";
    }
    if (gen) 
    {
        w->gen = malloc(strlen(gen) + 1);
        strcpy(w->gen, gen);
    }
    else 
    {
        w->gen = "";
    }
    return w;

}


int main() 
{
    FILE *original = fopen("French.txt", "r");
    char line[260];
    int len = 260;
    //ssize_t read;
    while ( fgets(line, len, original))            
    {
        //char *word = strtok(StrDup(line), "\t ");//I dont have strdup, had to use this
        char *word = strtok(strdup(line), "\t ");
        char *tmp = strtok(NULL, "[\n");
        char *cat = strtok(NULL, "]\n");

        if((!word)||(!tmp)||(!cat)) return 0;
        word[strlen(word)]=0;
        tmp[strlen(tmp)]=0;
        cat[strlen(cat)]=0;

        newentry(word, cat, tmp);           //bugs here
    }
    return 0;
}