PGM画像を読み込むプログラム(セグメントエラー発生)※追加質問あり

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
tasuke
記事: 6
登録日時: 7年前

PGM画像を読み込むプログラム(セグメントエラー発生)※追加質問あり

#1

投稿記事 by tasuke » 7年前

現在画像処理の勉強をしているものです。
PGM画像をファイルポインタから読み込んで、構造体変数に格納するプログラムを作成しました。
しかし、セグメントエラーが起きてしまいます。

簡単にプログラムの流れを説明します。
・main関数
画像読み込み関数load_imageを呼び出しています。
この関数の引数には読み込みたい画像のファイル名の文字列になります。
文字列を入れない場合はload_image関数で文字列の入力を要求するようになっております。

・load_image関数
まず受け取った引数に文字列が入っているかを調べ、なければ入力を要求します。
fopenでファイルを開きます。
続いてヘッダの読み込みをします。
今回取り扱う画像はPGM形式のためヘッダはコメント文を除いて3行になります。
コメント文を読み飛ばしながら
画像の形式、画素数、最大階調の情報を読み出します。
最後に各座標の画素値を読み出して終了します。

原因がわからず困っております。どうかご教授のほどよろしくお願いいたします。

コード:

#include <stdio.h>
#include<stdlib.h>
#include<string.h>

/* 定数宣言 */
#define MAX_IMAGESIZE       1280 /* 想定する縦・横の最大画素数 */
#define MAX_BRIGHTNESS       255 /* 想定する最大階調値 */
#define GRAYLEVEL            256 /* 想定する階調数(=最大階調値+1) */
#define MAX_FILENAME         256 /* 想定するファイル名の最大長 */
#define MAX_BUFFERSIZE       256 /* 利用するバッファ最大長 */
#define MAX_NUM_OF_IMAGES      5 /* 利用する画像の枚数 */

typedef struct PGM{
	char format[MAX_BUFFERSIZE];
	int width;
	int height;
	int brightness;
	int image[MAX_IMAGESIZE][MAX_IMAGESIZE];
}pgm;

/* 関数のプロトタイプ宣言 */
/* 階調画像を入力する関数 */
struct PGM load_image(char name[] );
/* name[]:ファイル名(""のときはキーボード入力)*/
/* 階調画像を出力する関数*/
void save_image( int n, char name[] );
/*name[]:ファイル名(""のときはキーボード入力)*/


int main(void){

	pgm im;
	im = load_image("");

	return 0;
}

struct PGM load_image(char name[] ){

	FILE *fp;
	char file_name[MAX_FILENAME];
	char buff[MAX_BUFFERSIZE];
	int header = 3;
	pgm img;
	int x,y;


	if(name[0] != '\0'){
		strcpy(file_name, name);
	}else{
		printf("入力ファイル名(*.pgm):");
		scanf("%s", file_name);
	}
	if((fp = fopen(file_name,"r")) == NULL){
		printf("ファイルを開くことができませんでした\n");
		exit(1);
	}

	while(header){
		fgets(buff, MAX_BUFFERSIZE, fp);
		if(buff[0] != '#'){
			switch(header){
			case 3:
				if(buff[0] != 'P' || buff[1] != '2'){
					printf("P2形式の画像ではありません\n");
					exit(1);
				}
				strcpy(img.format, buff);
				break;

			case 2:
				sscanf(buff,"%d %d", &img.width, &img.height);
				break;

			case 1:
				sscanf(buff, "%d", &img.brightness);
				break;
			}
                 header--;
		}
	}

	for(y = 0; y < img.width; y++){
		for(x = 0; x < img.height; x++){
			img.image[x][y] = (int)fgetc(fp);
		}
	}

	return img;

	fclose(fp);
}

最後に編集したユーザー tasuke on 2016年7月10日(日) 21:12 [ 編集 1 回目 ]

box
記事: 2002
登録日時: 13年前

Re: PGM画像を読み込むプログラム(セグメントエラー発生)

#2

投稿記事 by box » 7年前

画像ファイルというからには、中身はバイナリーだと思います。それを
tasuke さんが書きました:

コード:

				sscanf(buff,"%d %d", &img.width, &img.height);
				sscanf(buff, "%d", &img.brightness);
こんな風にテキストファイルっぽく扱っていいのでしょうか。本当にテキストファイルならばそれでいいのかもしれませんが…。
上に挙げた変数の値はどうなっていますか?sscanfの直後にprintfを入れて確認してみてください。
tasuke さんが書きました:

コード:

	return img;

	fclose(fp);
return文の後ろに実行文が来るのはよろしくないと思います。コンパイル時に警告が出ませんでしたか?
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: PGM画像を読み込むプログラム(セグメントエラー発生)

#3

投稿記事 by みけCAT » 7年前

tasuke さんが書きました:しかし、セグメントエラーが起きてしまいます。
具体的にどこでエラーが発生しますか?
大きなデータを自動変数で確保しているので、スタックオーバーフローの疑いがあります。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

tasuke
記事: 6
登録日時: 7年前

Re: PGM画像を読み込むプログラム(セグメントエラー発生)

#4

投稿記事 by tasuke » 7年前

>>box 様、回答ありがとうございます。

ご指摘いただいた2点についてお答えします。
・画像の取り扱いについて
今回取り扱う画像はP2形式のPGM画像であるため、ascii形式でデータを記録します。 (このことを伝え忘れておりました、すみません...)
P2形式のPGM画像をテキストエディタで開くと以下のような構成になっております。

----------------------------------------------------------------------------------------
P2
512 512
255
<(0,0)の画素値> <(1,0)の画素値> <(1,0)の画素値> ・・・
                    ・
                    ・
                    ・

