関数について……教えてください

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

関数について……教えてください

#1

投稿記事 by miki » 14年前

二度目の投稿です。
前回と同様、初歩的な質問ですみませんが、以下の問題がどうしても解けません……。

Q.入力した文字列sを整数に変換して返す関数を作成しなさい。
  ・数値はint型配列dataに格納する。
  ・入力が終わったらfor文を使って表示する。
  ・int unyo(char s[]); を使用すること。

 ~入力する文字列~
  123
  223
  323
  225
  ^Z 

 ~結果~
  データ数=4
data[0]=123
data[1]=223
data[2]=323
data[3]=225

この問題に対して僕が書いたのが以下の通りです。

コード:

 
#include <stdio.h>
#define MAXLINE	1000

int unyo(char s[]);

main()
{						//宣言
	char s[MAXLINE];	//s[0]~s[999]
	int c;				//文字格納用
	int n;				//数字格納用
	int i;				//番号カウント用
	int x;				//回数カウント用
	int d;				//データ数カウント用
	
	n=d=0;				//初期化
	
	for(i=0; i<MAXLINE-1 && (c=getchar())!=EOF; ++i)
	{					//0~999の間又はEOFでない間又は改行でない間繰り返す
		s[i]=c;			//受け取った文字をs[i]に代入
		if(c=='\n')
		{				//もし改行なら
			s[i]=c;			//'\n'をs[i]に代入
			++i;			//カウントを増やす
			++d;
		}
	}
	s[i]='\0';			//入力した文字の最後に'\0'(単語の終わり)を代入

	printf("データ数=%d\n", d);
	
	for(i=0; i<d; ++i)
	{
		data[i]=unyo(s);
		printf("data[%d]=%3d\n",i,data[i]);
	}
}

int unyo(char s[])
{
	int x,n,m;
	
	for(n=x=0; '1'<=s[x]&&s[x]<='9'; ++x)
	{						//入力されたのが数字の間繰り返す
		n=n*10+(s[x]-'0');	//入力された数字を再現する
	}
	
	return n;
}
 しかし、これだと関数部分に2回目以降入るときもs[0]からになってしまうため、ずっと同じ数になってしまいます。
 そこで、二週目以降、xを初期化しない方法が知りたいのです。
 もし、方法がなければ他の考え方を教えていただけると幸いです。

二回目の投稿でいたらぬ点が多々あると思いますがよろしくお願いします。

アバター
h2so5
副管理人
記事: 2212
登録日時: 15年前
住所: 東京
連絡を取る:

Re: 関数について……教えてください

#2

投稿記事 by h2so5 » 14年前

コンパイルできるコードを貼ってください。
data が定義されていません。

miki

Re: 関数について……教えてください

#3

投稿記事 by miki » 14年前

直そうとしているうちに消してしまったみたいです……すみませんでした。

コード:

#include <stdio.h>
#define MAXLINE	1000

int suuchi_u(char s[]);

main()
{						//宣言
	char s[MAXLINE];	//s[0]~s[999]
	int c;				//文字格納用
	int n;				//数字格納用
	int i;				//番号カウント用
	int x;				//回数カウント用
	int d;				//データ数カウント用
	int data[MAXLINE];
	
	n=d=0;				//初期化
	
	for(i=0; i<MAXLINE-1 && (c=getchar())!=EOF; ++i)
	{					//0~999の間又はEOFでない間又は改行でない間繰り返す
		s[i]=c;			//受け取った文字をs[i]に代入
		if(c=='\n')
		{				//もし改行なら
			s[i]=c;			//'\n'をs[i]に代入
			++i;			//カウントを増やす
			++d;
		}
	}
	s[i]='\0';			//入力した文字の最後に'\0'(単語の終わり)を代入

	printf("データ数=%d\n", d);
	
	for(i=0; i<d; ++i)
	{
		data[i]=suuchi_u(s);
		printf("data[%d]=%3d\n",i,data[i]);
	}
}

int suuchi_u(char s[])
{
	int x,n;
	
	for(n=x=0; '1'<=s[x]&&s[x]<='9'; ++x)
	{						//入力されたのが数字の間繰り返す
		n=n*10+(s[x]-'0');	//入力された数字を再現する
	}
	
	return n;
}

beatle
記事: 1281
登録日時: 14年前
住所: 埼玉
連絡を取る:

Re: 関数について……教えてください

#4

投稿記事 by beatle » 14年前

miki さんが書きました: しかし、これだと関数部分に2回目以降入るときもs[0]からになってしまうため、ずっと同じ数になってしまいます。
 そこで、二週目以降、xを初期化しない方法が知りたいのです。
この考え方は捨てて下さい。
そして、文字列を整数に変換する関数unyoに、毎回変換したい文字列の先頭ポインタを渡すようにしてください。
つまり、
123
456
という入力が来る場合、一回目のunyoの呼び出しではunyo("123")となるようにし、二回目はunyo("456")となるようにします。
もちろんunyoの引数に直接文字列定数は書けませんから

