🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

4回答

13013閲覧

ヒープは壊れていますと表示される

Anfaenger

総合スコア14

C

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2021/02/28 10:59

編集2021/03/05 01:50

下記プログラムにてヒープは壊れていますとエラーが出ます。
(修正:現在は「読み取り中にアクセス違反が発生」と表示されます)
配列xをS_fftのakに渡すときにサイズを超えている(?)のが原因だと思うのですが、
対処法が分かりません。ヒントをください。
エラー箇所はmain関数内の三番目のfor文の中です。
#エラー内容
ハンドルされない例外が 0x77BF0F01 (ntdll.dll) で発生しました(WAVFFT02.exe 内): 0xC0000005: 場所 0x000010A5 の読み取り中にアクセス違反が発生しました。

C++

1#include <stdio.h> 2#include <math.h> 3#include <stdlib.h> 4#pragma warning(disable:4996) 5 6typedef struct 7 8{ 9 10 int fs; //サンプリング周波数 11 12 int bits; //量子化bit数 13 14 int L; //データ長 15 16} WAV_PRM; 17 18#define PI 4.0*atan(1.0) // 円周率 19 20void S_fft(double* x, double* y, int, int); 21#define N 4096 // N=データ総数(2,4,8,16,32,64,128,256,512,1024 のどれか) 22 23double* audio_read(WAV_PRM* prm, char* filename); 24 25double* audiodatasize; 26 27int main(void) { 28 29 double* x, * y; 30 x = (double*)malloc(sizeof(double) * N); 31 y = (double*)malloc(sizeof(double) * N); 32 33 FILE* fp = fopen("fft.txt", "w"); // ファイル入出力 34 35 WAV_PRM prm_in; 36 double* data; 37 //FILE* audio = fopen("sinwave.wav", "rb"); 38 FILE* txt = fopen("mansample.txt", "w"); 39 char fn[] = "mansample.wav"; 40 41 int i, Fr = 4096; 42 const double dt = 0.00005; 43 double sc; 44 45 46 double fq; 47 int pw = 0; 48 printf("STG 01\n"); 49 sc = 2.0 * PI * dt; 50 for (i = 0; i < N; i++) { 51 if (x != NULL && y != NULL) { 52 // x = audio_read(&prm_in, fn); 53 y[i] = 0.0; 54 } 55 } 56 x = audio_read(&prm_in, fn); 57 printf("STG 02\n"); 58 // Fourier変換 59 60 printf("Size of Data : %d\n", sizeof *x); 61 62 S_fft(x, y, N, -1); 63 64 printf("STG 03\n"); 65 66 //for (i = 0; i < Fr; i++) printf(" i=%d %f %f \n", i, x[i], y[i]); 67 68 // 計算結果をファイルに格納 69 70 for (i = 0; i < N / 2; i++) { 71 if (x != NULL && y != NULL) { 72 pw = sqrt(x[i] * x[i] + y[i] * y[i]) * 100; // パワースペクトル 73 } 74 fq = i / (dt * Fr) * 2.2; // 周波数 75 //printf("%f = %d / (%f * %d)\n", fq, i, dt, N); 76 fprintf(txt, "%fHz %d\n", fq, pw); // エラー箇所 77 } 78 printf("STG 04\n"); 79 //fclose(fp); 80 //fclose(audio); 81 fclose(txt); 82 free(x); 83 free(y); 84 return 0; 85} 86 87/********* Fourier変換および逆Fourier変換を行う副関数 ***************/ 88/* 入力: x[n]: 被解析波形(振幅) n; 離散データの数 */ 89/* ff: Fourier変換の場合は -1, 逆Fourier変換の場合は 1 */ 90/* 出力: ak[n]:cos関数の係数、 bk[n]:sin関数の係数 */ 91/**********************************************************************/ 92void S_fft(double ak[], double bk[], int n, int ff) { 93 int i, j, k, k1, num, nhalf, phi, phi0; 94 static int rot[N]; 95 double s, sc, c, a0, b0, tmp; 96 97 for (i = 0; i < n; i++) rot[i] = 0; 98 99 //ak = (double*)malloc(sizeof(double) * N); 100 //bk = (double*)malloc(sizeof(double) * N); 101 102 nhalf = n / 2; num = n / 2; sc = 2.0 * PI / n; 103 while (num >= 1) { 104 for (j = 0; j < n; j += 2 * num) { 105 phi = rot[j] / 2; phi0 = phi + nhalf; 106 c = cos(sc * phi); s = sin(sc * phi * ff); 107 for (k = j; k < j + num; k++) { 108 k1 = k + num; 109 if (ak != NULL && bk != NULL) { 110 a0 = ak[k1] * c - bk[k1] * s; 111 b0 = ak[k1] * s + bk[k1] * c; 112 ak[k1] = ak[k] - a0; bk[k1] = bk[k] - b0; 113 ak[k] = ak[k] + a0; bk[k] = bk[k] + b0; 114 } 115 rot[k] = phi; rot[k1] = phi0; 116 } 117 } 118 num = num / 2; 119 } 120 if (ff < 0 && ak != NULL && bk != NULL) { 121 for (i = 0; i < n; i++) { 122 ak[i] /= n; bk[i] /= n; 123 } 124 } 125 126 for (i = 0; i < n - 1; i++) { 127 if ((j = rot[i]) > i && ak != NULL && bk != NULL) { 128 tmp = ak[i]; ak[i] = ak[j]; ak[j] = tmp; 129 tmp = bk[i]; bk[i] = bk[j]; bk[j] = tmp; 130 } 131 } 132} 133 134 135 136double* audio_read(WAV_PRM* prm, char* filename) 137 138{ 139 140 //変数宣言 141 142 FILE* fp; 143 144 int n; 145 146 double* data; 147 148 char header_ID[4]; 149 150 long header_size; 151 152 char header_type[4]; 153 154 char fmt_ID[4]; 155 156 long fmt_size; 157 158 short fmt_format; 159 160 short fmt_channel; 161 162 long fmt_samples_per_sec; 163 164 long fmt_bytes_per_sec; 165 166 short fmt_block_size; 167 168 short fmt_bits_per_sample; 169 170 char data_ID[4]; 171 172 long data_size; 173 174 short data_data; 175 176 177 178 //wavファイルオープン 179 180 fp = fopen(filename, "rb"); 181 182 183 184 //wavデータ読み込み 185 186 fread(header_ID, 1, 4, fp); 187 188 fread(&header_size, 4, 1, fp); 189 190 fread(header_type, 1, 4, fp); 191 192 fread(fmt_ID, 1, 4, fp); 193 194 fread(&fmt_size, 4, 1, fp); 195 196 fread(&fmt_format, 2, 1, fp); 197 198 fread(&fmt_channel, 2, 1, fp); 199 200 fread(&fmt_samples_per_sec, 4, 1, fp); 201 202 fread(&fmt_bytes_per_sec, 4, 1, fp); 203 204 fread(&fmt_block_size, 2, 1, fp); 205 206 fread(&fmt_bits_per_sample, 2, 1, fp); 207 208 fread(data_ID, 1, 4, fp); 209 210 //fread(&data_size, 4, 1, fp); 211 fread(&data_size, sizeof(unsigned char), 4, fp); 212 213 214 215 //パラメータ代入 216 217 prm->fs = fmt_samples_per_sec; 218 219 prm->bits = fmt_bits_per_sample; 220 221 prm->L = data_size / 2; 222 223 224 225 //音声データ代入 226 227 data = (double*)calloc(prm->L, sizeof(double)); 228 audiodatasize = (double*)malloc(sizeof(double) * prm->L); 229 230 for (n = 0; n < prm->L; n++) { 231 232 fread(&data_data, 2, 1, fp); 233 234 if (data != NULL) { 235 data[n] = (double)data_data / 32768.0; 236 } 237 238 } 239 240 241 242 fclose(fp); 243 244 return data; 245 246}

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

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

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

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

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

