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

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

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

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

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

Q&A

解決済

3回答

7943閲覧

ハンドルされない例外、書き込み中にアクセス違反。タイマー関数を使いビットマップ形式で球を描画したいのだが、描画途中で描画されなくなる

TRON1216.

総合スコア37

C

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

C++

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

0グッド

0クリップ

投稿2017/12/06 15:30

編集2017/12/08 09:59

.bat形式のあるデータ(球体の半径など)を読み取り、タイマー関数を用いてビットマップ形式で描画しようとしています。ビルドも無事にでき、実行したのですが、なぜか途中でエラーが起きます。半径の全データ数は約4600個あり、150msごとに再描画を繰り返す感じです。エラーのタイミングはさまざまで、2422番目のデータでストップしたり、3355番目でストップなどです。デバッグして調べたところ、全データの読み込みはちゃんとできていて、インフォヘッダーで書いた中身(g_img)が0になっていました。また、ハンドルされない例外が0x00365F6E で発生しました。や、書き込み中にアクセス違反が発生しました。といった文章がでてきました。メモリの解放のタイミングがおかしいのでしょうか?もしおかしければ解放のタイミングを知りたいです。また、この原因がメモリの解放以外にありそうでしたらアドバイスいただきたいです。メモリの解放のタイミング以外で考えると、BITMAPINFOHEADERもしくはCreatDIBitmap()のどこかがおかしいのだと考えています。ですが改善策がでてきません。よろしくお願いいたします。開発環境は、Visual Studio 2015 C++です。なお、まだ初心者なので、説明不足や知識不足、理解不足があるかもしれません。ご了承ください。下記に、描画するコードを載せておきます。

