2012-04-22 273 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()功能..