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

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

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

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

for

for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

Q&A

解決済

4回答

2735閲覧

C言語のfor文で動作を停止してしまう

tkphone343

総合スコア6

C

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

for

for文は、様々なプログラミング言語で使われている制御構造です。for文に定義している条件から外れるまで、for文内の命令文を繰り返し実行します。

0グッド

0クリップ

投稿2021/08/26 14:04

編集2021/08/27 12:26

前提・実現したいこと

C言語で、画像を読み込みハフ変換を行うプログラムを作成途中です。

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

for文の途中で動作を停止してしまいます。

該当のソースコード

エラーが出ている箇所までのソースコードです #include<stdio.h> #include <stdlib.h> #include"pgmlib.h" void hough( int n ); int main(void) { load_image( 0, "" ); hough( 0 ); return 0; } void hough( int n ) { int j,k,l,m,o,p,x,y,AA,BB,sum,i,h,AAm,aa,bb,h2,aam; int maxh = 0; int minBB = 18900; int maxBB = 0; int maxh2 = 0; int minbb = 6552; int maxbb = 0; double A,B,a,b; int *arr; int *arr2; l = 18900 /*横の座標*/, m = 200; /*縦の座標*/ arr = (int*)malloc(sizeof(int) * l * m); for (j=0; j<l; j++){ for (k=0; k<m; k++){ arr[j * m + k] = 0; } } for (y=0; y<height[n]; y++){ for (x=0; x<width[n]; x++){ if (image[n][x][y] <= 120){ for (A=-1.0; A<=1.0; A+=0.05){ B = -y * A + x; AA = (A + 1) * 100; BB = (B + 63) * 100; arr[BB * m + AA]++; } } } } for (AA=0; AA<=200; AA++){ sum = 0; i = 0; printf("test1-1 \n"); for (BB=0; BB<=18900; BB++){ if (arr[BB * m + AA] >= 1){ sum += arr[BB * m + AA] * arr[BB * m + AA]; i++; } } printf("test1-2 \n"); h = sum / i; printf("test1-3 \n"); if (h > maxh){ printf("test1-4 \n"); maxh = h; AAm = AA; } printf("test1-5 \n"); }

試したこと

2回目のtest1-2まで表示されるのですが、test1-3が表示されずに動作を停止してしまいます。

修正したソースコード

#include<stdio.h> #include <stdlib.h> #include"pgmlib.h" void hough(int n); int main(void) { load_image(0, ""); hough(0); return 0; } void hough(int n) { int j, k, l, m, o, p, x, y, sum, i, indexAm, h, Am, aa, bb, h2, aam, indexA, indexB; int maxh = 0; int minB = 18900; int maxB = 0; int maxh2 = 0; int minbb = 6552; int maxbb = 0; double A, a, b; int arr[40][2583] = {0}; //int arr2[6552][400] = {0}; /* arr = (int*)malloc(sizeof(int) * 3780200); for (j = 0; j < l; j++) { for (k = 0; k < m; k++) { arr[j * m + k] = 0; } } */ for (y = 0; y < height[n]; y++) { for (x = 0; x < width[n]; x++) { if (image[n][x][y] <= 120) { for (A = -1.0; A <= 1.0; A += 0.05) { indexA = A * 20 + 20; indexB = -y * indexA + x + 2520; arr[indexA][indexB]++; } } } } for (indexA = 0; indexA <= 40; indexA++) { sum = 0; i = 0; for (indexB = 0; indexB <= 2583; indexB++) { if (arr[indexA][indexB] >= 1) { sum += arr[indexA][indexB] * arr[indexA][indexB]; i++; } } h = sum / i; if (h > maxh) { maxh = h; indexAm = indexA; } } for (indexB = 0; indexB <= 2583; indexB++) { if (arr[indexAm][indexB] >= 1) { if (indexB <= minB) { minB = indexB; } if (indexB >= maxB) { maxB = indexB; } } }

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

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

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

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

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

Ftps

2021/08/26 14:09

エラーも一緒に記述してください。お役に立てるかもしれません。
tkphone343

2021/08/26 14:26

ご返信ありがとうございます。 コマンドプロンプトで実行しているのですが、「(ファイル名)は動作を停止しました」と表示されます。
guest

回答4

0

ベストアンサー

ライブラリとサンプルデータを見つけたので、試しに VC++ でビルドしてみました。
他の方が回答されているように arr のサイズを超過してアクセスしている為にアクセス違反となっていました。

