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

PROBLEMというラベルの付いた行にコメントすると

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

誰かがこの奇妙な行動の理由を私に説明できますか?

s注:これはスタックに割り当てられた変数であり、関数内に存在しなくなったことに気づきましたが、main()使用するとプログラムが機能するのはなぜprintf()ですか?

4

5 に答える 5

3

スタックに割り当てられた文字列へのポインターを返しています ( へのポインターbuffer) ssの記憶はtokenize帰還後に意味を失う。

于 2012-04-22T08:26:03.930 に答える
3

ギーカサウルスの言うことに加えて:

strtok_rの 3 番目のパラメーターは、次の 2 つの方法で誤って使用されています。
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

これを試して:

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 に答える
0

ローカル変数へのポインターを返しているという観察結果に加えて、あなたtokenizerがほぼ100%無意味であることは注目に値すると思います。

ほとんどの場合、呼び出す前にtokenizer先頭の文字をスキップしますが、区切り文字として「/」をに渡します。これにより、先頭の区切り文字が自動的にスキップされます。/strtok_rstrtok_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 に答える