5

char * strtok(char * s1、const char * s2)

この関数を繰り返し呼び出すと、文字列s1が「トークン」に分割されます。つまり、文字列はサブ文字列に分割され、それぞれが「\ 0」で終了します。ここで、「\0」は文字列s2に含まれるすべての文字を置き換えます。最初の呼び出しでは、s1としてトークン化される文字列を使用します。以降の呼び出しでは、最初の引数としてNULLが使用されます。現在のトークンの先頭へのポインタが返されます。トークンがなくなると、NULLが返されます。

やあ、

私は今使用しようとしていますが、strtokに渡すとセグメンテーション違反が発生することがわかりました。を渡すと、正常に動作します。char*s1char[]strtok

どうしてこれなの?

char*私はグーグルで検索しましたが、その理由は、読み取り専用でchar[]書き込み可能である方法に関するもののようです。より徹底的な説明をいただければ幸いです。

4

5 に答える 5

15

何に初期化しchar *ましたか?

次のような場合

char *text = "foobar";

次に、いくつかの読み取り専用文字へのポインターがあります

為に

char text[7] = "foobar";

次に、好きなことを行うことができる文字の 7 つの要素の配列があります。

strtok指定した文字列に書き込みます-区切り文字を上書きnullし、残りの文字列へのポインターを保持します。

したがって、読み取り専用の文字列を渡すと、書き込みが試行され、segfault が発生します。

また、strtok文字列の残りの部分への参照を保持するため、再入可能ではありません。一度に 1 つの文字列に対してのみ使用できます。実際には避けるのが最善です-代わりに strsep(3) を検討してください-たとえば、ここを参照してください:http://www.rt.com/man/strsep.3.html(ただし、それでも文字列に書き込みますので、読み取りは同じです-のみ/セグメンテーションの問題)

于 2008-11-07T17:40:59.053 に答える
6

推測されているが明示的に述べられていない重要な点:

あなたの質問に基づいて、私はあなたが C でのプログラミングにかなり慣れていないと推測しているので、あなたの状況についてもう少し説明したいと思います。間違っていたらすみません; 基本的なメカニズムの微妙な誤解が原因で、C を学ぶのが難しい場合があるため、できるだけわかりやすくするのが好きです。

ご存知のように、C プログラムを書き出すと、コンパイラは構文に基づいてすべてを事前に作成します。コード内の任意の場所で変数を宣言すると、たとえば次のようになります。

int x = 0;

コンパイラはこのテキスト行を読み取り、自分自身に言います: OK、x整数を保持するために割り当てたメモリ領域への定数参照で、現在のコード スコープ内のすべてのオカレンスを置き換える必要があります。

プログラムが実行されると、この行が新しいアクションにつながります。 valueをx参照するメモリ領域を設定する必要があります。int0

ここでの微妙な違いに注意してください: 参照ポイントxが保持するメモリ位置は一定です (変更できません)。ただし、xポイントする値は変更できます。代入を通じてコードでそれを行いますx = 15;。また、1 行のコードが実際には、コンパイラに対する 2 つの別個のコマンドになることにも注意してください。

次のようなステートメントがある場合:

char *name = "Tom";

コンパイラのプロセスは次のようになります: OK、現在のコード スコープ内のすべてのオカレンスを、ポインター値nameを保持するために割り当てたメモリ領域への定数参照に置き換える必要があります。charそして、そうします。

しかし、これに相当する 2 番目のステップがあります。値「T」、「o」、「m」、および を保持する文字の定数配列を作成する必要がありますNULL。次に、コードの一部を、"Tom"その定数文字列のメモリ アドレスに置き換える必要があります。

プログラムが実行されると、最後のステップが発生します。 の値 (定数ではない) へのポインターを、自動的に作成さcharた文字列 (定数) のメモリ アドレスに設定します。

したがって、 achar *は読み取り専用ではありません。a のみconst char *読み取り専用です。しかし、この場合の問題は、char *s が読み取り専用であることではなく、ポインタがメモリの読み取り専用領域を参照していることです。

この問題を理解することは、ライブラリからその関数の定義を見て、自分で問題を理解することと、私たちに尋ねなければならないことの間の障壁であるため、これらすべてを取り上げます。また、問題をより理解しやすくするために、一部の詳細を簡略化しました。

これがお役に立てば幸いです。;)

于 2008-11-08T19:22:22.107 に答える
2

C標準のせいです。

char *s = "abc";

と同じエラーが発生するように定義できます。

const char *cs = "abc";
char *s = cs;

文字列リテラルは変更できないという理由で。しかしそうではなく、コンパイルするように定義されていました。図に行きます。[編集: Mike B が考え出した - "const" は K&R C にはまったく存在しませんでした。ISO C と、それ以降の C および C++ のすべてのバージョンは、下位互換性を望んでいました。したがって、それは有効でなければなりません。]

エラーが発生するように定義されていた場合、strtok の最初のパラメーターは char* であるため、segfault まで到達できなかったため、コンパイラーはリテラルから生成されたポインターを渡すことができなかったでしょう。

C++ でこれを廃止する計画がかつてあったことは興味深いかもしれません ( http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1996/N0896.asc )。しかし、12年後、gccまたはg ++のいずれかを説得して、リテラルを非const char *に割り当てることについて何らかの警告を出すように説得することはできません。

[編集: あはは: -Wall または -Wextra に含まれていない -Wwrite-strings]

于 2008-11-07T19:34:40.413 に答える
0

簡単に言えば:

char *s = "HAPPY DAY";
printf("\n %s ", s);

s = "NEW YEAR"; /* Valid */
printf("\n %s ", s);

s[0] = 'c'; /* Invalid */
于 2009-02-21T01:21:53.783 に答える
0

コンパイラのドキュメントを見ると、これらの文字列を書き込み可能にするために設定できるオプションがある可能性があります。

于 2009-02-21T01:45:35.940 に答える