2012-04-22 178 views
1

我写了下面的程序。如果我评论的线标记问题解决的路径几个目录名奇怪的行为

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

char * 
tokenizer(char *path, char **name){ 
    char s[300]; 
    char *buffer; 
    memcpy(s, path, strlen(path)+1); 
    printf("%s\n",s); // PROBLEM 
    int i=0; 
    while(s[i] == '/'){ 
    i++; 
    } 
    if (i == strlen(path)){ 
    return NULL; 
    } 
    *name = strtok_r(s, "/", &buffer); 
    return buffer; 
} 

int main(void){ 
    char str[300]; 
    char *token, *p; 
    scanf("%s",str); 
    p = tokenizer(str, &token); 
    if (p != NULL) 
    printf("%s\n",token); 
    else 
    printf("Nothing left\n"); 
    while((p=tokenizer(p, &token)) != NULL){ 
    printf("%s\n",token); 
    } 
} 

输出上面的程序

Input: a/b/c 
Output: a/b/c 
a/b/c 
a 
b/c 
b 
c 
c 

Input: a/b/c 
Output: Some garbage value 

有人可以解释我这种奇怪行为的原因吗?

注: 我已经意识到s是一个堆栈分配的变量,并停止在功能main()存在,但为什么当我使用printf()程序工作?

+0

如果我编译你的程序,我会在最下面的'while'行发出警告。最好先研究一下。 – 2012-04-22 08:24:38

+0

@MrLister编译程序时,我没有收到任何警告。你指定的gcc编译器有哪些选项? – gibraltar 2012-04-22 08:26:46

+0

着名的'-Wall' – 2012-04-22 08:27:07

回答

3

除了什么geekasaur说:

strtok_r的第三个参数使用不当,有两种方式:
1.应在第一次调用之前被初始化为NULL。
2.不得以任何方式(将它返回给调用者)被使用。它应该只被传递给另一个strtok_r呼叫。

3

您正在返回指向堆栈分配字符串的指针(buffer指向s);在tokenize返回后,s的记忆不再有意义。

1

你不能做到这一点

char s[300]; 
char *buffer; 
... 
*name = strtok_r(s, "/", &buffer); 
return buffer; 

这里buffer是一个指向s[300]位置。 s[300]是函数调用时在堆栈上分配的函数局部变量,函数返回时被销毁。 所以你没有返回一个有效的指针,你不能使用该指针离开函数。

0

随着你正在返回一个指针到一个局部变量的观察,我认为这是值得指出的是,你的tokenizer几乎是100%没有意义的。

大部分什么你tokenizer确实调用strtok_r之前在任何领先/字符被跳过 - 但你传递“/”作为分隔符来strtok_r,这将在任何领先的分隔符自动跳过它自己。

而是简单的代码足以打印出的路径的组件没有分隔符:

char path[] = "a/b/c"; 
char *pos = NULL; 

char *component = strtok_r(path, "/", &pos); 
while (NULL != component) { 
    printf("%s\n", component); 
    component = strtok_r(NULL, "/", &pos); 
} 
+0

我知道如何标记字符串。我知道我可以采用上述实施方式。我在问为什么我的程序在printf的情况下表现得很奇怪。标记器只是一个测试程序。我正在实现一个像目录结构一样的linux文件系统,我需要逐个遍历目录来访问最终的inode。 – gibraltar 2012-04-22 08:58:11

+0

@gibraltar:所以如果你知道如何标记字符串,你为什么问你知道有未定义行为的代码的行为? – 2012-04-22 08:59:18

+0

我的问题是为什么程序在printf()的情况下行为正确? – gibraltar 2012-04-22 09:06:31

0

试试这个:

char* 
token(char * path, char ** name){ 

    static char * obuffer = NULL; 
    char * buffer = NULL, * p, * q; 

    if(path == NULL) { 
     buffer = realloc(buffer, strlen(obuffer) + 1); 
     p = obuffer; 
    } else { 
     buffer = malloc(257); 
     p = path; 
    } 

    if(!buffer) return NULL; 
    q = buffer; 

    if(!p || !*p) return NULL; 

    while(*p != '\0') { 
      if(*p == '/') { 
      p++; /* remove the/from string. */ 
      break; 
      } 
      *q ++ = *p++; 
    } 

    *q ++ = '\0'; 
    obuffer = p; 
    *name = buffer; 

    return buffer; 
} 

int main(void) 
{ 

    char * s = "foo/baa/hehehe/"; 
    char * name = NULL; 
    char * t = token(s, &name); 
    while(t) { 
     printf("%s\n", name); 
     t = token(NULL, &name); 
    } 

    return 0; 
} 

输出:

foo 
baa 
hehehe 

但你基本上“重塑车轮”strtok()功能..