guest

回答4

0

どこかでアクセス違反を起こして、ヒープメモリ領域を破壊しています。
デバッグ環境を整え、どこでアクセス違反を起こしてるかを探してみてください


C言語のコードを書くなら、デバッグできる環境を整えましょう。
Eclipseや、WindowsならVisualStudioなど。
コードの任意の場所で実行を止め、変数のナカミを見ることができます。そこから1行づつ実行して、コードの流れを見れるようになります
そうすれば、アテズッポでコードを書かなくて済むようになります。

投稿2021/02/28 11:14

y_waiwai

総合スコア88038

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

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

Anfaenger

2021/02/28 12:07

前回教えて頂いた通りVisual StudioでF5キーでデバッグしながら進めているのですが…… デバッグの仕方がまずかったでしょうか。もう少し調べてみます。 ありがとうございます。
Anfaenger

2021/02/28 12:20

ブレークポイントを設定して探してみてもやはりどこでヒープメモリ領域を破壊しているのか見当がつきません。もう少しだけヒントをください、お願いします。
y_waiwai

2021/02/28 12:20

各ポインタの値とその範囲を見てみてください。 アドレス違い上でないか、確保したサイズを超えてアクセスしてないかなど、おかしいところを探すのは難しいかも知れません。 C言語では、実行時エラーのチェックは行わない、ので、エラーのでてるところがおかしいとは限らない、ってとこに注意してください。
y_waiwai

