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()

4

5 回答 5

3

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

于 2012-04-22T08:26:03.930 回答
3

除了 geekasaur 所说的:

strtok_r的第3个参数用错了,有两种方式:
1、第一次调用前应该初始化为NULL。
2. 不应该以任何方式使用它(你将它返回给调用者)。它应该只传递给另一个strtok_r调用。

于 2012-04-22T08:32:36.553 回答
1

你不可以做这个

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

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

于 2012-04-22T08:30:30.420 回答
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);
}
于 2012-04-22T08:41:05.377 回答
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()功能..

于 2012-04-22T17:26:24.770 回答