大学の課題で、関数とポインタを使い次の問題をプログラミングする問題が出ました。
キーボードから入力した整数を指定した配列に読み込む関数 int readArray(int *a, int size) と指定した整数配列の先頭からn個の要素を画面に表示する関数 void printArray(int *a, int n) を作りなさい。ここでsizeは配列aの大きさを示しており、readArray(a, size) はsizeの値を超えて整数を読み込まないようにしなさい。
そして自分が作った答えがこちらです。
/*mysort.c*/
#include<stdio.h>
int readArray(int*,int);
void printArray(int*,int);
void mysort(int *,int);
#define swap(x,y) {int t; t=(x); (x)=(y); (y)=t;}
int main()
{
int a[100],n;
n = readArray(a, 100);
printArray(a, n);
mysort(a, n);
printArray(a, n);
return 0;
}
int readArray(int *a,int size)
{
int n;
/*配列aにデータを読む*/
n = 0;
printf("data = ");
while(scanf("%d",&a[n]) != EOF){
n++;
if(n>size) break;
printf("data = ");
}
return 0;
}
void mysort(int d[], int n)
{
int i,last,b,t;
b=0;
t=n-1;
while(t>b){
last=b;
for(i=b;i<t;i++)
if(d>d[i+1]){
swap(d,d[i+1]);
last = i;
}
t = last;
}
}
void printArray(int *a,int n)
{
/*配列a要素を表示する*/
int i;
for(i=0;i<n;i++) printf("a = %d\n",a);
}
コンパイル結果がこちらです。
[@peodbm02-( ~/C )-510]gcc mysort.c -o mysort
[@peodbm02-( ~/C )-511]./mysort
data = 11
data = 2
data = 3
data = [@peodbm02-( ~/C )-512]
答えすら出ずにどこが誤っているのかもわからない状態です。
かれこれ5日は考えていますが、期限が今週の木曜日23:59までなのでどうにかならないかと、この掲示板に投稿させていただきました。
ご教授の程、よろしくお願いします。
大学の課題が分かりません。
Re: 大学の課題が分かりません。
5日も考えなくても、変数の変化をトレースすれば
5分でどこが誤っているかわかるのではありませんか?
どこで勘違いしたのかを教えてください。
5分でどこが誤っているかわかるのではありませんか?
main:
a : [ ][ ][ ]...[ ]
n : [ ]
readArray:
a : main の a[0] への矢印
size : 100
n : 0
"data = "を表示
scanf で main の a[0] に 11 を書き込む
n : 1
n > size ではないので break しない
"data = "を表示
scanf で main の a[1] に 2 を書き込む
n : 2
n > size ではないので break しない
"data = "を表示
scanf で main の a[2] に 3 を書き込む
n : 3
n > size ではないので break しない
"data = "を表示
Ctrl-D を入力したので、
scanf は EOF を返す
whie ループを抜ける
return 0; なので readArray は 0 を返して main に戻る
main:
readArray が返した 0 を n に代入する。
n : 0
printArray:
a : main の a[0] への矢印
n : 0
i : 0
i < n ではないので、for ループを抜ける
main に戻る
main:
mysort:
Re: 大学の課題が分かりません。
返信ありがとうございます。
readArrayをreturn 0で返したのが間違いだと思うのですが、0で返すことで、正しくプログラムを終了させたという意味合いで使っていました。0で返すと0で入力されるのは当たり前ですよね。
readArrayはint型なので、returnを使わなければいけないと思い、何で返せばいいか分からず、0を使いました。
かずさんに日本語で説明されて分かったのですが、returnで返すものはnと言うことでしょうか?
readArrayをreturn 0で返したのが間違いだと思うのですが、0で返すことで、正しくプログラムを終了させたという意味合いで使っていました。0で返すと0で入力されるのは当たり前ですよね。
readArrayはint型なので、returnを使わなければいけないと思い、何で返せばいいか分からず、0を使いました。
かずさんに日本語で説明されて分かったのですが、returnで返すものはnと言うことでしょうか?
Re: 大学の課題が分かりません。
readArray関数から return しても、プログラムは終了しません。frontriver さんが書きました: ↑6年前readArrayをreturn 0で返したのが間違いだと思うのですが、0で返すことで、正しくプログラムを終了させたという意味合いで使っていました。0で返すと0で入力されるのは当たり前ですよね。
readArrayはint型なので、returnを使わなければいけないと思い、何で返せばいいか分からず、0を使いました。
main関数から return したら、プログラムは終了します。
そして、main関数は、0 を返すことが正常終了と規定されています。
一般の関数は、引数の意味や、返却値の意味を自由に決めていいのです。
そして、それを決めないと関数は書けません。
それから、変数を宣言するときは、その変数がどんな意味を持つのかも
プログラマが決めないといけません。
printArray の引数 size は、配列に入っているデータの個数です。
size には、main の変数 n が渡されます。
その n には readArray の返却値が代入されています。
ということは、main の n は、入力データの個数でなければなりません。
readArray が、読み込んだデータの個数を返すのは当然のことです。
readArray がデータの個数以外にエラーかどうかを返したければ、
書き方に工夫が必要です。
返却値でエラーを返し、引数 p で個数を返すなら、
int readArray(int *a, int size, int *p)
{
....
*p = n; // データの個数
return 0; // エラーなし
}
返却値で個数を返し、引数 e で エラーを返すなら、
int readArray(int *a, int size, int *e)
{
....
*e = 0; // エラーなし
return n; // データの個数
}
返却値で個数を返すが、エラーの場合は負の値を返すなら
int readArray(int *a, int size)
{
....
if (エラー) return -1; // エラー
return n; // データの個数
}
そのように変更してどういう結果になるか試していないのですか?frontriver さんが書きました: ↑6年前かずさんに日本語で説明されて分かったのですが、returnで返すものはnと言うことでしょうか?
最初の質問のプログラムはコードタグを使っていないのでおかしな表示に
なっています。フォーラム(掲示板)ルールに従ってください。
件名も「大学の課題が分かりません。」は不適切です。
「関数とポインタを使うプログラム」や「配列への読み込みと表示」など
内容を他の質問と区別できるものにしましょう。
Re: 大学の課題が分かりません。
返信ありがとうございます。
かずまさんのアドバイスをヒントに色々試行錯誤してみたらできました。
ありがとうございました。
加えて、フォーラム掲示板ルールにしたがっておらず、申し訳ありませんでした。
以後、質問をする際は気をつけます。
/*mysort.c*/
#include<stdio.h>
int readArray(int*,int);
void printArray(int*,int);
void mysort(int *,int);
#define swap(x,y) {int t; t=(x); (x)=(y); (y)=t;}
int main()
{
int a[100],n;
n = readArray(a, 100);
printArray(a, n);
mysort(a, n);
printArray(a, n);
return 0;
}
int readArray(int *a,int size)
{
int n;
/*配列aにデータを読む*/
n = 0;
printf("data = ");
while(scanf("%d",&a[n]) != EOF){
n++;
if(n>size) break;
printf("data = ");
}
return n;
}
void mysort(int d[], int n)
{
int i,last,b,t;
b=0;
t=n-1;
while(t>b){
last=b;
for(i=b;i<t;i++)
if(d[i]>d[i+1]){
swap(d[i],d[i+1]);
last = i;
}
t = last;
}
}
コンパイル結果
[peodbm02-( ~/C )-519]gcc mysort.c -o mysort
[peodbm02-( ~/C )-520]./mysort
data = 23
data = 2
data = 3
data = 4
data =
a = 23
a = 2
a = 3
a = 4
a = 2
a = 3
a = 4
a = 23
ありがとうございました。
加えて、フォーラム掲示板ルールにしたがっておらず、申し訳ありませんでした。
以後、質問をする際は気をつけます。
Re: 大学の課題が分かりません。
提出期限が過ぎてからの指摘で申し訳ありません。
そのプログラムだと、101個のデータが入力できてしまうか、
あるいは 101個目のデータで異常終了する可能性があります。
試しに、int a[4]; としてみてください。データが 5個入力できませんか?
a[0], a[1], a[2], a[3] の 4つの場所しかないのに、
参照してはいけない a[4] が使われているからです。
readArray の中の if(n>size) break; を if (n >= size) break; とするか、
あるいは、readArrayを次のように書くとよいでしょう。
printf は一つで済みます。
scanf の返却値を EOF ではなく、1 と比較しているのは、
EOF だと、まちがって数字以外を入れた時とんでもないことになるからです。
試してみてください。
次に、mysort ですが、変数 b はなんのためにあるのでしょうか?
値が 0 のまま変化しません。次のように書いてもいいでしょう。
そのプログラムだと、101個のデータが入力できてしまうか、
あるいは 101個目のデータで異常終了する可能性があります。
試しに、int a[4]; としてみてください。データが 5個入力できませんか?
a[0], a[1], a[2], a[3] の 4つの場所しかないのに、
参照してはいけない a[4] が使われているからです。
readArray の中の if(n>size) break; を if (n >= size) break; とするか、
あるいは、readArrayを次のように書くとよいでしょう。
int readArray(int *a, int size)
{
int n;
for (n = 0; n < size; n++) {
printf("data = ");
if (scanf("%d", &a[n]) != 1) break;
}
return n;
}
scanf の返却値を EOF ではなく、1 と比較しているのは、
EOF だと、まちがって数字以外を入れた時とんでもないことになるからです。
試してみてください。
次に、mysort ですが、変数 b はなんのためにあるのでしょうか?
値が 0 のまま変化しません。次のように書いてもいいでしょう。