#include <math.h> #define ID_MYTIMER 1 typedef struct{ HINSTANCE hi0; HWND hwin7; BYTE *lpBmpData; BITMAPINFOHEADER bmp_ih; char *fname; int fsize; } IMG; IMG g_img; LRESULT CALLBACK WndProc_bitmap( HWND hWnd_bitmap, UINT msg, WPARAM wp, LPARAM lp ) { PAINTSTRUCT ps; HDC hdc, hdc_mem; HBITMAP hBmp; float x,y,z,r; int a, b, ab; float lam1,lam2,lam3; g_img.bmp_ih.biSize = sizeof(BITMAPINFOHEADER); g_img.bmp_ih.biWidth = 659/*674*/; g_img.bmp_ih.biHeight = -494/*532*/; g_img.bmp_ih.biPlanes = 1; g_img.bmp_ih.biBitCount = 32; g_img.bmp_ih.biCompression = BI_RGB; g_img.bmp_ih.biSizeImage = 659/*674*/ * 494/*532*/ * 4; g_img.bmp_ih.biXPelsPerMeter = 3704; g_img.bmp_ih.biYPelsPerMeter = 3704; g_img.bmp_ih.biClrUsed = 0; g_img.bmp_ih.biClrImportant = 0; g_img.lpBmpData = (BYTE *)malloc(659/*674*/*494/*532*/*4); switch (msg) { case WM_CREATE: //ウインドウが生成されたときに1度だけ通過 //時間割り込みの発生タイミングを設定 SetTimer(hWnd_bitmap, ID_MYTIMER, 150, NULL); break; case WM_TIMER: if (wp != ID_MYTIMER) return (DefWindowProc(hWnd_bitmap, msg, wp, lp)); k +=1; InvalidateRect(hWnd_bitmap, NULL, FALSE); break; case WM_PAINT: hdc = BeginPaint(hWnd_bitmap, &ps); hdc_mem = CreateCompatibleDC( hdc ); q = 0; p = 0; for ( a = 0; a < 494/*532*/; a++){ for( b = 0; b < 659/*674*/; b++){ ab = a*(659/*674*/*4) + b*4; //始めの項が行数、次の項が左から何ビット目かを表す。(blueの位置を決めている) if((b-329.5)*(b-329.5)+(a-494)*(a-494) <= (s[k]/4*1000000*329.5+0.5)*(s[k]/4*1000000*329.5+0.5)){ p = p+1.0; //円の内側のピクセル数の合計 x = b-329.5; y = 494-a; z = sqrtf(-(x*x)-(y*y)+(s[k]/4*1000000*329.5+0.5)*(s[k]/4*1000000*329.5+0.5)); r = sqrtf(x*x + y*y + z*z); lam1 = (x*XSUNm_3[k] + y*YSUNm_3[k] + z*ZSUNm_3[k])/(r*SUN_MOON[k]); //太陽の方向との内積 lam2 = (x*XEARTHm_3[k] + y*YEARTHm_3[k] + z*ZEARTHm_3[k])/(r*EARTH_MOON[k]); //地球の方向との内積 lam3 = (x*XEQLm_3[k] + y*YEQLm_3[k] + z*ZEQLm_3[k])/(r*EQL_MOON[k]); //EQLの方向との内積 /*g_img.lpBmpData[ab] = 179*lam3; g_img.lpBmpData[ab+1] = 179*lam3; g_img.lpBmpData[ab+2] = 179*lam3; g_img.lpBmpData[ab+3] = 0;*/ if(lam2>0){ g_img.lpBmpData[ab] = 230*lam2; g_img.lpBmpData[ab+1] = 216*lam2; g_img.lpBmpData[ab+2] = 0; g_img.lpBmpData[ab+3] = 0; } if(lam1>0){ g_img.lpBmpData[ab] = 0; g_img.lpBmpData[ab+1] = 255*lam1; g_img.lpBmpData[ab+2] = 255*lam1; g_img.lpBmpData[ab+3] = 0; } if(!(lam1>=0 || lam2>=0) ){ g_img.lpBmpData[ab] = 179*lam3; g_img.lpBmpData[ab+1] = 179*lam3; g_img.lpBmpData[ab+2] = 179*lam3; g_img.lpBmpData[ab+3] = 0; q = q+1; } if(494 < (s[k]/4*1000000*329.5+0.5)) ok = q*100/325546; if(494 >= (s[k]/4*1000000*329.5+0.5)) ok = q*100/p/*(M_PI* (s[k]/4*1000000*329.5+0.5)*(s[k]/4*1000000*329.5+0.5)/2)*/; } // else{ if((b-329.5)*(b-329.5)+(a-494)*(a-494) > (s[k]/4*1000000*329.5+0.5)*(s[k]/4*1000000*329.5+0.5)){ g_img.lpBmpData[ab] = 0; g_img.lpBmpData[ab+1] = 0; g_img.lpBmpData[ab+2] = 0; g_img.lpBmpData[ab+3] = 0; } } } hBmp = CreateDIBitmap(hdc, &(g_img.bmp_ih), CBM_INIT, g_img.lpBmpData, (BITMAPINFO *)(&(g_img.bmp_ih)), DIB_RGB_COLORS); free(g_img.lpBmpData); SelectObject(hdc_mem, hBmp); SetStretchBltMode(hdc, COLORONCOLOR); StretchBlt(hdc, 0, 0, 659/*674*/, 494/*532*/, hdc_mem, 0, 0, 659/*674*/, 494/*532*/, SRCCOPY); DeleteDC( hdc ); DeleteDC( hdc_mem ); DeleteObject( hBmp ); EndPaint(hWnd_bitmap, &ps); ReleaseDC( hWnd_bitmap, hdc ); break; mode_edit編集 arrow_downward自己解決方法を記入する attachment(0) thumb_up(0) 低評価 (0) delete

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

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

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

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

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

guest

回答3

0

ベストアンサー

これが原因かどうかわかりませんが、プログラム的にまずいなと思うところを書いておきます。

WM_TIMERメッセージの処理で、k += 1し、そのkはWM_PAINTの中でs[k]として配列のインデックスとして使用されてますが、このままだとkはどこまでも+1されてしまうので、ストッパーの処理が必要です。そうしないと配列をオーバーしてアクセスしてしまう可能性があります。

また、kをインクリメントする処理はWM_TIMERの中ではなく、WM_PAINTのなかでインクリメントして、その中でkの値が配列をオーバーしないように処理した方がいいと思います。そのほうが安全です。

投稿2017/12/07 08:53

