こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

C言語のオーバーフローについて

csvからデータを読み取り、計算させるプログラムで、行が多くなると「StuckOverFlowReception」と表示されます。静的に領域を確保していることに原因があるような気がするのですが、どこがオーバーフローしているのか、どう直せばよいのかがわかりません。改善のご指摘をお願いします。 VisualStudio2010をwindows7で使用しています。プログラム初心者なので、かなりみにくいかもしれません。すいません。ちなみに15行ぐらいにするとオバーフローと表示されます。



#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define N 20//行数の定義
#define M 2048//列数の定義

int main()
{
char *fname = "ttt.csv"; //読み取り用ファイル
char *ffname = "tk.csv"; //読み取り用ファイル
FILE *IN1, *IN2, *OUT1, *OUT2;
char buff[30000]; //配列を静的に確保(桁が大きいので、大きくとっています)
char *pbuff; //読み取ったデータを格納する用
char arv[600]; //ffnameの配列用
char *parv; //arv[]の格納用
double a[N][M+30], b[N][M], c[N][M], w[4][32]; //配列の領域を定義
int i, j, x; //for文の繰り返し用
double m, n; //計算結果の一時的な格納用

if((IN1 = fopen(fname, "r")) == NULL){  ////ファイルを開く↓
printf("can't open the %s", fname);
return 0;
}
if((IN2 = fopen(ffname, "r")) == NULL){
printf("can't open the %s", ffname);
return 0;
}
if((OUT1 = fopen("high wavelet.csv", "w")) == NULL){
printf("can't open the ha.csv");
return 0;
}
if((OUT2 = fopen("low wavelet.csv", "w")) == NULL){
printf("can't open the la.csv");
return 0;
}                         ////ファイルを開く↑


i=j=0; //配列の取得↓
while(fgets(buff, 30000, IN1) != NULL){ //csvデータ1行読み込みの繰り返し
pbuff = buff;
while((pbuff = strtok(pbuff, ",\n")) != NULL){ //pbuffのデータを区切る
a[i][j++] = strtod(pbuff, NULL); //,をとばして配列に格納
pbuff = NULL;
}
i++;
j=0;
}

i=j=0; //上の作業と同じ↓
while(fgets(arv, 600, IN2) != NULL){
parv = arv;
while((parv = strtok(parv, ",\n")) != NULL){
w[i][j++] = strtod(parv, NULL);
parv = NULL;
}
i++;
j=0;
}          ///ここまででcsvを配列に格納完了

x=0;                //計算上必要な
      for(i=0; i<N; i++){         //作業をしてる
for(j=0; j<30; j++){    //だけなので、ここは
a[i][M+j] = a[i][j];//無視してください
}
}

for(i=0; i<N; i++){        //ここから実際の計算
for(j=0; j<M; j++){  //計算長くてすいません
m = (a[i][j]*w[0][0] + a[i][j+1]*w[0][1] + a[i][j+2]*w[0][2] + a[i][j+3]*w[0][3] + a[i][j+4]*w[0][4] + a[i][j+5]*w[0][5] + a[i][j+6]*w[0][6] + a[i][j+7]*w[0][7] + a[i][j+8]*w[0][8] + a[i][j+9]*w[0][9]
+ a[i][j+10]*w[0][10] + a[i][j+11]*w[0][11] + a[i][j+12]*w[0][12] + a[i][j+13]*w[0][13]
+ a[i][j+14]*w[0][14] + a[i][j+15]*w[0][15] + a[i][j+16]*w[0][16] + a[i][j+17]*w[0][17]
+ a[i][j+18]*w[0][18] + a[i][j+19]*w[0][19] + a[i][j+20]*w[0][20] + a[i][j+21]*w[0][21]
+ a[i][j+22]*w[0][22] + a[i][j+23]*w[0][23] + a[i][j+24]*w[0][24] + a[i][j+25]*w[0][25]
+ a[i][j+26]*w[0][26] + a[i][j+27]*w[0][27] + a[i][j+28]*w[0][28] + a[i][j+29]*w[0][29]
+ a[i][j+30]*w[0][30] + a[i][j+31]*w[0][31]);

n = (a[i][j]*w[1][0] + a[i][j+1]*w[1][1] + a[i][j+2]*w[1][2] + a[i][j+3]*w[1][3] + a[i][j+4]*w[1][4] + a[i][j+5]*w[1][5] + a[i][j+6]*w[1][6] + a[i][j+7]*w[1][7] + a[i][j+8]*w[1][8] + a[i][j+9]*w[1][9]
+ a[i][j+10]*w[1][10] + a[i][j+11]*w[1][11] + a[i][j+12]*w[1][12] + a[i][j+13]*w[1][13]
+ a[i][j+14]*w[1][14] + a[i][j+15]*w[1][15] + a[i][j+16]*w[1][16] + a[i][j+17]*w[1][17]
+ a[i][j+18]*w[1][18] + a[i][j+19]*w[1][19] + a[i][j+20]*w[1][20] + a[i][j+21]*w[1][21]
+ a[i][j+22]*w[1][22] + a[i][j+23]*w[1][23] + a[i][j+24]*w[1][24] + a[i][j+25]*w[1][25]
+ a[i][j+26]*w[1][26] + a[i][j+27]*w[1][27] + a[i][j+28]*w[1][28] + a[i][j+29]*w[1][29]
+ a[i][j+30]*w[1][30] + a[i][j+31]*w[1][31]);

b[i][x] = m; //配列×配列をしてm、nに一時的に格納し
c[i][x] = n; //新たな配列に入れてます
x++;
j++;
}
x=0;
}

for(i=0; i<N; i++){       //ここから新たに得た配列をcsvに書き込んでいます
for(j=0; j<(M/2); j++){
fprintf(OUT1, "%e", b[i][j]);
fprintf(OUT2, "%e", c[i][j]);
if(j==(M/2-1)){
fprintf(OUT1, "\n");
fprintf(OUT2, "\n");
}else{
fprintf(OUT1, ",");
fprintf(OUT2, ",");
}
}
}

fclose(IN1);
fclose(IN2);
fclose(OUT1);
fclose(OUT2);


rewind(stdin);
getchar();
return 0;
}

