- ベストアンサー
結果が不安定なプログラム
配列に入れられた文字列を、別の配列に逆にして入れ、表示するというプログラムを作っています。 #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>はどういった役割を果たしているのでしょうか?これがないとこのプログラムは動かなかったのですが・・。 どうかよろしくお願いします。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
★アドバイス ・文字列の 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 をインクルードします。 という事になります。 ・以上。
その他の回答 (3)
- Oh-Orange
- ベストアンサー率63% (854/1345)
★??? >私もこのやり方を何回も試したのですが、駄目だったのでとても助かりました。 ↑ これは i カウンタを使わないでポインタで処理する方法のことですか? 何回も試しても駄目だったのは str2 の配列サイズを指定していなかったからですよ。 >ただ私にはイマイチまだ分からないのですが、このやり方は俗に言う ↑ 『このやり方』とはどんなやり方ですかね。私のサンプルの方法ですか? >「ポインタの値を変えずにデータを参照」するパターンと、 ↑ これは『*(p1 - i)』とか、『*(p2 + i)』というパターンです。 >「ポインタの値そのものを更新してデータを参照」するパターンのどちらなのでしょうか? ↑ これが『*p1』とか、『*p2』というパターンです。 ・上記の解説よりどっちだと思いますか? 『このやり方』とはどんなやり方か分からないのでご自分で判断してみて下さい。 ・以上。
- DT200
- ベストアンサー率38% (63/164)
> while(*(p1 - i) != str1[0] - 1) *(p2 + i) = *(p1 - i++); whileの条件がstr1の先頭を指すまでとしたいのでしょうが、これではだめ。 ここは文字数が既知である為、素直にfor分の方が良いかも... また、str2にデータをコピーし終わったら'\0'で終端する必要あり。
お礼
御回答ありがとうございます。 確かにfor文の方が確実ですね。 うっかりNULLを入れるの忘れてました(汗)。 おかげ様で無事動きました。ありがとうございました。
- aris-wiz
- ベストアンサー率38% (96/252)
提示されているコードでは 実行結果: str1 = ABCDEFGHIJKLMNOPQRSTUVWXYZ str2 = ZYXWVUTSRQPONMLKJIHGFEDCBA になりません。 (確立的にはそうなるかもしれませんが) >str2[] = ""; この記述の意味を理解していますか? > *p2 = str2 ここでstr2のポインタを入れているわけですが、 そのstr2のポインタp2に対して >*(p2 + i) としています。 str2はここではサイズ1の配列です。 確保もしていない領域に対して、 モノを入れてはいけません。 ここまでが分かれば、どうすれば直るか分かると思います。
お礼
御回答下さりありがとうございました。 str2の領域を確保したところ、stdlibがなくても動くようになりました。 確保していない領域に文字を入れようとしていたのですね。 str2[]=""で何かいくらでも領域が取れていると思っていました。 御指摘感謝しています。ありがとうございました。
補足
御回答ありがとうございます。 私もこのやり方を何回も試したのですが、駄目だったのでとても助かりました。 ただ私にはイマイチまだ分からないのですが、このやり方は俗に言う「ポインタの値を変えずにデータを参照」するパターンと、「ポインタの値そのものを更新してデータを参照」するパターンのどちらなのでしょうか? 今後の為に教えて頂けたらと思いますm(_ _)m