PineMatsu

総合スコア3579

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

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

TRON1216.

2017/12/07 13:53

回答ありがとうございます。言いたいことはわかりました。150msごとにデータを順に再描画していこうと考えると、これしか思いつきませんでした。具体的にはどうすればいいのか見当がつきません。よろしければコードで教えていただけると幸いです。
PineMatsu

2017/12/08 07:44

WM_TIMERでは、InvalidateRectだけやって、k++はしない。 WM_PAINTの先頭でk++をやって、配列sの添字の上限でリミットを掛けておけば、配列のオーバーアクセスはなくなります。配列sサイズをARRAY_SIZEとすると、 if (++k > ARRAY_SIZE) k = ARRAY_SIZE - 1; の様な感じですね。
TRON1216.

2017/12/08 08:36

丁寧な返答ありがとうございます。やってみます!!
TRON1216.

2017/12/08 09:23

やりましたが、やはり同様の結果がおきました。あと、デバッグして調べましたが、毎回オーバーアクセスする前でプログラムが停止していました。おそらくg_imgがおかしいのだと思います。その中身がプログラム停止時に毎回0になっています。
PineMatsu

2017/12/11 08:25

これ、よく見たらswitch文の外で g_img.lpBmpData = (BYTE *)malloc(659/*674*/*494/*532*/*4); で、確保してますけど、これはまずいですよ。 つまり、WM_PAINTのメッセージの時だけ(case WM_PAINTの内側で)確保するようにしないと。もっと言えば、g_imgの各メンバーの初期化は、WM_PAINT処理の頭でやらないといけない、ということです。
TRON1216.

2017/12/11 17:25

すいませんいま回答みました。ご指摘ありがとうございます。直して実行してみます。
TRON1216.

2017/12/11 17:54

WM_PAINTの中に入れるとビルドはできるのですが実行した瞬間プログラムが停止しました、、。
PineMatsu

2017/12/12 08:57

どう直したかわからないので何とも言えませんが、WM_PAINT内の処理が多い(長い)ので別関数を作ってその中で処理させたほうが良いと思います。そのほうがデバッグしやすいし読みやすいです。その関数には引数としてWndProc_bitmapの引数なども作り方によっては渡してやる必要があります。 また、g_imgをグローバルで定義してますけど、グローバルである必然はあるのでしょうか?なければ、処理関数内で一時的に定義したほうが良いと思います。 あと、他の質問ページでウィンドウを動かした時におかしくなるということを書かれてましたが、ウィンドウを動かすとWM_PAINTメッセージがシステムから飛んできます。その関係で、タイマー処理での処理とバッティングしてしまう可能性があります。描画処理中は受け付けないような手段が必要かも。
TRON1216.

2017/12/12 10:17

g_imgをウィンドウプロシージャ内で定義し、g_imgの各メンバの初期化をWM_PAINT内にいれて実行したところ、ウィンドウを動かしてもプログラムは停止せず、最後まで描画できました。また、今までWM_PAINT内でしかfree(g_img.lpBmpData)を書いていなかったのですが、各WMメッセージに書きました。色々ご指摘いただき助かりました。 バッティングに関しては、初めて知ったことなので、これから調べていきたいと思います。
yumetodo

2017/12/12 12:02

まあどっかにatomicなフラグ変数を作って移動中はそのフラグを倒しておくようにしてやるんだろうなぁ。
guest

0

KoichiSugiyama 氏の言わんとする所は

c