コード:

while (...)
{
    // 標準入力から1行だけ読み込み、sにコピー
    data[i] = unyo(s);
    i++;
}
のようにすればいいでしょう。

miki

Re: 関数について……教えてください

#5

投稿記事 by miki » 14年前

返信ありがとうございます。

おかげさまで、どう考えればいいかはなんとなくですが分かってきました。

しかし、
// 標準入力から1行だけ読み込み、sにコピー
 の部分をどう書いていいかが分かりません……
大変恐縮ですがもう少しアドバイスいただけると幸いです。

box
記事: 2002
登録日時: 15年前

Re: 関数について……教えてください

#6

投稿記事 by box » 14年前

miki さんが書きました: // 標準入力から1行だけ読み込み、sにコピー
行全体を読むのであれば、fgets()あたりでじゅうぶんかな、という気がします。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

miki

Re: 関数について……教えてください

#7

投稿記事 by miki » 14年前

アドバイスありがとうございます。

fgets()というものを知りませんでした……

でも、この問題ではfgets()を使ってはいけないらしいのです、
なのでこれがどんなものかを調べて自分なりに考えてみました。
なんだかだいぶ別物になっている気がしますが

それで自分が書いたのが以下の通りになりました。

コード:

 

#include <stdio.h>
#define MAXLINE	1000

int u(char s[]);

main()
{						//宣言
	char s[MAXLINE];	//s[0]~s[999]
	char m[MAXLINE];
	int c;				//文字格納用
	int n;				//数字格納用
	int i;				//番号カウント用
	int ii;
	int x;				//回数カウント用
	int d;				//データ数カウント用
	int t;
	int dc;
	int data[MAXLINE];
	
	n=d=x=dc=0;				//初期化
	
	for(i=0; i<MAXLINE-1 && (c=getchar())!=EOF; ++i)
	{					//0~999の間又はEOFでない間又は改行でない間繰り返す
		m[i]=c;			//受け取った文字をm[i]に代入
		if(c=='\n')
		{				//もし改行なら
			m[i]=c;		//'\n'をm[i]に代入
			++i;		//カウントを増やす
			++d;		//データ数を増やす
		}
		++x;
	}
	m[i]='\0';			//入力した文字の最後に'\0'(単語の終わり)を代入

	printf("データ数=%d\n", d);
	
	
	for(ii=i=t=0; dc<d; ++i)
	{
		s[ii]=m[i];
		
		++ii;
		
		if(m[i]=='\n')
		{
			s[ii-1]='\0';
			data[t]=u(s);
			++t;
			ii=0;
			++dc;
		}
	}
	
	for(i=0; i<d; ++i)
	{
		printf("data[%d]=%d\n",i,data[i]);
	}
}

int u(char s[])
{
	int x,n;
	
	for(n=x=0; '1'<=s[x]&&s[x]<='9'; ++x)
	{						//入力されたのが数字の間繰り返す
		n=n*10+(s[x]-'0');	//入力された数字を再現する
	}
	
	return n;
}

これだと二回目以降が0になってしまいます……
おそらく2回目にuに入るのが0になってしまっているのですが、
これはなぜなのでしょうか……。

box
記事: 2002
登録日時: 15年前

Re: 関数について……教えてください

#8

投稿記事 by box » 14年前

miki さんが書きました: でも、この問題ではfgets()を使ってはいけないらしいのです、
何だかあいまいですね。
使ってはいけない「らしい」と使ってはいけない、とでは全然違いますよね。

ところで、最初に提示されていた仕様では、複数行のデータを入力後、
Ctrl+Z
という終わりの印を検知したら、データ数と、数値への変換結果を出力するように
なっていたと思います。
今のコードは、そういう風になっているのでしょうか。
どうも、1行分の対応しかできていないように見えるのですけれど。

それから、
MAXLINEの意味は、何ですか?
1行の最大文字数(1行に最大1000文字入力できる)ですか?
それとも、数値に変換したデータの個数(1000行分のデータ入力に対応できる)ですか?
両者の意味が全く異なることはわかりますよね。
miki さんが書きました:

コード:

 
	char s[MAXLINE];	//s[0]~s[999]
	char m[MAXLINE];
	int data[MAXLINE];

両者の意味がゴッチャになっていませんか?
もしくは、いずれか片方の意味を考慮していない配列定義になっていませんか?
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

naohiro19
記事: 256
登録日時: 15年前
住所: 愛知県

Re: 関数について……教えてください

#9

投稿記事 by naohiro19 » 14年前

コード:

#define MAXLENGHT 1000
にすれば誤解されないでしょう。

beatle
記事: 1281
登録日時: 14年前
住所: 埼玉
連絡を取る:

Re: 関数について……教えてください

#10

投稿記事 by beatle » 14年前

