掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.27700

fopenで例外発生
投稿者---Mr.Boo(2006/07/20 11:30:21)


環境 Borland C++ Compiler 5.5(無償版)
   BccDev 1.2.21
   Turbo Debugger
   Windows2000 SP4

研修用演題の解答例を作成しているのですが、下記プログラムを実行させると、
6人分のデータ(構造体データを1人分とした6人分のデータ)を入力すると、
fopenを呼んだところで、exception throwが発生してしまいます。
ファイル名入力とfopenをmallocの前に持ってくると、例外は発生せずに、
入力したファイルをopenすることが出来ます。

ファイル名は、コンソールからの入力ではなく、ソース上に直書きしても、例外が発生するため、buffが壊れているのではなさそうです。
(Wacthで変数をチェックしたのですが、buffの中身は問題ありませんでした)
どこ(誰)が、どのデータを破壊しているのが、分からず困っております。
どなたか、なにかヒントをいただけませんでしょうか?

すみません、全体を把握していただくために、貼付ソースが長くなってしまい、
見にくいとは思いますが、宜しくお願いいたします。

/*----------------------------------------
    include ファイル
----------------------------------------*/
#include        "stdio.h"
#include        "stdlib.h"
#include        "string.h"


/*----------------------------------------
    構造体宣言
----------------------------------------*/
typedef struct personaldata{
    short      studentNo;     // 生徒番号

    int   kokugo;            // 国語成績

    int   eigo;                        // 英語成績

    int   sugaku;            // 数学成績

    int   kagaku;            // 化学成績

    int   nihonshi;                    // 日本史成績

}PERSONALDATA;                // 各生徒成績情報


/*----------------------------------------
    定数宣言
----------------------------------------*/
#define  OK               1
#define  NG               -1

#define  MAX_DATA_NO      100 + 1      // 最大データ登録数 100件

#define  END_DATA   -1         // 入力終了生徒番号

#define  MAX_F_NAME         128            // 最大入力ファイル名


#define  FOPEN_ERROR      "ファイルオープンエラー[%s]\n"
#define  MEM_ALLOC_ERROR    "メモリ確保に失敗しました\n"


/*----------------------------------------
    データ入力処理
----------------------------------------*/
int dataInput()
{
    int  data;

    for(;;){
        scanf("%d", &data);
        if((data <= 100) && (data >= 0))
            return data;
        printf("正しい点数を入力してください");
    }
}

/*----------------------------------------
    新規入力処理
----------------------------------------*/
int inputData()
{
    int    data,len;
    char            buff[MAX_F_NAME];
    FILE            *fp;
    char            *mData;      // allocateメモリ

    PERSONALDATA    *pData;

    memset(buff,0,MAX_F_NAME);
    // 入力用ワークエリア確保

    mData = malloc(MAX_DATA_NO * sizeof(PERSONALDATA));
    pData = (PERSONALDATA *)mData;
    if(pData == NULL){
        printf(MEM_ALLOC_ERROR);
        return NG;
    }

    for( ; ; pData++){              // 成績データ入力

        printf("生徒番号:");
        scanf("%d", &(pData->studentNo));
        if(pData->studentNo== END_DATA){            // 入力終了:生徒番号 = -1

            break;
        }
        printf("国語:");
        pData->kokugo = dataInput();

        printf("英語:");
        pData->eigo = dataInput();

        printf("数学:");
        pData->sugaku = dataInput();

        printf("化学:");
        pData->kagaku = dataInput();

        printf("日本史:");
        pData->nihonshi = dataInput();
    }

    printf("保存しますか(0:NO, 1:YES)? ");
    scanf("%d", &data);
    if(data != 1)
        return OK;                // 保存せず終了


    fgets(buff, sizeof(buff), stdin);
    printf("ファイル名を入力してください:");
    fgets(buff, sizeof(buff), stdin);
    len = strlen(buff);
    buff[len-1] = '\0';
    if((fp = fopen(buff,"w"))==NULL){  //ここで例外発生
        printf(FOPEN_ERROR,buff);
        return NG;
    }
    pData = (PERSONALDATA *)mData;
    for(;;pData++){
        if(pData->studentNo == END_DATA){
            fprintf(fp, "%d,%d,%d,%d,%d,%d\n", pData->studentNo, 0, 0, 0, 0, 0);
            break;;
        }
        fprintf(fp, "%d,%d,%d,%d,%d,%d\n",
                pData->studentNo, pData->kokugo, pData->eigo,
                pData->sugaku, pData->kagaku, pData->nihonshi);
    }
    fclose(fp);
    free(mData);
    return OK;
}





この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:fopenで例外発生 27701 ruby 2006/07/20 11:50:05


No.27701

Re:fopenで例外発生
投稿者---ruby(2006/07/20 11:50:05)


1)main関数がありませんが、こちらで勝手に作ってよいでしょうか?
2)dataInput, inputData両関数のプロトタイプ宣言がありません。
3)標準ヘッダーファイルをインクルードする際、<>ではなくて""を
使っているのはなぜでしょうか?
4)inputData関数のforループから抜けるための条件が
生徒番号だけですが、大丈夫でしょうか?101件を超えるデータを
入力しようとすると、mData(pData)で確保した領域の範囲を
超えてしまうと思います。



