1
 struct TokenizerT_ {
    char* separators;
    char* tks;
    char* cur_pos;
    char* next;
  };

  typedef struct TokenizerT_ TokenizerT;

  TokenizerT *TKCreate(char *separators, char *ts) 
  { 
    TokenizerT *tokenizer;
    tokenizer = (TokenizerT*)malloc(sizeof(TokenizerT));

    //some manipulation here

    tokenizer->tks = (char*) malloc (strlen(str)* sizeof(char));
    tokenizer->tks=str;
    printf("size of tokenizer->tks is %zu\n", strlen(tokenizer->tks)); //this prints out the correct number (e.g. 7)
    return tokenizer;
  }

  int main(int argc, char **argv)
  {
    TokenizerT *tk = TKCreate(argv[1], argv[2]);
    printf("tk->tks: %zu\n", strlen(tk->tks)); //HOWEVER, this prints out the wrong number (e.g. 1)
  }

上記のコードからわかるように、私は構造体へのポインターを使用しています。何らかの理由で、tk->tksの正しい長さを受け取っていません。TKCreate関数のtksと同じサイズである必要があるため、これを理解できません。誰かがこれを説明できますか?

4

3 に答える 3

2

コードスニペットに定義が示されていないstrは、TKCreate()で定義されたローカル変数だと思います。その場合、tokenizer-> tksにstrの値を割り当てます。これは、TKCreate()のスコープ内の適切な文字列を指しますが、TKCreate()を終了すると、スタックの内容(パラメーターとローカル変数を含む)が解放されます。 TKCreate()のスコープ外でそのポインターを参照しようとすると、すべてのベットがオフになるように消去されます。

もっともらしい修正の1つは、tokenizer-> tksのストレージを動的に割り当てることです。これにより、TKCreate()を終了した後もストレージが保持されます。これはmallocの呼び出しで行うようですが、strからの明示的な代入で上書きします。代わりに、strの内容を(strcpyを使用して)動的に割り当てられたメモリに次のようにコピーする必要があります。strcpy(tokenizer-> tks、str);

于 2012-09-26T05:41:21.183 に答える
0

tostrcpyの内容を指定する必要があります。これは、代入演算子を使用すると、与えられたポインターが失われ、メモリリークが発生し、ローカル変数を指しているためです。ローカル変数は、関数の戻り後に破棄されます。strtokenizer->tksmalloctokenizer->tks

したがって、アプローチは次のようになります。

tokenizer->tks = (char *)malloc ((strlen(str) + 1) * sizeof(char));
strcpy(tokenizer->tks, str);

別物:

あなたが自分自身を解放する前に忘れないでください。free ->tks tk

したがって、printfの後に、次を使用する必要があります。

free(tk->tks);
free(tk);

プログラムが非常に小さい場合は、構造と文字列(別のメモリ位置にあり、構造のメモリスペース内にないため、両方を解放する必要があります)を解放しなくても問題はありません。実行後、プログラムはとにかくメモリは消去されます。ただし、この機能を完全に機能する大きなプログラムに実装する場合は、メモリを解放することをお勧めします。

于 2012-09-26T05:49:40.240 に答える
0

どこで定義されているかは明確ではありませんがstr、関数内のローカル変数の場合、スコープ外になる可能性があり、データが上書きされます。

strcpy()割り当てられたスペースで値を使用またはコピーするのmemcpy()を忘れたためにメモリリークが発生し、新しく割り当てられたメモリへの唯一のポインタをポインタで上書きします。コピーした場合、文字列だけでなく末尾のnullにも十分なスペースを割り当てるのを忘れたため、範囲外に書き込むことになります。また、割り当てが成功することを確認する必要があります。memmove()strstr

偽のコード:

tokenizer->tks = (char*) malloc (strlen(str)* sizeof(char));
tokenizer->tks = str;

修正されたコード:

size_t len = strlen(str) + 1;
tokenizer->tks = (char *)malloc(len);
if (tokenizer->tks == 0)
    ...error handling...
memmove(tokenizer->tks, str, len);

使用するmemmove()か、手軽にmemcpy()パフォーマンスを向上させることができます(いくつかの図とタイミングについては、PythonがCよりも速い理由をstrcpy()参照してください)。キャストを使用したことであなた(そして私)を非難する人がいます。彼らが主張する理由は理解できますが、私は彼らに完全には同意しません(そして通常は自分でキャストを使用します)。は定義上1であるため、特に乗算する必要はありませんが、乗算しても害はありません。malloc()sizeof(char)

于 2012-09-26T06:00:13.867 に答える