■ 階調画像(pgm形式)用ライブラリ pgmlib.h
http://www.is.kochi-u.ac.jp/~honda/lecture/image19/en1/pgmlib.h

■ サンプル画像データ
http://icb-lab.naist.jp/members/yoshi/ouec_lecture/image_recognition/image_files/lena.pgm

■ アクセス違反箇所
アクセス違反箇所

■ アクセス違反発生時の変数の状態
アクセス違反発生時の変数の状態

arr の要素数が 18900 * 200 = 3780000
arr[BB * m + AA] ⇒ arr[21500 * 200 + 0] ⇒ arr[4300000] … サイズを超過してアクセスしている

投稿2021/08/26 17:49

cx20

総合スコア4646

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

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

tkphone343

2021/08/27 03:16

わかりやすい回答ありがとうございます。 変数や式が多くてミスに気が付きませんでした。 修正してみます。
tkphone343

2021/08/27 04:51

すみません、説明不足だったのですが実際は64×64の画像を使用する予定なので、xとyは最大でも63になると考えarrのサイズを設定していました。 それでもサイズ設定が間違っているようだったので、BB * m + AA の最大値が3780200になると考え arr = (int*)malloc(sizeof(int) * 3780200) に変更したのですが改善されませんでした。 visual studio等を使用すればcx20さんのようにその時々の値を見なおしながら修正できるのでしょうか。
tkphone343

2021/08/27 07:18

ありがとうございます。 参考にして自分でデバッグできるようにしておきます。
guest

0

質問内容への直接的な回答とはなりませんが,全体的な見直しに役立つかもしれないので書いてみます.

ハフ変換とのことなので,arr は投票空間であろうと推測します.
また,コードの雰囲気から
y = a*x + b か,それに準じた形の直線の式のパラメタ{a,b}をそのまま投票空間の軸に考えているものと思えます.

for (A=-1.0; A<=1.0; A+=0.05)

という記述から,これが考慮するaの範囲と刻みであると見えます.
そうであれば,ここからパラメータaの方向に関する投票空間の広さを定めることができるでしょう.
すなわちAが何パターンの値を取り得るか,という話です.
これなら100も要らないでしょう.

次に,切片Bについてですが,
Aの値域が限定されているのですから,扱う画像のサイズからBの値域もまた定まります.
あとはB方向の分解能次第で,投票空間のB方向の広さが定まります.
ではB方向の分解能はどれほど必要なのか? と考えると,
画像上の線をハフ変換で検出しようというときに,Bの分解能がそれほど必要とは思えません.
Bの単位は[pixel]であり,例えば0.1とか0.5ずれたところでそれほど問題ないかもしれません.
(どちらかと言えば,分解能が相応に欲しいパラメータはAの側でしょう)

…というわけで,投票空間arrの広さを考えた際に

18900

だとかいう巨大なサイズが必要になるとは到底思えません.
(何か根本的な部分で間違いがあるのではないかと.)


余談ですが,大抵の場合,直線検出ではパラメータを(r,θ)とする方式を取ります(※).
任意の直線を相手にする場合,パラメータ(A,B)では値域が制限できませんが,(r,θ)なら値域が自明であるため投票空間のサイズを決める方法が自明ですし,「A と 線の方向 との間の関係」のことを考えると,直接的に角度θを用いた方がやはり話が簡単になるからです.

(※) rは原点から直線に下した垂線の長さであり,θはその垂線の向き(角度)

投稿2021/08/27 05:52

編集2021/08/27 06:01
fana

総合スコア11954

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

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

tkphone343

2021/08/27 07:17

ご回答ありがとうございます。推測されているところはおおむね正しいです。 今回、参考にしている資料にそって作成しておりそのために y = a*x + b を採用しております。 サイズが巨大とのことですが、実は最初は普通の配列で投票平面を表現しようとしていたのですが、添字に少数や負の数は使えないと考え、少数を防ぐために100倍したりしており最大の値が大きくなってしまっています。 この点は自分ももう少し上手くできないかと引っかかっているのですが、なにかよい方法があればご教授願いたいです。
tkphone343

2021/08/27 07:29

補足ですが配列が大きすぎるためにポインタを使ってはどうかということになりました。
fana

2021/08/27 07:32

