前提・実現したいこと
CPU時間を計測するプログラムを作成しています。
普通にコンパイルして実行するとうまくいくのですが。
課題で指示された最適化オプション-O2をつけてコンパイルし、実行すると
Segmentation fault (コアダンプ)と表示されます。
どこに間違いが起きているのか分からず質問させてもらいました。
C言語でプログラムを作成しています。
以下のプログラムをリンクしてコンパイルしました。
#include <stdio.h>
#include <time.h>
#include "iata_db.h"
int main(void)
{
db_t db;
char key[KEY_LEN+1];
char *data;
int i;
db_init(&db);
db_hash_load(&db);
/* 空港コードを入力するとデータを出力; EOFまで繰り返し実行 */
for (;;) {
fprintf(stderr, "key = ");
if (scanf(KEY_FMT, key)==EOF) { break; }
clock_t clk_start, clk_end;
clk_start = clock();
for(i=0; i<=100000; i++)
{
data = db_hash_search(&db, key);
}
clk_end = clock();
fprintf(stderr, "cpu = %11.6f [sec]\n", (double) (clk_end-clk_start)/CLOCKS_PER_SEC);
if (data==NULL) { printf("NO RECORD\n"); }
else { printf("%s => %s\n", key, data); }
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "iata_db.h"
/* c が改行記号かどうか判定するマクロ */
#define IS_EOL(c) ((c)=='\n' || (c)=='\r')
/* iata_db.c の内部だけで使用する関数 */
static void extract_data(char line[], char key[], char data[]);
static void record_set(record_t *r, char key[], char data[]);
void db_init(db_t db)
/ db_t 型変数の初期化 */
{
int i;
db->n = 0;
for (i=0; i<MAX_RECORDS; i++) {
strcpy(db->record[i].key, "");
db->record[i].data = NULL;
}
}
void db_load(db_t db)
/ db_t 型変数にファイル IATA_F からデータを読み込む */
{
FILE *fp;
char line[KEY_LEN+1+DATA_LEN+1];
char key[KEY_LEN+1];
char data[DATA_LEN+1];
/* ファイルのオープン */
if ((fp=fopen(IATA_F, "r"))==NULL) {
fprintf(stderr, "ファイル (%s) が開けません\n", IATA_F);
exit(1);
}
/* データの読み込み /
while (fgets(line, DATA_LEN, fp) != NULL) {
/ 入力データ数が収容可能最大レコード数を超えたらエラー /
if (MAX_RECORDS<=db->n) {
fprintf(stderr, "MAX_RECORDS(%d) <= n(%d)\n", MAX_RECORDS, db->n);
exit(1);
}
/ line から key と data を切り出す /
extract_data(line, key, data);
/ db->n 番目のレコードに key と data を格納し, db->n を1増やす */
record_set(&db->record[db->n], key, data);
db->n++;
}
fclose(fp);
}
static void record_set(record_t r, char key[], char data[])
/ r の指すレコードに key と data を書き込む (data は動的割当て) /
{
assert(r!=NULL);
assert(key!=NULL);
assert(data!=NULL);
/ key /
assert(strlen(key)<=KEY_LEN);
strcpy(r->key, key);
/ data /
assert(strlen(data)<=DATA_LEN);
r->data = (char) malloc(sizeof(char)*(strlen(data)+1));
strcpy(r->data, data);
}
static void extract_data(char line[], char key[], char data[])
/* line から key と data を抽出する*/
{
assert(line!=NULL);
assert(key!=NULL);
assert(data!=NULL);
int k;
/* ファイルの1行が長過ぎて line に収容できていないことがないかのチェック /
/ line の末尾が改行でない → 1行が長過ぎるのでエラー */
if (! IS_EOL( line[strlen(line)-1] ) ) {
fprintf(stderr, "line length exceeded line size\n");
exit(1);
}
/* 先頭の KEY_LEN 文字が key */
int p_key = 0;
for (k=0; k<KEY_LEN; k++) {
key[k] = line[p_key+k];
}
key[k] = '\0';
/* KEY_LEN+1 文字目以降改行記号までが data */
int p_data = KEY_LEN+1;
for (k=0; k<DATA_LEN; k++) {
if (IS_EOL(line[p_data+k])) { break; }
data[k] = line[p_data+k];
}
data[k] = '\0';
}
void db_dump(db_t db)
/ db_t 型変数の全データを出力する */
{
int i;
for(i=0; i<MAX_RECORDS; i++)
{
printf("[ %d]", i);
if(db->record[i].data != NULL)
{
printf("%s %s", db->record[i].key, db->record[i].data);
}
printf("\n");
}
}
char *db_linear_search(db_t *db, char key[])
{
int i;
for(i=0; i<MAX_RECORDS; i++)
{
if(strcmp(key,db->record[i].key)==0)
{
return db->record[i].data;
break;
}
}
return NULL;
}
char *db_binary_search(db_t *db, char key[KEY_LEN+1])
{
int low=0;
int high=db->n-1;
int mid;
for(;;)
{
mid=(high+low)/2;
if(strcmp(key,db->record[mid].key)==0)
{
return db->record[mid].data;
}
else if(strcmp(key,db->record[mid].key)> 0)
{
low = mid + 1;
}
else if(strcmp(key,db->record[mid].key)< 0)
{
high = mid - 1;
}
if(high < low){break;}
}
return NULL;
}
int db_hash_f(char key[])
{
int i;
int v = 0;
for (i=0; key[i]!='\0'; i++) {
v = (v<<5) + (key[i]-'A');
}
return v % MAX_RECORDS;
}
void db_hash_load(db_t *db)
{
FILE *fp;
char line[KEY_LEN+1+DATA_LEN+1];
char key[KEY_LEN+1];
char data[DATA_LEN+1];
int h;
int m = MAX_RECORDS;
/* ファイルのオープン */
if ((fp=fopen(IATA_F, "r"))==NULL) {
fprintf(stderr, "ファイル (%s) が開けません\n", IATA_F);
exit(1);
}
/* データの読み込み /
while (fgets(line, DATA_LEN, fp) != NULL) {
/ 入力データ数が収容可能最大レコード数を超えたらエラー /
if (MAX_RECORDS<=db->n) {
fprintf(stderr, "MAX_RECORDS(%d) <= n(%d)\n", MAX_RECORDS, db->n);
exit(1);
}
/ line から key と data を切り出す /
extract_data(line, key, data);
/ db->n 番目のレコードに key と data を格納し, db->n を1増やす */
h = db_hash_f(key);
while(strcmp(db->record[h].key, "")!= 0)
{
h++;
if(h == m){h = h - m;}
}
record_set(&db->record[h], key, data);
}
fclose(fp);
}
char *db_hash_search(db_t *db, char key[KEY_LEN+1])
{
int h;
int i;
int m = MAX_RECORDS;
for(i=0; i<= MAX_RECORDS; i++)
{
if(strcmp(db->record[h].key, key)==0)
{
return db->record[h].data;
break;
}
h++;
if(h == m){h = h - m;}
}
return NULL;
}