プログラム

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ざこ

プログラム

#1

投稿記事 by ざこ » 16年前

C++について勉強していますが下記のプログラムがうまくいきません。
char rev_str(char *s1)
{
   char *s="water";
   int i,j;
 
   for(i=0;i<strlen(s);i++){
   *s++;
   }
 
   for(j=strlen(s);j=0;j--){
   *s1++=*s++;
   }

  return *s1;
}

int main()
{
  char s1[80];
  cout<<"waterを逆にすると"<<rev_str(s1)<<"です\n";

  return 0;
}
ある文字列を逆にして出力するプログラムをC++で書いています。
エラーはでませんがs1の中身がフフフフフフになってます。
原因と対策を教えて下さい。

たかぎ

Re:プログラム

#2

投稿記事 by たかぎ » 16年前

> s1の中身がフフフフフフになってます。

笑われていますね。

> 原因と対策を教えて下さい。

s1を未初期化のまま使用しているからです。
適切に初期化すれば改善します。

御津凪

Re:プログラム

#3

投稿記事 by 御津凪 » 16年前

> s1の中身がフフフフフフになってます。

たかぎさんと同意見です。凡ミスです。

> 原因と対策を教えて下さい。
原因はもう一つあり、 for 文の条件が j=0 となっているところです。
正しくは j != 0 ですよね?

対策として、こういう凡ミスは、条件文は左辺に定数が置かれるように書くと発見しやすいですよ。
(癖つけないと難しいですが)

0 = j はコンパイルエラーになりますから。

ざこ

Re:プログラム

#4

投稿記事 by ざこ » 16年前

char s1[80]; の所初期化してchar s1[80]="";にしてもさっぱり・・

non

Re:プログラム

#5

投稿記事 by non » 16年前

初期化という問題ではなく、考え方に問題があるのでは?
>char rev_str(char *s1)
s1に答えを入れたいのなら、returnの必要ないし、
returnで返したいなら、
char *rev_str(void)
です。
でも、元の文字列を関数内で定義するなら、関数を作った
意味がないですよね。

dic

Re:プログラム

#6

投稿記事 by dic » 16年前

引数とポインタとローカル変数の有効範囲を理解していませんね

toyo

Re:プログラム

#7

投稿記事 by toyo » 16年前

for(i=0;i<strlen(s);i++){
       *s++;
   }

*s++;

s++;
でも同じですしむしろ
s += strlen(s);
ですみます。
そしてsを文字数分インクリメントした後にstrlen(s)を使ってますがこの値は不定になります。

toyo

Re:プログラム

#8

投稿記事 by toyo » 16年前

for(i=0;i<strlen(s);i++){
       *s++;
   }
あー
これだとループのたびにstrlen(s)が変化しますね
どうしてもループでやるなら
int len = strlen(s);
   for(i=0 ;i < len; i++){
       s++;
   }
のようにしないと

たかぎ

Re:プログラム

#9

投稿記事 by たかぎ » 16年前

すみません。
よく見ていませんでした。
問題は他にありますね。

non

Re:プログラム

#10

投稿記事 by non » 16年前

>char *rev_str(void)
ごめん。間違えたので訂正。
char *rev_str(char *s1)
でした。

dic

Re:プログラム

#11

投稿記事 by dic » 16年前

独自にはできますが色々アルゴリズムが難解なやり方をやってらしているので
シンプルなのをひとつ
#include <iostream>
using namespace std;


char*	rev_str(char *s)
{
	unsigned int	len, i;

	char	temp[80];

	len = strlen(s);

	for( i=0; i<strlen(s); i++ ) {
		temp[len] = s;
		len--;
	}

	return s;
}

int main()
{
  char s[80] = "water";
  cout<<"waterを逆にすると"<<rev_str(s)<<"です\n";

  return 0;
}

Mist

Re:プログラム

#12

投稿記事 by Mist » 16年前

正しいソース書いてみましたのでどこが違うか確認してみてください。
ポインタと文字列の扱いに対する理解が足りていないと思います。
#include    <iostream>
using namespace std;

char    *rev_str(char *s1)
{
    char            *s = "water";
    unsigned long   length, loop;
    char            *ptmp = s1;

    length = strlen(s);
    s += (length - 1);
 
    for(loop = length; loop > 0; loop--, s1++, s--) {
        *s1 = *s;
    }

    return  ptmp;
}

int main()
{
    char s1[80];

    memset(s1, 0, sizeof(s1));

    cout << "waterを逆にすると" << rev_str(s1) << "です" << endl;

    return  0;
}

Mist

Re:プログラム

#13

投稿記事 by Mist » 16年前

