str1にしたとき Segmentation fault (core dumped) と表示されてしまいます。何が原因なのでしょうか
strtok() は空白文字 ' ' を '\0' に書き変えて文字列を分割します。書き変えできない領域のメモリを書き変えようとした事がSegmentation faultの原因です。
str1 と str2 、同じようですが違いがあります。
C
1 char *str1 = "ls -a -l -v";
2 char str2[] = "ls -a -l -v";
どちらも関数内のauto変数であり、書き変え可能なスタック領域に割当られます。しかしstr1 はポインタ変数であり、str2 は配列であること。この違いは明確ですか?
まずchar str2[] = "ls -a -l -v";
の場合。
str2[] とある通り、str2 は配列です。この配列に 'l', 's', ' ', '-' ... という文字が格納されています。
配列の大きさ(長さ)は、終端文字 '\0' を含めた 12 バイトです。12バイトの配列そのものがスタック領域(RAM)にあるので、空白文字を '\0' に書き変えることができます。
一方、char *str1 = "ls -a -l -v";
の場合。
*str1 ですから str1 はポインタ変数です。auto変数として在るのはポインタ変数です。str1の値は文字列のアドレスであって、文字列そのものではありません。
では 'l', 's', ' ', '-' ... という文字列そのものは何処にあるかといえば、スタックとは別の、書き変えできない領域にあります。定数データ領域などと呼ばれます。文字列リテラルはROM領域にあるということ。
ここで、パソコン上のプログラムは書き変え可能なDRAM上で動作するのでは?と疑問に思うかもしれませんが、OS(Windows, Linux等)はメモリ管理機能を持っていて、定数データ領域(とプログラムコード領域)に割り当てたメモリを、書き変え不能に設定することができます。そこはDRAM上であってもROM領域です。
それ故、その領域を書き変えようとしてSegmentation faultが起こるのです。
- RAM領域にある str1 というポインタ変数
- ROM領域にある文字列リテラル "ls -a -l -v"
という関係を明確にすることが肝心です。
P.S.
memset(argv, 0, SIZE);
に驚きました。ごく限られた用途で、一時的に使うなら使えなくもない(現にこのプログラムは動作するようだ)が、行儀の悪い、危険を伴う、誤った使い方です。SIZEの値を大きくすれば不具合が起こるでしょう。試してごらんなさい。
引数 argc, argv は、このような使い方をするのではなく、コマンドライン引数にアクセスするための変数です。argc, argv の代りになる別の変数を用意してください。例えば
C
1int main(int argc, char **argv)
2{
3 int index = 0; // argcの代り
4 char **arr; // argvの代り
5
6 arr = malloc(SIZE);
7 if (arr != NULL) {
8 memset(arr, 0, SIZE);
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。