C でハマりやすいポインタの理解でしょうか。
下記に書かれているように、対象文字列を変更しながらポインタを返すので、
対象データとしてリテラルを使用することはできません。
C:strtok
http://www9.plala.or.jp/sgwr-t/lib/strtok.html
文字列リテラル
http://mkubara.com/index.php/%E6%96%87%E5%AD%97%E5%88%97%E3%83%AA%E3%83%86%E3%83%A9%E3%83%AB
▽2
●
a-kuma3 ●50ポイント ベストアンサー |
これが原因です。
これらの関数はその最初の引数を変更する。
Man page of STRTOK
C 言語での文字列リテラルは、コンパイラの実装に任されてはいますが、変更不能な領域に配置されることが多いです。
strtok() は、呼び出すたびに、最初の呼び出しで指定された文字列の中身を書き換えます。
質問の前半のコードでは、文字列リテラルの中身を書き換えているので、Segmentation Fault が発生します。
後半のコードでは、auto な char の配列の内容を書き換えているので、書き換えは許されており、Segmentation Fault は発生しません。
strcpy( chk, "abc,def;ghi"); ptr = strtok(chk, ",;");
を行うと、配列 chk に格納されている "abc" の後に続く "," が \0 に書き換えられています。
strtok() が返しているのは、実は chk の先頭アドレスです。
カンマが \0 に書き換えられているので、strtok() が返すポインタを printf で表示すると "abc" の後に続く \0 までが表示されるので、"abc" と表示されます。
同様に、次の、
ptr = strtok(NULL, ",;");
では、"def" に続く ";" が \0 に書き換えられて、'd' が格納されている位置を strtok() が返します。
この挙動は、コンパイラによって違ってきます。
今では、ほとんど触れることはできなくなっていますが、MS-DOS の環境や、組み込み系の環境だと、文字列リテラルの内容を書き換えても、許されることがあります。