1#include <math.h> 2#define ID_MYTIMER 1 3 4typedef struct{ 5 HINSTANCE hi0; 6 HWND hwin7; 7 BYTE *lpBmpData; 8 BITMAPINFO bmi; 9 char *fname; 10 int fsize; 11} IMG; 12 13IMG g_img; 14 15LRESULT CALLBACK WndProc_bitmap( HWND hWnd_bitmap, UINT msg, WPARAM wp, LPARAM lp ) 16{ 17 18 PAINTSTRUCT ps; 19 HDC hdc, hdc_mem; 20 HBITMAP hBmp; 21 float x,y,z,r; 22 int a, b, ab; 23 float lam1,lam2,lam3; 24 25 g_img.bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 26 g_img.bmi.bmiHeader.biWidth = 659/*674*/; 27 g_img.bmi.bmiHeader.biHeight = -494/*532*/; 28 g_img.bmi.bmiHeader.biPlanes = 1; 29 g_img.bmi.bmiHeader.biBitCount = 32; 30 g_img.bmi.bmiHeader.biCompression = BI_RGB; 31 g_img.bmi.bmiHeader.biSizeImage = 659/*674*/ * 494/*532*/ * 4; 32 g_img.bmi.bmiHeader.biXPelsPerMeter = 3704; 33 g_img.bmi.bmiHeader.biYPelsPerMeter = 3704; 34 g_img.bmi.bmiHeader.biClrUsed = 0; 35 g_img.bmi.bmiHeader.biClrImportant = 0; 36 37 g_img.lpBmpData = (BYTE *)malloc(659/*674*/*494/*532*/*4); 38 39 switch (msg) { 40 case WM_CREATE: //ウインドウが生成されたときに1度だけ通過 41 //時間割り込みの発生タイミングを設定 42 SetTimer(hWnd_bitmap, ID_MYTIMER, 150, NULL); 43 break; 44 45 case WM_TIMER: 46 if (wp != ID_MYTIMER) return (DefWindowProc(hWnd_bitmap, msg, wp, lp)); 47 k +=1; 48 InvalidateRect(hWnd_bitmap, NULL, FALSE); 49 break; 50 51 case WM_PAINT: 52 hdc = BeginPaint(hWnd_bitmap, &ps); 53 hdc_mem = CreateCompatibleDC( hdc ); 54 q = 0; 55 p = 0; 56 for ( a = 0; a < 494/*532*/; a++){ 57 for( b = 0; b < 659/*674*/; b++){ 58 ab = a*(659/*674*/*4) + b*4; //始めの項が行数、次の項が左から何ビット目かを表す。(blueの位置を決めている) 59 if((b-329.5)*(b-329.5)+(a-494)*(a-494) <= (s[k]/4*1000000*329.5+0.5)*(s[k]/4*1000000*329.5+0.5)){ 60 p = p+1.0; //円の内側のピクセル数の合計 61 x = b-329.5; 62 y = 494-a; 63 z = sqrtf(-(x*x)-(y*y)+(s[k]/4*1000000*329.5+0.5)*(s[k]/4*1000000*329.5+0.5)); 64 r = sqrtf(x*x + y*y + z*z); 65 lam1 = (x*XSUNm_3[k] + y*YSUNm_3[k] + z*ZSUNm_3[k])/(r*SUN_MOON[k]); //太陽の方向との内積 66 lam2 = (x*XEARTHm_3[k] + y*YEARTHm_3[k] + z*ZEARTHm_3[k])/(r*EARTH_MOON[k]); //地球の方向との内積 67 lam3 = (x*XEQLm_3[k] + y*YEQLm_3[k] + z*ZEQLm_3[k])/(r*EQL_MOON[k]); //EQLの方向との内積 68 // g_img.lpBmpData[ab] = 179*lam3; 69 // g_img.lpBmpData[ab+1] = 179*lam3; 70 // g_img.lpBmpData[ab+2] = 179*lam3; 71 // g_img.lpBmpData[ab+3] = 0; 72 if(lam2>0){ 73 g_img.lpBmpData[ab] = 230*lam2; 74 g_img.lpBmpData[ab+1] = 216*lam2; 75 g_img.lpBmpData[ab+2] = 0; 76 g_img.lpBmpData[ab+3] = 0; 77 } 78 if(lam1>0){ 79 g_img.lpBmpData[ab] = 0; 80 g_img.lpBmpData[ab+1] = 255*lam1; 81 g_img.lpBmpData[ab+2] = 255*lam1; 82 g_img.lpBmpData[ab+3] = 0; 83 } 84 if(!(lam1>=0 || lam2>=0) ){ 85 g_img.lpBmpData[ab] = 179*lam3; 86 g_img.lpBmpData[ab+1] = 179*lam3; 87 g_img.lpBmpData[ab+2] = 179*lam3; 88 g_img.lpBmpData[ab+3] = 0; 89 q = q+1; 90 } 91 if(494 < (s[k]/4*1000000*329.5+0.5)) ok = q*100/325546; 92 if(494 >= (s[k]/4*1000000*329.5+0.5)) ok = q*100/p/*(M_PI* (s[k]/4*1000000*329.5+0.5)*(s[k]/4*1000000*329.5+0.5)/2)*/; 93 } 94 else{ 95 if((b-329.5)*(b-329.5)+(a-494)*(a-494) > (s[k]/4*1000000*329.5+0.5)*(s[k]/4*1000000*329.5+0.5)){ 96 g_img.lpBmpData[ab] = 0; 97 g_img.lpBmpData[ab+1] = 0; 98 g_img.lpBmpData[ab+2] = 0; 99 g_img.lpBmpData[ab+3] = 0; 100 } 101 } 102 } 103 hBmp = CreateDIBitmap(hdc, &(g_img.bmi.bmiHeader), CBM_INIT, g_img.lpBmpData,&(g_img.bmi), DIB_RGB_COLORS); 104 free(g_img.lpBmpData); 105 SelectObject(hdc_mem, hBmp); 106 SetStretchBltMode(hdc, COLORONCOLOR); 107 StretchBlt(hdc, 0, 0, 659/*674*/, 494/*532*/, hdc_mem, 0, 0, 659/*674*/, 494/*532*/, SRCCOPY); 108 DeleteDC( hdc ); 109 DeleteDC( hdc_mem ); 110 DeleteObject( hBmp ); 111 EndPaint(hWnd_bitmap, &ps); 112 ReleaseDC( hWnd_bitmap, hdc ); 113 break; 114 } 115 } 116}

