質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

977閲覧

2次元配列の動的メモリ確保とコアダンプ修正

pekeuto

総合スコア19

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/05/22 08:02

前提・実現したいこと

k近傍による判断結果を出力するコードを書いている途中です。
実現したいこと
・a配列の2次元配列(nxd)の動的メモリ確保の仕方
・mergesort関数によるコアダンプの修正

発生している問題・エラーメッセージ

セグメンテーション違反です (コアダンプ)

該当のソースコード

C

1#include<stdio.h> 2#include<stdlib.h> 3#include<math.h> 4#define k 3 5int merge(double *arr,int p,int q,int r){ 6 int i,j=0,bi=p,ci=q+1; 7 double *T=(double*)malloc((r-p+1)*sizeof(double)); 8 while(bi!=q+1){ 9 if(arr[bi]<=arr[ci]){ 10 T[j]=arr[bi]; 11 ++j; 12 ++bi; 13 }else{ 14 T[j]=arr[ci]; 15 ++j; 16 ++ci; 17 } 18 if(ci==r+1){ 19 break; 20 } 21 } 22 if(bi==q+1){ 23 while(j!=r-p+1){ 24 T[j]=arr[ci]; 25 ++j; 26 ++ci; 27 } 28 }else if(ci==r+1){ 29 while(j!=r-p+1){ 30 T[j]=arr[bi]; 31 ++j; 32 ++bi; 33 } 34 } 35 for(i=0;i<r-p+1;++i){ 36 arr[i+p]=T[i]; 37 } 38 free(T); 39 return 0; 40} 41int mergesort(double *arr,int a,int b){ 42 int mid; 43 double t=0; 44 if(a+1==b){ 45 if(arr[a]>arr[b]){ 46 t=arr[a]; 47 arr[a]=arr[b]; 48 arr[b]=t; 49 } 50 return 1; 51 } 52 mid=(a+b)/2; 53 mergesort(arr,a,mid); 54 mergesort(arr,mid+1,b); 55 merge(arr,a,mid,b); 56 return 0; 57} 58double dis(int size1,int size2,double a[size1][size2],double *s){ 59 double u,v,ans1=0,ans=0; 60 int i=0; 61 for(i=0;i<size2;++i){ 62 u=a[size1][i]; 63 v=s[i]; 64 ans1+=pow((u-v),2); 65 } 66 ans=sqrt(ans1); 67 printf("%lf ",ans); 68 return ans; 69} 70int knn_diag(double *s,int n,int d,double a[n][d]){ 71 int i=0,c=0; 72 double b[5]={}; 73 for(i=0;i<n;++i){ 74 b[i]=dis(i,d,a,s);//距離をbに代入 75 } 76 /*for(i=0;i<n;++i){ 77 printf("%lf ",b[i]); 78 }*/ 79 c=mergesort(b,0,n-1);//小さい方から順に並べる 80 for(i=0;i<k;++i){ 81 printf("%lf \n",b[i]);//k番目まで出力 82 } 83 return 0; 84} 85int main(){ 86 int n,d,i=0,j=0,c=0; 87 scanf("%d %d",&n,&d); 88 //n=5,d=2; 89 double a[5][2]={{180.0,60.0},{164.0,90.0},{151.0,80.0},{153.0,50.0},{172.0,40.0}};//aをnxd配列の動的メモリ確保 90 91 //aにnxd個のデータを標準入力で代入 92 /*for(i=0;i<n;++i){ 93 for(j=0;j<d;++j){ 94 scanf("%lf",&a[i][j]); 95 } 96 }*/ 97 double *s=(double*)malloc(d*sizeof(double)); 98 //s配列にd個のデータを標準入力で代入 99 for(i=0;i<d;++i){ 100 scanf("%lf",&s[i]); 101 } 102 c=knn_diag(s,n,d,a); 103 if(c==0){ 104 printf("You are healthy!\n"); 105 }else{ 106 printf("You have a heart disease!\n"); 107 } 108 return 0; 109}