boxさんの指摘した部分を修正するのに加えて、変数名をもっとわかりやすいものにしましょう。
アルファベット1文字の変数が多すぎです。s, c, n, iはよく使うのでいいとして、その他の変数名は単語の組み合わせで作ってみてください。
例えば変数dは「numOfData」という名前がいいかと思います。
わかりやすい名前を付けることによって、その変数を何に使っているかをきちんと意識できるようになり、バグが減ります。

さらなる修正として、fgetsを使ってはいけないのでしたらmyfgetsなどという名前で、fgetsの動作を模倣するような関数を作れば、プログラム全体の構成がもっと簡単になります。
myfgetsを作る前に一度fgetsを使ってプログラムを作り、そのfgetsをmyfgetsに切り替えてもきちんと動くようにmyfgetsを実装してあげると楽だと思います。

box
記事: 2002
登録日時: 15年前

Re: 関数について……教えてください

#11

投稿記事 by box » 14年前

naohiro19 さんが書きました:

コード:

#define MAXLENGHT 1000
にすれば誤解されないでしょう。
確かに、MAXLENGTH(MAXLENGHTではなくて)の方が、「最大長」を端的に示す名前としてはよさそうです。
だとしても、例えば
 ・最大1000個分の数値に対応できる
 ・1行あたりの最大文字数は80である
の両方に対応するには、何かが抜けているような気がします。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

miki

Re: 関数について……教えてください

#12

投稿記事 by miki » 14年前

変数は分かりやすいように、関数は誰が見ても誤解のないようにし
もう一度0から考え直しました。

そうして書き直したところ、ちゃんと動作しました!!

いろいろアドバイスありがとうございました。
それではまた分からないところができましたらよろしくお願いします。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 15年前
住所: 東海地方
連絡を取る:

Re: 関数について……教えてください

#13

投稿記事 by softya(ソフト屋) » 14年前

フォーラムルールにあります通り解決コードの添付と解決チェックをお願いします。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

miki

Re: 関数について……教えてください

#14

投稿記事 by miki » 14年前

遅れてしまってすみませんした、
次の問題も入ってしまっていますが以下のコードで解決しました!!

コード:

#include <stdio.h>
#define MAXLINE 1000
#define NMAX	3000 //データ数NMAXまで対応可

double 	get_average	(int data[], int d);
int 	get_max		(int data[], int d);
int 	get_min		(int data[], int d);
int 	getline		(char s[], int lim);
int 	suuchika	(char s[]);

main()
{						//宣言
	char line[MAXLINE];	//s[0]~s[999]
	int data[NMAX];
	int t=0,datacount=0;
	
	while(getline(line,MAXLINE)>0)
	{
		data[t]=suuchika(line);
		++t;
		++datacount;
	}
	
	printf("データ数=%d\n",datacount);
	
	for(t=0; t<datacount; ++t)
	{
		printf("data[%d]=%3d\n",t,data[t]);
	}
	
	printf("平均値=%5.2f\n",get_average(data,datacount));
	printf("最大値=%3d\n",get_max(data,datacount));
	printf("最小値=%3d\n",get_min(data,datacount));
}

int suuchika(char s[])
{
	int x,n=0;
	
	if('0'<=s[0]&&s[0]<='9')
	{
		n=(s[0]-'0');
	}
	
	for(x=1; '0'<=s[x]&&s[x]<='9'; ++x)
	{						//入力されたのが数字の間繰り返す
		n=n*10+(s[x]-'0');	//入力された数字を再現する
	}
	
	if(s[0]=='-')
	{
		n=n*(-1);
	}
	
	return n;
}

int getline(char s[], int lim)
{
	int c,i;
	
	for(i=0; i<lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
	{
		s[i]=c;
	}
	
	if(c=='\n')
	{
		s[i]=c;
		++i;
	}
	s[i]='\0';
	
	return i;
}

double get_average(int data[], int datacount)
{
	int i,sum;
	float ave;
	
	for(i=sum=0; i<datacount; ++i)
	{
		sum+=data[i];
	}
	ave=(float)sum/datacount;
	return ave;
}

int get_max(int data[], int datacount)
{
	int max,i;
	
	max=data[0];
	
	for(i=1; i<datacount; ++i)
	{
		if(max<data[i])
		{
			max=data[i];
		}
	}
	
	return max;
}

int get_min(int data[], int datacount)
{
	int min,i;
	
	min=data[0];
	
	for(i=1; i<datacount; ++i)
	{
		if(min>data[i])
		{
			min=data[i];
		}
	}
	
	return min;
}
ありがとうございました。

box
記事: 2002
登録日時: 15年前

Re: 関数について……教えてください

#15

投稿記事 by box » 14年前

miki さんが書きました:

コード:

double get_average(int data[], int datacount)
{
	float ave;
	ave=(float)sum/datacount;
	return ave;
}
まあどうでもいいようなことかもしれませんが、どうせなら、
doubleかfloatかどちらかにそろえる方がいいのではないか、と思います。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

閉鎖

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