投稿日時 - 2013-10-28 15:16:54

QNo.8324323

困ってます

質問者が選んだベストアンサー

「StuckOverFlow」辺りで検索すると出てくると思いますが……。

一般的にローカル変数はスタック領域に作成される事が多いです。
そして、VisualStudioではスタック領域は1M程度確保される場合が多いようです。

そんなワケで、「ローカル変数に大量のメモリを使用する」と、スタックオーバーフローになることがあります。

対処方法は3通り…ですかね。
・リンカーオプションでスタック領域を大きくする。(どっかで限界来ますけどねぇ…)
・グローバル変数にする。(どっからでも書き換えできてウマー。知らないうちに書き換えられてあれぇ???)
・静的変数にする。(グローバル変数よりはマシでしょう)
・ヒープ領域から動的確保する。(ポインタ使う事になりますが。多次元配列だと工夫が必要でしょう。)

ヒープから確保する。ってのが一般的な対処方法でしょうね。
次点が静的変数でしょうか。
# double a[N][M+30], b[N][M], c[N][M], w[4][32]; ではなく
# static double a[N][M+30], b[N][M], c[N][M], w[4][32]; となる。

投稿日時 - 2013-10-28 15:37:47

お礼

スタック領域を増やすことは検討したのですが、やはり限界があることから、動的に確保すべきかもしれません。ただ、原因の変数がわかれば、それだけの変更でよかったのですが、わからないだけに、とりあえずプログラム書き換えよう…

と、思って、試しで静的変数にしたとたん一気に行数が増えました!確認したまでで200までいけます。
staticなので格納領域が毎度初期化されない?からよかったのでしょうか?

とにかく、策をわざわざ考えていただきありがとうございます!

投稿日時 - 2013-10-28 18:26:45

ANo.1

このQ&Aは役に立ちましたか?

1人が「このQ&Aが役に立った」と投票しています

回答(6)

ANo.6

「1度に使うのが1行」なら
csvのデータを全部読み込んでから纏めて計算するのではなく
csvのデータを1行読み込んでその行を計算して出力→次の行を読み込む
というふうにすればいいということではないでしょうか。

投稿日時 - 2013-10-28 19:09:08

お礼

あー、なるほど! データを格納して残していくのではなく、1行計算したら、上から書き換えていくってことですね?確かにそれなら1行分の領域を確保するだけで済みますね。かなりいい考え方ですね。ありがとうございます!

投稿日時 - 2013-10-29 12:05:39

ANo.5

「数百行あるので、なるべく沢山で計算できたらと…」の意味がさっぱり分からない.

何百万行あろうと「一度に 1行しか使わない」のであれば「今現在の処理に必要な 1行」だけをおぼえておけばいい. 少なくとも, この質問で挙がっているプログラムについてはその通りでしょ?

ついでにいうと, 場合によっては fgets を使わなくて済むかもしれない.

投稿日時 - 2013-10-28 18:07:19

お礼

すいません。つまり、「1行計算して出力」を1度の実行で何行分もやりたいってことです。要は、何度も実行するのがめんどくさいっていうわがまま…もしかして、1行計算できれば、もっと簡単な方法で多数の行を計算できる方法があるっていうことですが?
だとすれば自分の勉強不足が甚だしいですね。申し訳ないです。
とりあえず静的変数にして行数は増えました。
考えてくださりありがとうございます!

投稿日時 - 2013-10-28 18:40:39

ANo.4

a に入れるべきデータを, なぜ全部読み込まなければならないのですか?

投稿日時 - 2013-10-28 16:13:24

補足

列は2048データ固定で、wevelet変換という1行まるまる使って計算する手法を使ってます。なので、行に関しては、何度も同じ計算をして、最終的に同csvにコピーすればいいのですが、数百行あるので、なるべく沢山で計算できたらと…

投稿日時 - 2013-10-28 16:28:20

ANo.3

Mは本当は2048もいらないのでは?

だったら malloc を勉強して動的にとれば実際のデータ分だけで済みます。

投稿日時 - 2013-10-28 16:10:31

補足

データは2048個固定です。
一応
char buff[] → char *buff;

while(fgets(buff, 30000, IN1) != NULL){
buff = (char*)malloc(30000);
pbuff = buff;
while((pbuff = strtok(pbuff, ",\n")) != NULL){
a[i][j++] = strtod(pbuff, NULL);
pbuff = NULL;
}
i++;
j=0;
free(buff);
}

でやったのですが、同じでした。

投稿日時 - 2013-10-28 18:00:42

double a[N][M+30], b[N][M], c[N][M], w[4][32]; //配列の領域を定義

この行の領域割り当てが多きすぎるので、これを、

double a[N][M+30], b[N][M], c[N][M], w[4][32]; //配列の領域を定義

main()
{



}

と、mainの外、しかし、同一ファイル内に移してみて下さい。

投稿日時 - 2013-10-28 15:44:05

お礼

参考書に、1つの関数に詰め込みすぎると予期せぬことが起こりやすいと書いてありました。やはりそれも原因の1つなのでしょうか。ご指摘のように関数を変えたり、より計算が楽になるような工夫をしてみようと思います。
ご指摘ありがとうございます!

投稿日時 - 2013-10-28 18:46:13

あなたにオススメの質問