かぶったか(^-~;

dic

Re:プログラム

#14

投稿記事 by dic » 16年前

すいません
文字転換しただけで後処理してませんでした
#include <iostream>
using namespace std;


char*	rev_str(char *s)
{
	unsigned int	len, i;

	char	temp[80];

	memset( temp, 0, sizeof(temp) );	//	忘れ物

	len = strlen(s) - 1;

	for( i=0; i<strlen(s); i++ ) {
		temp[len] = s;
		len--;
	}

	strcpy( s, temp );	//	忘れ物

	return s;
}

int main()
{
  char s[80] = "water";
  cout<<"waterを逆にすると"<<rev_str(s)<<"です\n";

  return 0;
}

になります

ざこ

Re:プログラム

#15

投稿記事 by ざこ » 16年前

うーん今「独習C++」って参考書で勉強してるんですが「独習C」の方も
買った方がいいかもしれませんね。質問したときに結構ボロボロかなとは思ってたのですが
何が悪いのかがわかりませんでした。ありがとうございました。

バグ

Re:プログラム

#16

投稿記事 by バグ » 16年前

せっかくなので、STL使ってみました。
#include <iostream>
#include <string>

std::string reverse(std::string str)
{
	std::string buf;
	for (std::string::reverse_iterator it = str.rbegin(); it != str.rend(); ++it)
	{
		buf += *it;
	}
	return buf;
}

int main(void)
{
	std::string str = "water";	
	std::cout << str << " を逆にすると " << reverse(str) << " です" << std::endl;
	return 0;
}

Mist

Re:プログラム

#17

投稿記事 by Mist » 16年前

本を読むのもいいですが、ステップ実行ができる環境(VC++)とかがあるのであれば一行ずつステップ実行して各変数の値がどのように変わっていくのか、ポインタは文字列のどの部分を指しているか等を順番に確認していくほうが本なんか読むよりも理解が早まると思いますけどね。

> 何が悪いのかがわかりませんでした。
正解見ても自分の間違いがわからなかったって意味じゃないですよね(^^;?
それだったら、具体的にどこが間違っているか書きますけど。

ざこ

Re:プログラム

#18

投稿記事 by ざこ » 16年前

参考書に従い勉強していく→練習問題があった→自分なりに解く→一応作れた・・エラーはでない(エラーが出る場合サイトなどで調べまくる。どうしても直せない場合質問へ)→正常に稼動しない・・→デバッグで確かめる→それでも直せない→質問する→納得する→練習問題の解答をみて
納得する。

これの繰り返しです。デバックに関してはブレークポイント指定してやる方法だとわかるんですけど
ステップインの方がまだイマイチなんですよね。ステップインすると変なとこに飛ばされたりで、さっぱりです。
他にも関数の中の変数見れないとか色々理解不足が多いです。
VC++のデバッグの使い方に関してわかりやすく載ってるサイトか参考書あれば是非教えて下さい。

Mist

Re:プログラム

#19

投稿記事 by Mist » 16年前

「VC++ デバッグ」等のキーワードでググればいくらでもヒットしますので使用されているバージョンにあったページを探してみてください。

●ステップ実行についてのアドバイス
ステップイン、ステップオーバー、ステップアウトの違いは理解されていますか?
ステップイン:一行実行する。関数がある場合は関数の中に入る。
ステップオーバー:一行実行する。関数がある場合は関数の中には入らないですべて実行する。
通常はこれを使用し関数の中に入りたい場合だけステップインする。
標準関数を使用している行でステップインすると標準関数の中に入ってしまうのでこちらを使用する。
ステップアウト:現在の関数から抜けるまで実行する。

そのほかに、ステップ実行中の右クリックメニューに「カーソル行まで実行」というのもあります。
その名の通り、カーソルのある行まで実行していくれるものです。

ざこ

Re:プログラム

#20

投稿記事 by ざこ » 16年前

本屋とかでデバッグの本探しまくったんですがやり方について載ってる本はなかったのですが・・
サイトで調べればよかったんですね。わかりやすく載ってるサイト見つけました。
ただステップインしてると
「STRCAT.ASMのパスを入力してください」と出た後に変な所に飛ばされます。プログラム自体は正常に稼動できます。
サイトによるとこの場所は混合モードとかいうそうですが、その辺がさっぱりです。
どういうものかはわかるんですが混合モードにならずにステップインする方法とかありますか?

Mist

Re:プログラム

#21

投稿記事 by Mist » 16年前

基本的にソースコードのない部分については無理です。
(他の人が作ったLIBやDLLの中など)
ソースコードがあるのであれば「xxxxxxのパスを入力してください」と要求されたときに該当するソースファイルを選択すれば実行できます。
ただし、最適化されているとソース通りには動作しない場合もありますが。

標準関数(CRT)についてはCRTのソースコードをインストールすることで出来るようになったと思いますが、VC++EEはソースコードが付いてこないので無理っぽいです。

Naohiro19

Re:プログラム

#22

投稿記事 by Naohiro19 » 16年前

stringクラスを使うのも手だと思います。

バグ

Re:プログラム

#23

投稿記事 by バグ » 16年前

>>Naohiro19さん
一応、STLを使用したサンプルをあげておいたのですが、皆さんに華麗にスルーされて、ちょっと悲しかったりしています(笑)

Justy

Re:プログラム

#24

投稿記事 by Justy » 16年前


>皆さんに華麗にスルーされて、ちょっと悲しかったりしています

 では寂しい思いをさせいないために、ツッコミでも(w
 
 std::iter_swapを使えばループは半分で済みませんか?
 或いは std::reverse系を使えば……。

tk-xleader

Re:プログラム

#25

投稿記事 by tk-xleader » 16年前

>一応、STLを使用したサンプルをあげておいたのですが、皆さんに華麗にスルーされて、ちょっと悲しかったりしています(笑)

僕も書いてみました。
#include<iostream>
#include<string>

int main()
{
	std::string str="water";
	std::cout<<str<<"を逆にすると"<<std::string(str.rbegin(),str.rend())<<std::endl;
	return 0;
}
高速かどうかは別の問題としてください。

たかぎ

Re:プログラム

#26

投稿記事 by たかぎ » 16年前

>一応、STLを使用したサンプルをあげておいたのですが、皆さんに華麗にスルーされて、ちょっと悲しかったりしています(笑)

というか、reverseを自分で実装する必要はありません。
#include <iostream>
#include <string>
#include <algorithm>

int main()
{
  std::string str("water");
  std::cout << str << "を逆にすると";
  std::reverse(str.begin(), str.end());
  std::cout << str << std::endl;
}
結果を返却値で返した方が使い勝手はよい気もしますが、一時オブジェクトが生成される問題もあるので、どっちもどっちですね。

閉鎖

“C言語何でも質問掲示板” へ戻る