試したこと

knn_diag関数でmergesort関数による並び替えをするところでコアダンプが発生したと思います。

補足情報(FW/ツールのバージョンなど)

標準入力
5 2
150 60

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

プログラム自体の期待する動作がいまいちよくわかりませんが。

・mergesort関数によるコアダンプの修正

mergesortに渡されるパラメータをちょっとトレースしてみましょう。
n=5として。
knn_diag()から呼び出しmergesort(b,0,4)
mergesortに入って、
mid=(0+4)/2;
でmidは2
mergesort(arr,0,2); ...A
mergesort(arr,3,4); ...B

Aのmergesortに入って
mid=(0+2)/2;
で1
mergesort(arr,0,1) ...AA
mergesort(arr,2,2) ...AB

AAはa+1==bの条件にハマって素直にreturn。ABに入って
mid=(2+2)/2;
で2
mergesort(arr,2,2) ...ABA
mergesort(arr,3,2) ...ABB

あれれ? ABとABAは同じ。つまり、ABAからはまたmergesort(arr,2,2);が呼ばれて、そこからまた...永遠にmergesort(arr,2,2);の呼び出しが続いてスタックを消費し尽くして、なおメモリを消費してコアダンプ、ということが想定されますね。

mergesortの後ろ2つのパラメータが等しくなるというのはどういうことか、そのときどうするべきかが考えられていません。
(それ以外の間違いがあるかどうかはチェックしていません)

・a配列の2次元配列(nxd)の動的メモリ確保の仕方

先に言っておきますけれど、動的配列ということはプログラム中でサイズが変わる可能性があるということなので、生成した配列にソースコード上の初期値記述で初期値を与えることは出来ませんよ。

gccだとCのオプション機能「可変長配列」が使えるので、サイズの小さな(スタック上に置いても問題ないサイズの)配列なら、例えば

C

1int n,d; 2//n,dを適宜設定する 3double a[d][n];

でいいです。
サイズが大きくてヒープにとりたいのなら

C

1double (*a)[n]; 2a = malloc( sizeof(double)*d*n );

でいいでしょう。(もちろん、メモリを確保できたかの確認はして下さい)

可変長配列が使えないMicrosoft Cなどでは、素直な「2次元配列の動的確保」は出来ないと思ってもいいかも知れません。もちろん、それに相当する結果は得られますけれど。「2次元配列」を確保したら、そのポインタは「1次元配列へのポインタ」型変数に格納するわけですが、この1次元配列の要素数を動的に指定する手段がないからです。


余計なツッコミかもしれませんが、

C

1 scanf("%d %d", &n, &d); 2 //n=5,d=2; 3 double a[5][2] = {{180.0, 60.0}, {164.0, 90.0}, {151.0, 80.0}, {153.0, 50.0}, {172.0, 40.0}}; //aをnxd配列の動的メモリ確保

nやdはどんな値になるか、ユーザー入力次第なわけで、それをint knn_diag(double *s, int n, int d, double a[n][d])に与えるようなことは私にはとてつもなく危険なことに思えます。

投稿2019/05/26 02:54

thkana

総合スコア7629

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

C

1#include<stdio.h> 2#include<stdlib.h> 3int main(){ 4 int i,j,n=5; 5 double **a=(double**)malloc(n*sizeof(double*)); 6 for(i=0;i<6;++i){ 7 a[i]=(double*)malloc(n*sizeof(double)); 8 } 9 for(i=0;i<5;++i){ 10 for(j=0;j<5;++j){ 11 scanf("%lf",&a[i][j]); 12 } 13 } 14 for(i=0;i<5;++i){ 15 for(j=0;j<5;++j){ 16 printf("%.2lf",a[i][j]); 17 } 18 } 19}

投稿2019/05/24 12:11

pekeuto

総合スコア19

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

int mergesort(double *arr, int a, int b)のarrが壊れています。
イメージ説明
原因を確かめましょう。

投稿2019/05/22 09:25

cateye

総合スコア6851

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問