ということだと思われます。

投稿2017/12/09 16:13

yumetodo

総合スコア5850

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

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

TRON1216.

2017/12/10 09:44

回答ありがとうございます。それだとビルド失敗し、「引数 5 を 'BITMAPINFOHEADER *' から 'const BITMAPINFO *' へ変換できません。」とでてきます。なにかアドバイスあればよろしくお願いいたします。
yumetodo

2017/12/10 09:53

IMG構造体は書き換えていますか?書き換えていればそんなエラーにならないはず。
TRON1216.

2017/12/10 09:57

書き換えていないです。見落としていました。もう一度書き直してやってみます。ありがとうございます!
TRON1216.

2017/12/10 10:02

すいません、bmiHeaderを入れるとtagBITMAPINFOHEDERにありませんとなるのですが、これはどこで定義するのでしょうか?
TRON1216.

2017/12/10 10:04

あ、BITMAPINFOですね、すいません早とちりで汗やり直します。
TRON1216.

2017/12/10 10:12

ビルドできましたが実行すると状況は変わりませんでした、、、
yumetodo

2017/12/10 10:22

確保しているメモリーのアドレスを表示するようにしてエラーメッセージのアドレスを比較して原因を追求してくださいとしか・・・
guest

0

ざっとコードを見た限りなので見落としがあるかもしれませんが、

c++

1 hBmp = CreateDIBitmap(hdc, &(g_img.bmp_ih), CBM_INIT, g_img.lpBmpData, (BITMAPINFO *)(&(g_img.bmp_ih)), DIB_RGB_COLORS); 2

この部分、BITMAPINFOHEADERをBITMAPINFOにキャストして使っていますね。BITMAPINFO構造体は

C++

1typedef struct tagBITMAPINFO { 2 BITMAPINFOHEADER bmiHeader; 3 RGBQUAD bmiColors[1]; 4} BITMAPINFO;

なので、上記のキャストではRGBQUADの部分を関係ないメモリの内容で埋めてしまっているのではないかと思います。ここを直せばよいのではないかと思います。

投稿2017/12/07 01:08

KoichiSugiyama

総合スコア3041

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

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

TRON1216.

2017/12/07 08:32

回答ありがとうございます。CreateDIBitmapの第5引数を変えればよいということでしょうか、、、?もしそうだとすると、具体的に何を入れるとよいのでしょうか?理解不足で申し訳ありません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問