2021/02/28 12:27

ざっとみただけですが、 > x = audio_read(&prm_in, fn); prm_inは初期化されてませんね
Anfaenger

2021/02/28 13:37

prm_inの初期化は必要でしょうか…? とあるサイトを参考に(というか関数をお借りして)作ったコードなのですが、 そのサイトでは特に初期化等はしていなかったようなのでそのまま使用しています。
y_waiwai

2021/02/28 13:44

そこらへん、ステップ実行でどうなるか見てみれば まあ、ワケワカラン赤の他人としてはこれ以上はやめておきますw
guest

0

mallocやcallocが必要なメモリを指定して呼び出すのに対して、freeは解放するメモリの大きさを指定していないことを不思議に思ったことはありませんか。

freeが解放するメモリの大きさを指定しなくてよいのは、mallocが返すメモリへのポインタの手前の管理領域に割り当てたメモリの大きさを持っているからです。

多くの場合、メモリ破壊は領域外アクセス(SIGSEGV)になることが多いのですが、それ以外のエラーになる場合もあります。
それは、続けてmalloc等で取った領域、xとyがあり、xを配列などとして使って取ったメモリを超えて書き込んで、yの管理領域を上書きしてしまいうエラーです。このあと、yをfreeしようとすると、free関数がチェックをして管理領域が壊れていることを知らせます。
あるいは、x += 1 とか y++ をやってmallocしたときの先頭アドレスでない状態にしてからfreeを行った場合も同じエラーが出ます。
今回起こっているのはそういう現象です。
xの指す領域でサイズを超えて書き込んでいるか、xやyを更新していないかをを調べてください。

投稿2021/03/01 00:25

編集2021/03/01 01:00
ppaul

総合スコア24670

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

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

0

malloc,callocで確保したメモリ以上に書き込んでいるのでは。確保したメモリのサイズと、メモリにループで書き込んでる所をデバッグして突き合わせていくしかないですね。

C

1x = audio_read(&prm_in, fn);

ここで戻ってきたxのメモリ長は不明ですが、

C

