↓が自分の作ったマージソートのプログラムなのですが、コンパイルするとエラーが起きてしまいます。
mergesort()にポインタを引数として渡してる、引数の数が足りない、ということが書いてありますが…。
ちゃんとint型を渡してるし、引数の数も合ってるように思います。
どこがおかしいのでしょう?
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define Max 255
int A[Max];
main(){
int n,k;
n=inputdata();
int w=1;
mergesort(w,n);
printdata(n);
return(0);
}
inputdata(){ //配列に乱数を要素として入れていく
int n,i;
printf("n= ");
scanf("%d",&n); //使用者にいくつの要素を入れるか指定してもらう
srand(time(NULL));
for(i=1; i<=n; i++){
A[i]=1+rand()%30;
}
printf("A[%d]={%d,",n,A[1]);
for(i=2;i<n;i++) printf("%d,",A[i]);
printf("%d}\n",A[n]);
return(n);
}
void mergesort(int p, int r){
int q;
if(p<r){
q=(p+r)/2;
mergesort(p,q);
mergesort(q+1,r);
merge(p,q,r);
}
}
void merge(int p, int q, int r){
int i,j,k,B[Max];
i=p; j=q+1;
for(k=p;k<=r;k++){
if((j>r) || ((i<=q)&&(A[i]<=A[j]))){
B[k]=A[i]; i++;
}else{
B[k]=A[j]; j++;
}
}
for(k=p; k<=r; k++) A[k]=B[k];
}
printdata(int n){
int i;
printf("A[%d]={%d,",n,A[1]);
for(i=2; i<n; i++) printf("%d,",A[i]);
printf("%d}\n",A[n]);
}
・エラーメッセージ
merge1.c: In function ‘main’:
merge1.c:12: warning: passing argument 1 of ‘mergesort’ makes pointer from integer without a cast
merge1.c:12: error: too few arguments to function ‘mergesort’
merge1.c: At top level:
merge1.c:31: error: conflicting types for ‘mergesort’
/usr/include/stdlib.h:294: error: previous declaration of ‘mergesort’ was here
merge1.c:41: warning: conflicting types for ‘merge’
merge1.c:37: warning: previous implicit declaration of ‘merge’ was here
No.2ベストアンサー
- 回答日時:
>どこがおかしいのでしょう?
書いている順番がおかしい。
まず、mainが一番上にあり、呼ばれる関数本体が定義される前に呼び出しをしているのが悪い。
この場合、Cコンパイラは「関数が定義されていないので、引数と返り値を勝手に予想」してコンパイルしてしまう。
で、関数の本体が現れた段階で「予想したのと違う」って言って、エラーになったりワーニングになったりする。
それと、運悪く、stdlib.hに「既にmergesortというのが定義されてて、名前が衝突している」ので、mergesortと言う名前の関数は使えない。
もう一つは、mainで
main(){
int n,k;
n=inputdata();
int w=1;
とやってて、実効コードが現れた後で、変数の宣言をしようとしているので、ここでエラーになる。
他にも「intを返す関数に、戻り値の型を書いてない」」とか「引数無しの関数に、引数が無い事を示すvoidと書かれてない」とか、色々問題点が山盛り。
で、それらを全て修正し、ワーニングが出ないようにしたのが、以下のソースコード。
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define Max 255
int A[Max];
/*関数は呼ばれる前に実体を定義する事*/
/*inputdataはmainから呼ばれるので、mainより先に関数本体を定義する事*/
/*intを返す関数には、ちゃんと「intを返す」と書く事*/
/*引数が無い場合は引数無しを明示するため、引数に「void」と書く事*/
int inputdata(void){ //配列に乱数を要素として入れていく
int n,i;
printf("n= ");
scanf("%d",&n); //使用者にいくつの要素を入れるか指定してもらう
srand(time(NULL));
for(i=1; i<=n; i++){
A[i]=1+rand()%30;
}
printf("A[%d]={%d,",n,A[1]);
for(i=2;i<n;i++) printf("%d,",A[i]);
printf("%d}\n",A[n]);
return(n);
}
/*関数は呼ばれる前に実体を定義する事*/
/*mergeはmerge_sortから呼ばれるので、merge_sortより先に関数本体を定義する事*/
void merge(int p, int q, int r){
int i,j,k,B[Max];
i=p; j=q+1;
for(k=p;k<=r;k++){
if((j>r) || ((i<=q)&&(A[i]<=A[j]))){
B[k]=A[i]; i++;
}else{
B[k]=A[j]; j++;
}
}
for(k=p; k<=r; k++) A[k]=B[k];
}
/*関数は呼ばれる前に実体を定義する事*/
/*merge_sortはmainから呼ばれるので、mainより先に関数本体を定義する事*/
/*mergesortと言う関数名は使えないので変更する事*/
void merge_sort(int p, int r){
int q;
if(p<r){
q=(p+r)/2;
merge_sort(p,q);
merge_sort(q+1,r);
merge(p,q,r);
}
}
/*関数は呼ばれる前に実体を定義する事*/
/*printdataはmainから呼ばれるので、mainより先に関数本体を定義する事*/
/*返り値が無いのなら、関数の戻り値の型をvoidにする事*/
void printdata(int n){
int i;
printf("A[%d]={%d,",n,A[1]);
for(i=2; i<n; i++) printf("%d,",A[i]);
printf("%d}\n",A[n]);
}
/*mainを呼ぶ人は居ないので、必然的にmainの実体は一番最後に書く事になる*/
/*intを返す関数には、ちゃんと「intを返す」と書く事*/
/*引数が無い場合は引数無しを明示するため、引数に「void」と書く事*/
int main(void){
int n,k;
int w=1; /*変数の宣言は実効コードより前に行う事*/
n=inputdata(); /*これは実効コード。これ以降は変数の宣言は出来ない*/
/*int w=1; 実効コードの後に変数は宣言できない*/
merge_sort(w,n);
printdata(n);
return(0);
}
どうだろうか?これでエラーもワーニングも出ない筈。
質問者さんは「どのプログラムを見ても、mainが一番最後にあるな。なんでだろう?」って思った事は無いだろうか?
これは「関数を参照(呼び出し)する前に、関数の実体を定義しておく」と言う書き方をしているから。
普通、変数は
int i;
と定義を済ませた後で
i=0;
と言うように参照や代入を行う。
関数もこれと同じで
int inputdata(void){
中身
}
と定義を済ませた後で
int main(void){
(略)
n=inputdata();
というように参照(呼び出し)を行う。
Cのお約束の「定義してから使う」って言うのは、関数にも当てはまる話なのだ。
--------------------------------
ここから蛇足。読み飛ばしても可。
もし「mainが最初に無いと、なんか気持ち悪い」と言うなら、実体が定義される前の関数を正しく呼べるように、関数のプロトタイプ宣言を行ってから、実体が後から定義される関数を呼べば良い。
すると、以下のようになる。
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define Max 255
int A[Max];
/*使う関数をプロトタイプ宣言する*/
int inputdata(void);
void merge_sort(int p, int r);
void merge(int p, int q, int r);
void printdata(int n);
main(){
int n,k;
int w=1; /*変数の宣言は実効コードより前に行う事*/
n=inputdata(); /*これは実効コード。これ以降は変数の宣言は出来ない*/
/*int w=1; 実効コードの後に変数は宣言できない*/
merge_sort(w,n);
printdata(n);
return(0);
}
int inputdata(void){ //配列に乱数を要素として入れていく
int n,i;
printf("n= ");
scanf("%d",&n); //使用者にいくつの要素を入れるか指定してもらう
srand(time(NULL));
for(i=1; i<=n; i++){
A[i]=1+rand()%30;
}
printf("A[%d]={%d,",n,A[1]);
for(i=2;i<n;i++) printf("%d,",A[i]);
printf("%d}\n",A[n]);
return(n);
}
void merge_sort(int p, int r){
int q;
if(p<r){
q=(p+r)/2;
merge_sort(p,q);
merge_sort(q+1,r);
merge(p,q,r);
}
}
void merge(int p, int q, int r){
int i,j,k,B[Max];
i=p; j=q+1;
for(k=p;k<=r;k++){
if((j>r) || ((i<=q)&&(A[i]<=A[j]))){
B[k]=A[i]; i++;
}else{
B[k]=A[j]; j++;
}
}
for(k=p; k<=r; k++) A[k]=B[k];
}
void printdata(int n){
int i;
printf("A[%d]={%d,",n,A[1]);
for(i=2; i<n; i++) printf("%d,",A[i]);
printf("%d}\n",A[n]);
}
--------------------------------
ここから蛇足の蛇足。
1番目の修正ソースのように「呼ぶ前に関数本体を定義する」と言う書き方をすると、関数プロトタイプ宣言は不要な筈。
しかし「2つの関数が、お互いを相互に呼び出す」と言う場合、どうしてもどちらか1つの関数は「呼んだ後に関数本体を定義する」と言う事になる。
そういう場合は「関数プロトタイプ宣言」が必須となる。
例:
int func2(int a):/*プロトタイプ宣言*/
int func1(int a){
(略)
if (a > 1) return func2(a - 1);
return 0;
}
int func2(int a){
(略)
if (a > 1) return func1(a - 1);
return 0;
}
例を見て判る通り、func1とfunc2の関数の場所を逆にしても、やはり「呼んだ後に関数本体を定義する」のが避けられない。
なので、こういう場合には「関数プロトタイプ宣言」が欠かせない。
No.5
- 回答日時:
本質は既に書かれている通り「ISO C にも POSIX にも定義されていない mergesort という関数が stdlib.h で宣言されている」 (とエラーメッセージにもちゃんと書いてある) ことなので, 関数名を変えるか (可能なら) 適切なコンパイラオプションでつぶすかすることになる.
以下余談:
ちと調べてみると BSD系では mergesort が定義されている>#4.
ついでにいうと今の ISO C をまじめに取り入れているコンパイラなら「実効コードの後に変数は宣言できない」という制限はない>#2. なぜか知らんがいまだに ISO C に対応しようとしない (ということは事実上 C++0x にも準拠しないことになる) MS なコンパイラではそのような制限があるが, どっちかといえばこれは 「MS なコンパイラ」が腐っていると思うべき.
No.4
- 回答日時:
追記。
>それと、運悪く、stdlib.hに「既にmergesortというのが定義されてて
>名前が衝突している」ので、mergesortと言う名前の関数は使えない。
他の一般的なC、C++では「mergesortと言う関数は標準関数として定義されていない筈」で、普通は、自前でmergesortと言う関数を作っても何も問題は起きない筈。
質問者さんが使っているコンパイラには、なぜか「mergesortと言う識別子がstdlib.hに定義済み」で、標準から逸脱した変なコンパイラらしいので、使用する場合は注意が必要だと思われます。
出来れば「変なものが定義されてない、もっと標準的なコンパイラ」を使った方が良いでしょう。
No.3
- 回答日時:
#define Max 255の次の行に、以下の行を追加して下さい。
void mergesort(int p, int r); //これを追加
void merge(int p, int q, int r); //これを追加
No.1
- 回答日時:
通りすがりです。
>↓が自分の作ったマージソートのプログラムなのですが、
>コンパイルするとエラーが起きてしまいます。
>mergesort()にポインタを引数として渡してる、
>引数の数が足りない、ということが書いてありますが…。
>ちゃんとint型を渡してるし、引数の数も合ってるように思います。
>どこがおかしいのでしょう
正直、引数が違うとかの問題ではないかと思いますが。
.netでコンパイルしてみたので確認してください。
ちなみ、ソースは質問者様の書いたものをそのままコンパイルしました。
#include<stdio.h> が 1行目になります。
==============================================================
mergesort.cpp(8) : error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません
mergesort.cpp(10) : error C3861: 'inputdata': 識別子が見つかりませんでした
mergesort.cpp(12) : error C3861: 'mergesort': 識別子が見つかりませんでした
mergesort.cpp(13) : error C3861: 'printdata': 識別子が見つかりませんでした
mergesort.cpp(17) : error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません
mergesort.cpp(17) : error C2365: 'inputdata' : 再定義; 以前の定義は '以前は不明な識別子' でした。
mergesort.cpp(21) : warning C4244: '引数' : 'time_t' から 'unsigned int' への変換です。データが失われる可能性があります。
mergesort.cpp(31) : error C2365: 'mergesort' : 再定義; 以前の定義は '以前は不明な識別子' でした。
mergesort.cpp(35) : error C3861: 'mergesort': 識別子が見つかりませんでした
mergesort.cpp(36) : error C3861: 'mergesort': 識別子が見つかりませんでした
mergesort.cpp(37) : error C3861: 'merge': 識別子が見つかりませんでした
mergesort.cpp(41) : error C2365: 'merge' : 再定義; 以前の定義は '以前は不明な識別子' でした。
mergesort.cpp(54) : error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません
mergesort.cpp(54) : error C2365: 'printdata' : 再定義; 以前の定義は '以前は不明な識別子' でした。
mergesort.cpp(59) : warning C4508: 'printdata' : 関数に戻り値の型が指定されていません。戻り値を void 型と見なします。
mergesort - エラー 13、警告 2
========== ビルド: 0 正常終了、1 失敗、0 更新、0 スキップ ==========
ご自身で確認してみてください。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# 並列プログラミングのπ計算について 1 2022/07/16 22:30
- C言語・C++・C# C 言語の Gauss Jordan 法について 2 2022/12/28 11:16
- C言語・C++・C# 質問です 下記のコードを分かりやすく解説お願いします 初心者です #include ‹stdio.h 3 2022/05/26 22:03
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ハンドルされていない例外が発...
-
2重定義って??
-
DWORDの実際の型は何でしょうか
-
関数の実体定義にヘッダファイ...
-
visualstudio C# テキストボッ...
-
クラスや構造体のarrayを作りた...
-
構造体の宣言でエラーが出ます。
-
long型の定数の末尾にLを付ける...
-
変数の型を定義しなかった場合...
-
VC6でlong longでエラー?
-
main.c:7:43: warning: implici...
-
分割コンパイル時に構造体....
-
【#define】 defineで定義した...
-
構造体のあるメンバを基準にソ...
-
C++のfor文について
-
CStringを含むconst構造体
-
VB 関数
-
C言語エラーの解決法教えてくだ...
-
[C++]継承したクラスのコンスト...
-
エラー「invalid conversion fr...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
DWORDの実際の型は何でしょうか
-
visualstudio C# テキストボッ...
-
2重定義って??
-
long型の定数の末尾にLを付ける...
-
C++のfor文について
-
typedef enumの使い方を教えて...
-
関数の実体定義にヘッダファイ...
-
変数の型を定義しなかった場合...
-
ハンドルされていない例外が発...
-
C++でboolにintの値を代入する...
-
main.c:7:43: warning: implici...
-
プログラムの中で別のmainを呼...
-
【#define】 defineで定義した...
-
void func( void )について
-
構造体の要素すべてに対する四...
-
構造体の宣言でエラーが出ます。
-
C++の(左辺値)参照を参照渡し
-
main()とint main(void)の違い
-
intとINTの違いは?
-
DLLでLIBファイルが作成されない
おすすめ情報