この投稿にコメントする

削除パスワード

No.27702

Re:fopenで例外発生
投稿者---Mr.Boo(2006/07/20 12:01:18)


>1)main関数がありませんが、こちらで勝手に作ってよいでしょうか?
main関数はinputDataを呼んでいるだけなので、作っていただいても結構です。

>2)dataInput, inputData両関数のプロトタイプ宣言がありません。
こちらで作成中の正規のファイルには、プロトタイプ宣言文は記載しております。

>3)標準ヘッダーファイルをインクルードする際、<>ではなくて""を
>使っているのはなぜでしょうか?
以前、参考にしていたソースファイルが、""だったので、そのままで使っておりますが、特に支障をきたすことがなかったので、そのままで使っております。

>4)inputData関数のforループから抜けるための条件が
>生徒番号だけですが、大丈夫でしょうか?101件を超えるデータを
>入力しようとすると、mData(pData)で確保した領域の範囲を
>超えてしまうと思います。
課題の前提条件として、データ数は100件を超えることはない、としているため、データ入力の終了条件を生徒番号だけにしております。

以上、宜しくお願いいたします。



この投稿にコメントする

削除パスワード

No.27703

Re:fopenで例外発生
投稿者---kolona(2006/07/20 13:17:47)


マクロの問題です。
マクロ展開は単純な置換作業なので演算子の優先順位は考慮されません。
#define MAX_DATA_NO 100 + 1
で最大数を定義されていますが、
MAX_DATA_NO * sizeof(PERSONALDATA)
をそのままマクロ展開すると
100+1*24
になってしまい(型のサイズは処理系依存なので24は変化する)
大体124Byte程度しか確保されず、6個ほどでメモリを破壊します。
マクロで式を展開するときは必ず
#define MAX_DATA_NO (100 + 1)
のように括弧で優先順位を強制する必要があります。


この投稿にコメントする

削除パスワード

No.27705

Re:fopenで例外発生
投稿者---Mr.Boo(2006/07/20 13:39:27)


>マクロの問題です。
>マクロ展開は単純な置換作業なので演算子の優先順位は考慮されません。
>#define MAX_DATA_NO 100 + 1
>で最大数を定義されていますが、
>MAX_DATA_NO * sizeof(PERSONALDATA)
>をそのままマクロ展開すると
>100+1*24
>になってしまい(型のサイズは処理系依存なので24は変化する)
>大体124Byte程度しか確保されず、6個ほどでメモリを破壊します。
>マクロで式を展開するときは必ず
>#define MAX_DATA_NO (100 + 1)
>のように括弧で優先順位を強制する必要があります。

ruby様、kolona様、有難う御座いました。
解決いたしました。

言われてみれば、確かにマクロで展開するだけですから、私の記述では
ご指摘のような式になってしまいますね。
(このサイトの18章にも注意書きがありました)
今までのソースも見直さないと、ちょっと怖いことになっているかもしれない。

ところで、メモリ破壊が起きていたのは分かっておりTurbo Debuggerで
mallocされたエリアのメモリダンプを確認したかったのですが、アドレスの
指定の仕方が、分かりませんでした。
Turbo Debuggerの分かりやすい説明って、どこかにないのでしょうかね。
書籍で売っているのは、確認したのですが研修用のソフト確認のためだけなので
なんかもったいなくて。
(勉強のための投資はけちるなってか?)

どなたかご存じないでしょうか?




この投稿にコメントする

削除パスワード

No.27704

Re:fopenで例外発生
投稿者---acid(2006/07/20 13:36:14)


答えは先に言われてしまったので、実際の出力結果だけを…

MAX_DATA_NO = 101
sizeof(PERSONALDATA) = 24
MAX_DATA_NO * sizeof(PERSONALDATA) = 124

こーいう出力結果が出ました。defineはようは置き換えですからね。
ところで、個人的には生徒数分だけmallocすれば良いと思うんですけど、
演習だからそういうわけにはいかないのかな?


この投稿にコメントする

削除パスワード

No.27706

Re:fopenで例外発生
投稿者---Mr.Boo(2006/07/20 13:48:11)


>答えは先に言われてしまったので、実際の出力結果だけを…
>
>MAX_DATA_NO = 101
>sizeof(PERSONALDATA) = 24
>MAX_DATA_NO * sizeof(PERSONALDATA) = 124
>
>こーいう出力結果が出ました。defineはようは置き換えですからね。
>ところで、個人的には生徒数分だけmallocすれば良いと思うんですけど、
>演習だからそういうわけにはいかないのかな?

acid様、有難う御座います。

メモリは生徒数だけをmallocすれば、ということですが、課題の前提条件として
最大数だけを提示し、生徒番号が-1を入力されて入力終了としなさい、としてい
るため、先に最大生徒数だけmallocするようにしました。

でも、・・・・う〜ん、確かに入力された生徒数だけmallocする方が、処理と
しては、すっきりするでしょうね。

そこのところは、もう少し考えて見ます。



この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