1 for (i = 0; i < N; i++) { 2 if (x != NULL && y != NULL) { 3 pw = sqrt(x[i] * x[i] + y[i] * y[i]) * 100; // パワースペクトル 4 } 5 fq = i / (dt * Fr) * 2.2; // 周波数 6 //printf("%f = %d / (%f * %d)\n", fq, i, dt, N); 7 fprintf(txt, "%fHz %d\n", fq, pw); /* エラー箇所 */ 8 }

N固定でループ回してると、xのメモリ長<(N*sizeof(double)) の場合にバッファオーバーランすると思います。

VisualStudioなら、デバッグ中にメニューのデバッグ⇒ウィンドウ⇒メモリで、ポインタのアドレスを打ち込んで直接メモリの中を覗けます。電卓で16進数表示でアドレス計算しながら、どこまで書き込まれたか実際に確認してみるとよいでしょう。

投稿2021/02/28 13:01

編集2021/02/28 14:25
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

メモリを動的確保したことが失敗の原因だと思う

違います。
動的確保が直接の原因ではありません。動的であれ静的であれ、確保した領域を超えて書き込みを行っているのでしょう。ちゃんとわからないでメモリをめちゃくちゃにいじくり回していることこそが「原因」といえるでしょう。C言語は、いろいろなことを「プログラマの責任」のひとことで済ませてしまう怖い言語です。「初心者」をいいわけにちゃんと理解しないでプログラムを作るなら、その結果はすべて自分に跳ね返ってきますので覚悟してください。

さて。
main関数の
x = (double*)malloc(sizeof(double) * N);
ここで確保したメモリ領域は、使われないまま
x = audio_read(&prm_in, fn);
としてxが上書きされてしまうので、二度とアクセスできなくなります。いわゆる「メモリリーク」と呼ばれる不良です。(ヒープ破壊にはつながりませんが)

このとき、audio_read関数が返すのは
fread(&data_size, 4, 1, fp);
prm->L = data_size / 2;
data = (double*)calloc(prm->L, sizeof(double));
として確保した領域です。このあとにこの領域は
S_fft(x, y, N, -1);
としてS_fftに渡されます。S_fft(double ak[], double bk[], int n, int ff)の中では

C++

1 for (i = 0; i < n; i++) { 2 ak[i] /= n; bk[i] /= n; 3 }

などとしているところがあります。つまり、data_size<2*N以上でなければ、確保したエリアをはみ出してアクセスを行う(メモリの破壊を行う)ということになります(他に危ないところがあるかどうかのチェックはしていません)。ここが一番怪しいところです。しかし、入力ファイルの詳細が不明なため、ここでエラーが埋め込まれたのかどうかはしかとは確認できません。

また、audio_read関数中での
audiodatasize = (double*)malloc(sizeof(double) * prm->L);
は全く使われていないようですが、何か意図があるのですか? (これも直接のエラーにはなりませんが)

投稿2021/02/28 12:51

thkana

総合スコア7703

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

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

Anfaenger

2021/02/28 13:24

ありがとうございます、理解しました!多分そこだと思います! audiodatasizeは試行錯誤の残骸です。プログラム中のゴミです。お見苦しいコードですみません……。 試しにブレークポイントをその場所に設置してみたら、ak[i]の中身が{-nan}と表示されてしまいます。 これはどういう意味でしょうか?検索しても同じような内容が見当たらなくて……
Anfaenger

2021/02/28 13:45

ちなみになんですが、STG 03まで表示される(S_fftの実行が完了する)までプログラムが動くときと、STG 02までしか動かないときとがランダムに起こります。これも同じ原因でしょうか?
thkana

2021/02/28 22:11

そこまでプログラムを読んでいませんが、多分違う原因でしょう。 Cでは、動的に確保されるメモリ(ローカル変数とかmallocで確保した領域)は勝手には初期化されないので、生成直後は内容は不定(プログラムを実行してみて初めて値が決まること。特定の値が期待できないこと)となります。なにか値を設定する前にその値を使用して計算していたりして、その値が破綻を招いているのでは。
Anfaenger

2021/03/01 10:04

言われた通りakのメモリを確保しようとしてS_fft関数内にak = (double*)malloc(sizeof(double) * N)でメモリ領域を確保してみたら正常に動作はするのですが、出力結果が出鱈目になってしまいます。 ブレークポイントを設置してxの中身を覗いてみても原因が分かりません。 もう少しだけヒントをお願いします。
thkana

2021/03/01 11:38

プログラムは、首尾一貫していなければいけません。局所的にちょこちょこといじくり回してもダメなときはダメです。 まず、音声データを入力する領域とデータを出力する領域を兼用するのをやめて、それぞれに独立に必要なサイズで領域を確保するようにしてください。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問