> for (A=-1.0; A<=1.0; A+=0.05) ならば,投票空間のパラメータAの方向のサイズは41個で済みますね. (Aの取り得る値のパターンが41種類しかないので) つまり, 傾きパラメータA の値 → 投票空間とする配列の(この方向の)index という変換は, A=-1.0 → index=0 A=1.0 → index=40 になるような計算式 index = f(A) により行えばよいわけで,fは単なる線形な関数でしょうから難しいことは特にないハズ.
fana

2021/08/27 07:36

> 配列が大きすぎるためにポインタを使ってはどうか これが 何の話で 何がどう解決するのか 私には意味がわかりませんが. --- > y = a*x + b を採用 ならば, > B = -y * A + x; ってのは間違ってないですか?
fana

2021/08/27 07:41

各パラメータ{A,B}に関して,取り扱う値域(最小,最大)と,刻み幅 を決める ↓ すると,投票空間の必要なサイズが定まる. それだけの話では.
fana

2021/08/27 08:05 編集

Aの値でサンプリングしているのだから,Aの値を100倍とかする意味はありません. Bの値を100倍して用いるというのは,切片を 1/100 [pixel] 刻みで扱おうという話に相当しますが, 回答内で述べたように,切片側をそれだけの細かさで扱うことにどれだけの意味があるのか? を考えた方がよいでしょう. (また,投票空間の分解能を上げすぎれば投票がばらけてしまうことに繋がるのだから,投票結果に基づいて検出結果を得ようとする後処理で苦労することにもなり得る) まずは低分解能で動くものを作ってみて,その結果を見て「これじゃ分解能が足りねぇなぁ」となったら分解能を上げてみる,みたいな手順でやってみたら?
tkphone343

2021/08/27 08:29

多くのご指摘ありがとうございます。非常に助かります。 y = a*x + b の部分はその形の式を使うという意味で実際の式は B = -y * A + x で大丈夫です。言葉が足りなくて申し訳ありません。 刻み幅が少ないのにサイズが大きいのは小数点を避けるために単に100倍していますが、おっしゃる通り無駄な要素が大量にできてしまう状況なので、index = f(A) で置き換える考え方を参考に修正してみます。 ポインタについてはあまり理解していない状況で、サイズを小さくできれば配列でエラーも出なくなると思うので、普通の配列を使ったやり方に戻してみます。
tkphone343

2021/08/27 12:15

とりあえず書き換えてみたのですが、コマンドプロンプトでは一応エラーは無くなりましたがvisual studioではエラーコードc6262のスタックサイズが大きすぎるというようなエラーが出ます。 #include<stdio.h> #include <stdlib.h> #include"pgmlib.h" void hough(int n); int main(void) { load_image(0, ""); hough(0); return 0; } void hough(int n) { int j, k, l, m, o, p, x, y, sum, i, indexAm, h, Am, aa, bb, h2, aam, indexA, indexB; int maxh = 0; int minB = 18900; int maxB = 0; int maxh2 = 0; int minbb = 6552; int maxbb = 0; double A, a, b; int arr[40][2583] = {0}; //int arr2[6552][400] = {0}; /* arr = (int*)malloc(sizeof(int) * 3780200); for (j = 0; j < l; j++) { for (k = 0; k < m; k++) { arr[j * m + k] = 0; } } */ for (y = 0; y < height[n]; y++) { for (x = 0; x < width[n]; x++) { if (image[n][x][y] <= 120) { for (A = -1.0; A <= 1.0; A += 0.05) { indexA = A * 20 + 20; indexB = -y * indexA + x + 2520; arr[indexA][indexB]++; } } } } for (indexA = 0; indexA <= 40; indexA++) { sum = 0; i = 0; for (indexB = 0; indexB <= 2583; indexB++) { if (arr[indexA][indexB] >= 1) { sum += arr[indexA][indexB] * arr[indexA][indexB]; i++; } } h = sum / i; if (h > maxh) { maxh = h; indexAm = indexA; } } このように書き換えました。 それとヘッダーファイルのほうでもエラーが出ているようです。中身はいじっていないので正しく動作すると思うのですがそういう仕様なのでしょうか。
rubato6809

2021/08/27 12:26

> スタックサイズが大きすぎる static int arr[40][2583] = {0}; としてみたら?
tkphone343

2021/08/27 12:28

コードが見にくかったので、質問文のほうにも載せました。
tkphone343

2021/08/27 13:01

