ページ 1 / 1
関数について……教えてください
Posted: 2012年6月11日(月) 14:21
by miki
二度目の投稿です。
前回と同様、初歩的な質問ですみませんが、以下の問題がどうしても解けません……。
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を初期化しない方法が知りたいのです。
もし、方法がなければ他の考え方を教えていただけると幸いです。
二回目の投稿でいたらぬ点が多々あると思いますがよろしくお願いします。
Re: 関数について……教えてください
Posted: 2012年6月11日(月) 15:31
by h2so5
コンパイルできるコードを貼ってください。
data が定義されていません。
Re: 関数について……教えてください
Posted: 2012年6月11日(月) 20:29
by miki
直そうとしているうちに消してしまったみたいです……すみませんでした。
コード:
#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;
}
Re: 関数について……教えてください
Posted: 2012年6月11日(月) 21:49
by beatle
miki さんが書きました: しかし、これだと関数部分に2回目以降入るときもs[0]からになってしまうため、ずっと同じ数になってしまいます。
そこで、二週目以降、xを初期化しない方法が知りたいのです。
この考え方は捨てて下さい。
そして、文字列を整数に変換する関数unyoに、毎回変換したい文字列の先頭ポインタを渡すようにしてください。
つまり、
123
456
という入力が来る場合、一回目のunyoの呼び出しではunyo("123")となるようにし、二回目はunyo("456")となるようにします。
もちろんunyoの引数に直接文字列定数は書けませんから
コード:
while (...)
{
// 標準入力から1行だけ読み込み、sにコピー
data[i] = unyo(s);
i++;
}
のようにすればいいでしょう。
Re: 関数について……教えてください
Posted: 2012年6月12日(火) 00:09
by miki
返信ありがとうございます。
おかげさまで、どう考えればいいかはなんとなくですが分かってきました。
しかし、
// 標準入力から1行だけ読み込み、sにコピー
の部分をどう書いていいかが分かりません……
大変恐縮ですがもう少しアドバイスいただけると幸いです。
Re: 関数について……教えてください
Posted: 2012年6月12日(火) 02:56
by box
miki さんが書きました:
// 標準入力から1行だけ読み込み、sにコピー
行全体を読むのであれば、fgets()あたりでじゅうぶんかな、という気がします。
Re: 関数について……教えてください
Posted: 2012年6月12日(火) 10:52
by miki
アドバイスありがとうございます。
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になってしまっているのですが、
これはなぜなのでしょうか……。
Re: 関数について……教えてください
Posted: 2012年6月12日(火) 12:07
by box
miki さんが書きました:
でも、この問題ではfgets()を使ってはいけないらしいのです、
何だかあいまいですね。
使ってはいけない「らしい」と使ってはいけない、とでは全然違いますよね。
ところで、最初に提示されていた仕様では、複数行のデータを入力後、
Ctrl+Z
という終わりの印を検知したら、データ数と、数値への変換結果を出力するように
なっていたと思います。
今のコードは、そういう風になっているのでしょうか。
どうも、1行分の対応しかできていないように見えるのですけれど。
それから、
MAXLINEの意味は、何ですか?
1行の最大文字数(1行に最大1000文字入力できる)ですか?
それとも、数値に変換したデータの個数(1000行分のデータ入力に対応できる)ですか?
両者の意味が全く異なることはわかりますよね。
miki さんが書きました:
コード:
char s[MAXLINE]; //s[0]~s[999]
char m[MAXLINE];
int data[MAXLINE];
両者の意味がゴッチャになっていませんか?
もしくは、いずれか片方の意味を考慮していない配列定義になっていませんか?
Re: 関数について……教えてください
Posted: 2012年6月12日(火) 12:55
by naohiro19
コード:
#define MAXLENGHT 1000
にすれば誤解されないでしょう。
Re: 関数について……教えてください
Posted: 2012年6月12日(火) 12:58
by beatle
boxさんの指摘した部分を修正するのに加えて、変数名をもっとわかりやすいものにしましょう。
アルファベット1文字の変数が多すぎです。s, c, n, iはよく使うのでいいとして、その他の変数名は単語の組み合わせで作ってみてください。
例えば変数dは「numOfData」という名前がいいかと思います。
わかりやすい名前を付けることによって、その変数を何に使っているかをきちんと意識できるようになり、バグが減ります。
さらなる修正として、fgetsを使ってはいけないのでしたらmyfgetsなどという名前で、fgetsの動作を模倣するような関数を作れば、プログラム全体の構成がもっと簡単になります。
myfgetsを作る前に一度fgetsを使ってプログラムを作り、そのfgetsをmyfgetsに切り替えてもきちんと動くようにmyfgetsを実装してあげると楽だと思います。
Re: 関数について……教えてください
Posted: 2012年6月12日(火) 21:48
by box
naohiro19 さんが書きました:コード:
#define MAXLENGHT 1000
にすれば誤解されないでしょう。
確かに、MAXLENGTH(MAXLENGHTではなくて)の方が、「最大長」を端的に示す名前としてはよさそうです。
だとしても、例えば
・最大1000個分の数値に対応できる
・1行あたりの最大文字数は80である
の両方に対応するには、何かが抜けているような気がします。
Re: 関数について……教えてください
Posted: 2012年6月12日(火) 23:30
by miki
変数は分かりやすいように、関数は誰が見ても誤解のないようにし
もう一度0から考え直しました。
そうして書き直したところ、ちゃんと動作しました!!
いろいろアドバイスありがとうございました。
それではまた分からないところができましたらよろしくお願いします。
Re: 関数について……教えてください
Posted: 2012年6月13日(水) 00:19
by softya(ソフト屋)
フォーラムルールにあります通り解決コードの添付と解決チェックをお願いします。
Re: 関数について……教えてください
Posted: 2012年6月13日(水) 00:52
by miki
遅れてしまってすみませんした、
次の問題も入ってしまっていますが以下のコードで解決しました!!
コード:
#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;
}
ありがとうございました。
Re: 関数について……教えてください
Posted: 2012年6月13日(水) 01:01
by box
miki さんが書きました:
コード:
double get_average(int data[], int datacount)
{
float ave;
ave=(float)sum/datacount;
return ave;
}
まあどうでもいいようなことかもしれませんが、どうせなら、
doubleかfloatかどちらかにそろえる方がいいのではないか、と思います。