• ベストアンサー

結果が不安定なプログラム

配列に入れられた文字列を、別の配列に逆にして入れ、表示するというプログラムを作っています。 #include<stdio.h> #include<string.h> #include<stdlib.h> void main() {   char str1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ", str2[] = "";   int i = 0, len = strlen(str1);   char *p1 = str1 + len - 1, *p2 = str2;   while(*(p1 - i) != str1[0] - 1) *(p2 + i) = *(p1 - i++);   printf("str1 = %s\n",p1 = str1);   printf("str2 = %s\n",p2); } 実行結果: str1 = ABCDEFGHIJKLMNOPQRSTUVWXYZ str2 = ZYXWVUTSRQPONMLKJIHGFEDCBA と出るのですが、この文字列を例えば"TANGOHYOJI"とかに変えてみると、実行は出来るんですがprintfの部分が表示されません。 また表示できても、文字が違う文字になって表示されたりします。 あと、この場合に使われている<stdlib.h>はどういった役割を果たしているのでしょうか?これがないとこのプログラムは動かなかったのですが・・。 どうかよろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.3

★アドバイス ・文字列の char 型配列の宣言が正しくありません。  正しくはサイズを指定します。  char str1[ 27 ] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";  char str2[ 27 ] = "";  ※str1 にはサイズを省略しても良いですが、str2 はサイズを指定しないと   str2[1] となってしまいます。メモリが足りないため実行時にメモリ破壊   となります。とても危険です。 ・あと p1、p2 でポインタを使っているので i カウンタとか添え字での参照を  行わなくてポインタとして移動、参照すればスッキリしますよ。ソースが。  下にコメント付きで書き直してみました。参考にして下さい。 サンプル: #include<stdio.h> #include<string.h> // 逆順コピー int main( void ) {  // 格納領域(分かりやすく2行で記述)  char str1[ 27 ] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";  char str2[ 27 ] = "";    // 先頭,末尾ポインタの設定  char *p1 = str1 + strlen(str1) - 1;  char *p2 = str2;    // 逆順にコピー  while ( p1 >= str1 ){ ←これだけで良い(ポインタで比較)   *p2++ = *p1--; ←i カウンタを使わない(ポインタなのでスッキリ)  }  *p2 = '\0'; ←忘れずに追加    // 表示  printf( "str1 = %s\n", str1 ); ←p1=str1 としないで素直に str1 で良いと思う  printf( "str2 = %s\n", str2 ); ←ここも同じ  return 0; } 最後に: >あと、この場合に使われている<stdlib.h>はどういった役割を果たしているのでしょうか?  stdlib.h に属する関数を利用したいときにインクルードします。  今回は必要ないと思います。よって >これがないとこのプログラムは動かなかったのですが・・。  ↑  これは何かの偶然でしょうね。たまたま動いただけ。 ・ヘッダファイルは必要に応じてインクルードするものです。  例えば  printf() 関数を利用するには stdio.h をインクルードします。  strlen() 関数を利用するには string.h をインクルードします。  という事になります。 ・以上。

sikimori
質問者

補足

御回答ありがとうございます。 私もこのやり方を何回も試したのですが、駄目だったのでとても助かりました。 ただ私にはイマイチまだ分からないのですが、このやり方は俗に言う「ポインタの値を変えずにデータを参照」するパターンと、「ポインタの値そのものを更新してデータを参照」するパターンのどちらなのでしょうか? 今後の為に教えて頂けたらと思いますm(_ _)m

その他の回答 (3)

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.4

★??? >私もこのやり方を何回も試したのですが、駄目だったのでとても助かりました。  ↑  これは i カウンタを使わないでポインタで処理する方法のことですか?  何回も試しても駄目だったのは str2 の配列サイズを指定していなかったからですよ。 >ただ私にはイマイチまだ分からないのですが、このやり方は俗に言う  ↑  『このやり方』とはどんなやり方ですかね。私のサンプルの方法ですか? >「ポインタの値を変えずにデータを参照」するパターンと、  ↑  これは『*(p1 - i)』とか、『*(p2 + i)』というパターンです。 >「ポインタの値そのものを更新してデータを参照」するパターンのどちらなのでしょうか?  ↑  これが『*p1』とか、『*p2』というパターンです。 ・上記の解説よりどっちだと思いますか?  『このやり方』とはどんなやり方か分からないのでご自分で判断してみて下さい。 ・以上。

  • DT200
  • ベストアンサー率38% (63/164)
回答No.2

> while(*(p1 - i) != str1[0] - 1) *(p2 + i) = *(p1 - i++); whileの条件がstr1の先頭を指すまでとしたいのでしょうが、これではだめ。 ここは文字数が既知である為、素直にfor分の方が良いかも... また、str2にデータをコピーし終わったら'\0'で終端する必要あり。

sikimori
質問者

お礼

御回答ありがとうございます。 確かにfor文の方が確実ですね。 うっかりNULLを入れるの忘れてました(汗)。 おかげ様で無事動きました。ありがとうございました。

  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.1

提示されているコードでは 実行結果: str1 = ABCDEFGHIJKLMNOPQRSTUVWXYZ str2 = ZYXWVUTSRQPONMLKJIHGFEDCBA になりません。 (確立的にはそうなるかもしれませんが) >str2[] = ""; この記述の意味を理解していますか? > *p2 = str2 ここでstr2のポインタを入れているわけですが、 そのstr2のポインタp2に対して >*(p2 + i) としています。 str2はここではサイズ1の配列です。 確保もしていない領域に対して、 モノを入れてはいけません。 ここまでが分かれば、どうすれば直るか分かると思います。

sikimori
質問者

お礼

御回答下さりありがとうございました。 str2の領域を確保したところ、stdlibがなくても動くようになりました。 確保していない領域に文字を入れようとしていたのですね。 str2[]=""で何かいくらでも領域が取れていると思っていました。 御指摘感謝しています。ありがとうございました。

関連するQ&A