rubato6809さん static を使うことでスタックのエラーはなくなりました。 ありがとうございます。
tkphone343

2021/08/28 03:02

エラーは全てヘッダーファイルで起きていてc4996のエラーコードなのですが、これはどうしようもないのでしょうか。依然としてvisual studioでは止まってしまいます。
rubato6809

2021/08/28 23:43

「for文で動作を停止してしまう」件は配列の範囲外アクセス(バッファオーバーラン)で決着済みだと思います。この件を解決済みにしましょう。ベストアンサーを決めてください。 > エラーは全てヘッダーファイルで起きていて そのエラーはコンパイルエラーだと思いますので「for文で動作を停止…」と別の問題です。問題点を切り分けて問いを発散させない事。ご自分で解決できないなら新たな質問を立てたら良いと思います。
guest

0

printf("test1-1 \n");

これ以降のfor文でおもいっきしアクセス違反してますね

投稿2021/08/26 14:13

y_waiwai

総合スコア88024

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

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

tkphone343

2021/08/26 14:29

ご回答ありがとうございます。 アクセス違反とは sum+= の部分でしょうか。
y_waiwai

2021/08/26 14:33

その行でもやらかしてますね
majiponi

2021/08/26 14:38

Next Conan's Hint: 境界条件 arr[BB * m + AA]++;は大丈夫?
tkphone343

2021/08/26 14:40

すみません、見直してみたのですがアクセス違反がよくわかっていません。 初めてポインタを使っているのですが、ポインタのあたりで間違えているのでしょうか。
tkphone343

2021/08/26 14:42

majiponiさん 自分では配列と同じように扱えるのかと考えていたのですが、それが間違いでしょうか。
jimbe

2021/08/26 17:28

扱い方は間違ってはおりません。問題は、arrの大きさに対する添字の値です。 arr は配列幾つ分のメモリを確保していますか。 それに対してあちこちにある添字の計算式は、それぞれちゃんとその範囲内に入っているでしょうか。
tkphone343

2021/08/27 05:02

jimbeeさん ありがとうございます。添字に問題がありそうなので、見直してみます。
guest

0

何処でインデックスが範囲外になっているかを確認する方法としまして、プログラム内でチェックを仕掛ける方法もあります。
以下は、DEBUG の定義の有無によって、配列へのアクセスを、配列の添え字をチェックする関数の呼び出しに変換します。
デバッグが終われば #define DEBUG をコメントアウトすることで直接配列アクセスになります。

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <stdarg.h> 4 5#define DEBUG 6 7#ifdef DEBUG 8int *getArr(int *arr, int i, char *fmt, ...) { 9 if(i < 0 || i >= 18900*200) { 10 char buf[1024]; 11 va_list ap; 12 va_start(ap, fmt); 13 vsprintf(buf, fmt, ap); 14 va_end(ap); 15 printf("'%s' index error: i=%d\n",buf,i); 16 exit(1); 17 } 18 return &arr[i]; 19} 20#define ARR(i,s) (*getArr(arr,i,s)) 21#define ARR1(i,s,v1) (*getArr(arr,i,s,v1)) 22#define ARR2(i,s,v1,v2) (*getArr(arr,i,s,v1,v2)) 23#define ARR3(i,s,v1,v2,v3) (*getArr(arr,i,s,v1,v2,v3)) 24#else 25#define ARR(i,s) arr[i] 26#define ARR1(i,s,v1) arr[i] 27#define ARR2(i,s,v1,v2) arr[i] 28#define ARR3(i,s,v1,v2,v3) arr[i] 29#endif 30 31int main(void) { 32 int *arr = (int*)malloc(sizeof(int) * 18900 * 200); 33 34 int BB = 18900; 35 int m = 200; 36 int AA = 0; 37 38 ARR3(BB*m+AA, "testA BB=%d,m=%d,AA=%d",BB,m,AA) = 123; 39 40 int i=BB*m+AA; 41 printf("arr[%d]=%d\n", i, ARR(i,"testB")); 42 printf("end.\n"); 43} 44

配列内のインデックス(int AA=-1)とした場合

plain

1arr[3779999]=123 2end.

配列外のインデックス(int AA=0)とした場合

plain

1'testA BB=18900,m=200,AA=0' index error: i=3780000

投稿2021/08/27 09:21

編集2021/08/27 10:50
jimbe

総合スコア13168

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問