• 締切済み

C言語に詳しい方お願い致しいます

文字列Aから文字列Bを除いた結果を表示するプログラムなのですが 一ヶ所分からない部分があります。 #include <stdio.h> #include <string.h> int main(void){  char str1[] = "abcdefg";  char str2[] = "cde";  char str3[128] = "";  char *p1 = str1, *p2;  size_t len;  len = strlen(str2);  while((p2 = strstr(p1,str2)) != NULL) {   strncat(str3,p1,p2 - p1);   p1 = p2 + len;   printf("----\n");   printf("p2=%s\n", p2);   printf("str3=%s\n", str3);   printf("p1=%s\n", p1);  }  strcat(str3,p1);  printf("%s\n",str3);  return 0; } while文中の p1 = p2 + len; なのですが、何故これでp1の内容が「fg」になるのでしょう。

みんなの回答

回答No.2

>アドレスに3を足した結果が何故今回のようになるのか今一想像できません。 「ポインタ」は「配列にアクセスするのを簡略化した書き方」だと考えると理解しやすいでしょう。 例えば char *p1 = str1; というのは char *p1; p1 = &str1[0]; と同じ意味です。これは1番目の要素のポインタをp1に代入しています(先頭を「1番目」として数えています。C言語では「先頭を0番目」とした方が判りやすいかも?) この状態で *p1 = 'a'; と代入すると str1[0] = 'a'; と代入したのと同じ事が起きます。 上記を踏まえて。 p1 = &str1[3]; p2 = &str1[6]; こうすると、p1にはstr1配列の4番目の要素のアドレスが、p2にはstr1配列の7番目の要素のアドレスが代入されます(先頭を「1番目」と数えます) ここで、p2に代入する式を変更して p1 = &str1[3]; p2 = &str1[3]; p2++; p2++; p2++; と変えたら、どうなるでしょうか? 「p2++;」は「ポインタを1つ先に進める」つまり「今まで指していた配列要素の、1つ次の配列要素を指す」ようにする「加算命令」です。 「p2 = &str[3]」で、p2が「4番目」を指します。そして「1回目のp2++」で「5番目」、「2回目のp2++」で「6番目」、「3回目のp2++」で「7番目」を指します。 つまり、最初の p1 = &str1[3]; p2 = &str1[6]; と同じ動きをするのです。 では「p2++」を3回繰り返している部分を「足し算」に変えてみます。 p1 = &str1[3]; p2 = &str1[3]; p2 = p2 + 3; これも同じ動作をします。 このプログラムは「最初に、p2をp1と同じ値にしている」ので、以下のように書き換えできます。 p1 = &str1[3]; p2 = p1; p2 = p2 + 3; 「p2をp1と同じ値にしてから、p2に3を加える」のは「p2に、p1に3を加えた物を代入する」のと同じですから、以下のように書き換え可能です。 p1 = &str1[3]; p2 = p1 + 3; これも最初のプログラムと同じ動作をします。 p1から「要素番号が3つ進んだ場所」をp2に代入しているのです。 「ポインタに3を足す」というのは「要素番号が3つ分進んだ場所」に変える、と言う事です。 これが「ポインタの加算」(減算も同じ)の正体なのです。 なお「アドレスに3を足す」と言うのは、間違いとは言い切れませんが、実は「正確ではない」のです。 正確には「指している要素の場所を3つ進めている」のです。 で、C言語では「指している要素の場所」の事を「ポインタ」と呼びます。 つまり「指している要素の場所を3つ進めている」は「ポインタを3つ進めている」と言う事です。 ここで注意して欲しいのは「アドレスとポインタを混同してはいけない」という事です。 1要素のサイズが「1バイト」なら「ポインタが1つ増えると、アドレスも1つ増える」ので「ポインタとアドレスを同一視しても大丈夫」です。 ですが、1要素のサイズが「1バイトじゃない時」は、同一視してはいけません。「ポインタが1つ増えた」からといって「アドレスも1つ増える」とは限りません。

tdosj
質問者

お礼

有難うございます。 例えばp2に200と入っていて、そこから3つ進めると203になりますが、そこは「f」なのでp2は「f」になるのでは?と思っていたのでおかしくなっていました。 その理屈で行くと200は「c」だけになってしまいます。 こんな事でつまずいていました。

回答No.1

>p1 = p2 + len; >なのですが、何故これでp1の内容が「fg」になるのでしょう。 while文の中にある代入文「p2 = strstr(p1,str2)」によって、p2には「abcdefg」の文字列の「cの位置」が代入されます。 │a│b│c│d│e│f│g│\0│     ↑     p2 lenは「cdeの長さ」である「3」が代入されています。 この状態で「p1 = p2 + len;」を実行すると「p1は、p2から3文字先の文字を指す」ようになります。     p2   p2 + 3     ↓     ↓ │a│b│c│d│e│f│g│\0│          ↑         p2 + len つまり、p1は「f」の文字位置を指すようになります。 なので、p1の位置から%sでprintfすると「fg」が出力されます。

tdosj
質問者

補足

丁寧に解説して頂いて有難うございます。 私がポインタを理解できていないことが全ての原因なのは承知しています。 ポインタにはそれが指す変数のアドレスが格納されていると理解していますが アドレスに3を足した結果が何故今回のようになるのか今一想像できません。 ポインタを解説したHP等読んではみたのですが・・・

関連するQ&A

専門家に質問してみよう