----------------------------------------------------------------------------------------

よって今回はテキストファイルとして扱うことができると思われます。
printfでの確認を実行しようとしましたが、セグメントエラーでやはり実行できませんでした。

・fcloseの位置について
こちらは訂正させていただきました。
しかし、セグメントエラーはなくなりませんでした。

tasuke
記事: 6
登録日時: 7年前

Re: PGM画像を読み込むプログラム(セグメントエラー発生)

#5

投稿記事 by tasuke » 7年前

みけCAT 様、回答ありがとうございます。

pgm構造体を宣言することでセグメントエラーが発生しているようです。
構造体宣言部を消して実行するとセグメントエラーはなくなりました。
しかし、この構造体のどこに問題があるのか自分ではよくわかりません。

スタックオーバーフローということはこの構造体変数のデータが大きすぎるということでしょうか?

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: PGM画像を読み込むプログラム(セグメントエラー発生)

#6

投稿記事 by みけCAT » 7年前

tasuke さんが書きました:スタックオーバーフローということはこの構造体変数のデータが大きすぎるということでしょうか?
スタックに置くには大きすぎるということですね。
malloc()関数などを用いて領域を確保するといいでしょう。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

tasuke
記事: 6
登録日時: 7年前

Re: PGM画像を読み込むプログラム(セグメントエラー発生)

#7

投稿記事 by tasuke » 7年前

>>みけCAT 様、回答ありがとうございます。
早速試してみます、ありがとうございました!

tasuke
記事: 6
登録日時: 7年前

Re: PGM画像を読み込むプログラム(セグメントエラー発生)

#8

投稿記事 by tasuke » 7年前

追加の質問をさせてください。
構造体をメモリの動的確保をしてから宣言することで先ほどのセグメントエラーが消えました。
しかし、今度はファイル名入力後に再びセグメントエラーが発生しました。
エラーは26~48行目のヘッダ読み飛ばし処理の中で起きているようです。(この処理をコメントアウトするとセグメントエラーは消えました。)
この処理の中ではすでに宣言済みの変数しか使用していないため
先ほどのオーバーフローと同じ問題ではないと考えていますが、自分ではよくわかりません。
何度も質問して申し訳ありませんが、よろしくお願いいたします。
以下に今回使用したPGM画像のヘッダ部分を載せます。

--------------------------------------------------------------------
P2
# Created by IrfanView
512 512
255
162 162 162 161 162 157 163 161 165 161 ・・・

--------------------------------------------------------------------

コード:

struct PGM *load_image(char name[] ){

	FILE *fp;
	char file_name[MAX_FILENAME];
	char buff[MAX_BUFFERSIZE];
	int header = 3;
	pgm *img;
	int x,y;

	img = malloc(256 + sizeof(int)*3 + 256*256*sizeof(int));
	if(img == NULL)
		printf("記憶域の確保に失敗しました。\n");


	if(name[0] != '\0'){
		strcpy(file_name, name);
	}else{
		printf("入力ファイル名(*.pgm):");
		scanf("%s", file_name);
	}
	if((fp = fopen(file_name,"r")) == NULL){
		printf("ファイルを開くことができませんでした\n");
		exit(1);
	}

	while(header){
		fgets(buff, MAX_BUFFERSIZE, fp);
		if(buff[0] != '#'){
			switch(header){
			case 3:
				if(buff[0] != 'P' || buff[1] != '2'){
					printf("P2形式の画像ではありません\n");
					exit(1);
				}
				strcpy(img->format, buff);
				break;

			case 2:
				sscanf(buff,"%d %d", &img->width, &img->height);
				break;

			case 1:
				sscanf(buff, "%d", &img->brightness);
				break;
			}
			header--;
		}
	}

	for(y = 0; y < img->width; y++){
		for(x = 0; x < img->height; x++){
			img->image[x][y] = (int)fgetc(fp);
		}
	}

	free(img);
	fclose(fp);
	return img;

}

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: PGM画像を読み込むプログラム(セグメントエラー発生)※追加質問あり

#9

投稿記事 by みけCAT » 7年前

このセグメントエラーの問題は後で考えるとして、freeした後のゴミアドレスを返しているのはなぜですか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: PGM画像を読み込むプログラム(セグメントエラー発生)

#10

投稿記事 by みけCAT » 7年前

tasuke さんが書きました:

コード:

	img = malloc(256 + sizeof(int)*3 + 256*256*sizeof(int));
こんな無駄に複雑で間違えたり環境依存になったりする可能性の高い式を書くのではなく、素直に構造体の大きさ(sizeof(pgm)またはsizeof(*img))だけ確保しましょう。
実際、imageは1280×1280のはずなのに、256×256しか確保していないので、明らかに確保したバッファが足りなくなるでしょう。
tasuke さんが書きました:エラーは26~48行目のヘッダ読み飛ばし処理の中で起きているようです。(この処理をコメントアウトするとセグメントエラーは消えました。)
セグメントエラーが消えたのは、malloc()関数で確保して初期化していない領域の不定の値を用い、未定義動作を起こした結果たまたまではないですよね?
きちんと別途必要なメンバを初期化してテストしましたよね?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

tasuke
記事: 6
登録日時: 7年前

Re: PGM画像を読み込むプログラム(セグメントエラー発生)※追加質問あり

#11

投稿記事 by tasuke » 7年前

みけCAT 様、回答ありがとうございます。

きちんとsizeof(pgm)としたところ問題なく動作しました。
申し訳ありませんでした。

閉鎖

“C言語何でも質問掲示板” へ戻る