掲示板利用宣言

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

 私は

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

掲示板2

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

No.28312

printfでエラーが発生します
投稿者---Mr.Boo(2006/10/04 15:33:00)


開発環境 Borland C++ Compiler 5.5.1
     TurboDebugger
     BccDeveloper
実行OS  Windows2000 Pro,Windows XP HOME

上記環境で、入社予定者に対して教育をしております。
その中で、1点原因が分からず困っている問題があります。

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

void main(int argc, char *argv[] )
{
    FILE *fp;
    int   i,j;
    int   line=0;       //行のカウントをする
    char  *mozi;
    
    /*エラー処理*/
    if(argc != 3){
        if(argc ==1){
            printf("ファイル名が正しく指定されていません\n");
            exit(1);
        }
        else if(argc==2){
            printf("キーワードが指定されていません\n");
            exit(1);
        }
        else{
            printf("引数が不正です。");
            exit(1);
        }
    }
    if((fp=fopen(argv[1],"r"))==NULL){
        printf("指定されたファイルが開けません\n");
        exit(1);
    }

    for(line=1;fgets(mozi,256,fp) !=NULL;line++)
    {
        for(i=0;*(mozi+i) !='\0';i++)
        {
            if(*argv[2]==*(mozi+i)){     //一番上の文字列がヒット
                for(j=0;*(argv[2]+j) !='\0';j++)
                {
                     if(*(argv[2]+j) != *(mozi+i+j)){
                        i+=j;
                        break;
                    }
                 }

                 if(*(argv[2]+j)=='\0'){
                     printf("FileName:   %s:Line =%d\n",argv[1],line);
                
                }
            }
        }
    }
}


上記プログラムは、引数で入力されたファイルから、同じく引数で入力された文字列を検索するプログラムです。
現在、作成最中なので、完全ではないのですが途中確認を行ったところ、ファイル名と行番号を表示させるprintfでエラーが発生してしまいます。

TurboDebuggerのエラーメッセージは、”Stopped on exception throw”で、カーネルの中でとまっているので、暴走してしまっているようです。
printfに引き渡されている、ファイル名や行番号は間違っていないので、引数の問題でもなさそうですし、printfを単に文字列を表示するように変えてもだめでした。

どなたか、アドバイスをいただけませんでしょうか。
正直言って、はまっています。


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:printfでエラーが発生します 28314 si 2006/10/04 15:53:59
<子記事> Re:printfでエラーが発生します 28316 nano 2006/10/04 16:05:54
<子記事> Re:printfでエラーが発生します 28330 yoh2 2006/10/05 00:04:23


No.28314

Re:printfでエラーが発生します
投稿者---si(2006/10/04 15:53:59)


char *mozi;

for(line=1;fgets(mozi,256,fp) !=NULL;line++)
{

バッファが確保されてない。


この投稿にコメントする

削除パスワード

No.28320

Re:printfでエラーが発生します
投稿者---Mr.Boo(2006/10/04 16:35:37)


> char *mozi;
>
> for(line=1;fgets(mozi,256,fp) !=NULL;line++)
> {
>
>バッファが確保されてない。

siさん、ありがとうございます。
そうですよね、バッファの確保がありませんでした。
いつもの悪い癖で、前後の処理を見直せていませんでした。
バッファを確保すれば、一発で動作しました。


この投稿にコメントする

削除パスワード

No.28334

Re:printfでエラーが発生します
投稿者---かずま(2006/10/05 02:14:46)


> バッファを確保すれば、一発で動作しました。

本当でしょうか?

fgets() で読み込んだ moji の最後は '\n' ですが、
argv[2] の最後は '\n' ではないはずですから、
文字列の検索が成功することはありえないと思います。

>  if(*(argv[2]+j) != *(mozi+i+j)){
次のように書いたほうが分かりやすいと思いませんか?
    if (argv[2][j] != moji[i+j]) {



この投稿にコメントする

削除パスワード

No.28335

Re:printfでエラーが発生します
投稿者---かずま(2006/10/05 10:27:02)


> fgets() で読み込んだ moji の最後は '\n' ですが、

すみません。moji ではなく、mozi ですね。

元のプログラムには #include <string.h> がありますが、
それなら strstr() を使えばいいと思います。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    FILE *fp;  int line;  char mozi[1024];
    
    if (argc == 1) puts("ファイル名が正しく指定されていません"), exit(1);
    if (argc == 2) puts("キーワードが指定されていません"), exit(1);
    if (argc != 3) puts("引数が不正です。"), exit(1);

    fp = fopen(argv[1], "r");
    if (!fp) puts("指定されたファイルが開けません"), exit(1);

    for (line = 1; fgets(mozi, sizeof mozi, fp); line++) {
        char *p = strstr(mozi, argv[2]);
        if (p) printf("FileName: %s:Line = %d\n", argv[1], line);
    }
    return 0;
}



この投稿にコメントする

削除パスワード

No.28336

Re:printfでエラーが発生します
投稿者---かずま(2006/10/05 10:42:57)


> fgets() で読み込んだ moji の最後は '\n' ですが、
> argv[2] の最後は '\n' ではないはずですから、
> 文字列の検索が成功することはありえないと思います。

すみません。これは私の勘違いでした。
argv[2] の最後までの一致を見ているので問題ありません。


この投稿にコメントする

削除パスワード

No.28316

Re:printfでエラーが発生します
投稿者---nano(2006/10/04 16:05:54)


こんな風にしたかったのでしょうか…。
最大の修正点はmoziを配列にしたことです。
あとは、main関数の戻り値を規格に従ってint型にしたのと、
オープンしたファイルをちゃんとクローズするようにしました。

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

#define MAXSIZE (256)

int main(int argc, char *argv[])
{
    FILE *fp;
    int i, j, line;
    char mozi[MAXSIZE];
    
    /*エラー処理*/
    if (argc != 3) {
        if (argc == 1) {
            fprintf(stderr, "ファイル名が正しく指定されていません\n");
            exit(1);
        }
        else if (argc == 2) {
            fprintf(stderr, "キーワードが指定されていません\n");
            exit(1);
        }
        else {
            fprintf(stderr, "引数が不正です\n");
            exit(1);
        }
    }
    
    fp = fopen(argv[1], "r");
    if (fp == NULL) {
        fprintf(stderr, "指定されたファイルが開けません\n");
        exit(1);
    }
    
    for (line = 1; fgets(mozi, sizeof(mozi), fp) != NULL; line++) {
        for (i = 0; *(mozi+i) != '\0'; i++) {
            if (*argv[2] == mozi[i]) {
                for (j = 0; *(argv[2]+j) != '\0'; j++) {
                    if (*(argv[2]+j) != mozi[i+j]) {
                        i += j;
                        break;
                    }
                }
                if (*(argv[2]+j) == '\0') {
                    printf("FileName:   %s:Line =%d\n", argv[1], line);
                }
            }
        }
    }
    fclose(fp);
    return 0;
}




この投稿にコメントする

削除パスワード

No.28321

Re:printfでエラーが発生します
投稿者---Mr.Boo(2006/10/04 16:39:57)


>こんな風にしたかったのでしょうか…。
>最大の修正点はmoziを配列にしたことです。
>あとは、main関数の戻り値を規格に従ってint型にしたのと、
>オープンしたファイルをちゃんとクローズするようにしました。
>
><pre>#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXSIZE (256)

int main(int argc, char *argv[])
{
FILE *fp;
int i, j, line;
char mozi[MAXSIZE];

<font color="#009900">/*エラー処理*/</font>
if (argc != 3) {
if (argc == 1) {
fprintf(stderr, <font color="#0000ff">"ファイル名が正しく指定されていません\n"</font>);
exit(1);
}
else if (argc == 2) {
fprintf(stderr, <font color="#0000ff">"キーワードが指定されていません\n"</font>);
exit(1);
}
else {
fprintf(stderr, <font color="#0000ff">"引数が不正です\n"</font>);
exit(1);
}
}

fp = fopen(argv[1], <font color="#0000ff">"r"</font>);
if (fp == NULL) {
fprintf(stderr, <font color="#0000ff">"指定されたファイルが開けません\n"</font>);
exit(1);
}

for (line = 1; fgets(mozi, sizeof(mozi), fp) != NULL; line++) {
for (i = 0; *(mozi+i) != '\0'; i++) {
if (*argv[2] == mozi[i]) {
for (j = 0; *(argv[2]+j) != '\0'; j++) {
if (*(argv[2]+j) != mozi[i+j]) {
i += j;
break;
}
}
if (*(argv[2]+j) == '\0') {
printf(<font color="#0000ff">"FileName:   %s:Line =%d\n"</font>, argv[1], line);
}
}
}
}
fclose(fp);
return 0;
}

</pre>

nanoさん、ありがとうございます。
おぉ、確かに開いたファイルをクローズしていませんでした。
こんなミスから、メモリリークを起こしてしまうのですね。


この投稿にコメントする

削除パスワード

No.28325

Re:printfでエラーが発生します
投稿者---nano(2006/10/04 16:49:12)


>こんなミスから、メモリリークを起こしてしまうのですね。

ファイルがオープンしたままになっていることと
メモリーリークとは特に関係ないように思うのですが…。
malloc系の関数で動的に確保した領域をfreeしないために
発生するのがメモリーリークだと思ってました。

ファイルをオープンしっぱなしにすると、別のプログラムで
同じファイルをオープンしようとしてもできない、という弊害が
発生しうるとは思いますが…。


この投稿にコメントする

削除パスワード

No.28326

Re:printfでエラーが発生します
投稿者---123456789(2006/10/04 18:28:25)


文面のしっかりさと、ミスのレベルを比べると、どうやら投稿者は結構うっかりさんのようですね。


この投稿にコメントする

削除パスワード

No.28329

Re:printfでエラーが発生します
投稿者---yoh2(2006/10/04 23:49:29)


>>こんなミスから、メモリリークを起こしてしまうのですね。
>
>ファイルがオープンしたままになっていることと
>メモリーリークとは特に関係ないように思うのですが…。
>malloc系の関数で動的に確保した領域をfreeしないために
>発生するのがメモリーリークだと思ってました。

メモリリークはmalloc系の開放し忘れだけに使い、メモリリークやファイルの閉じ忘れなど、
開放すべきものの開放し忘れはまとめてリソースリークと表現することが多いですね。
(文脈によっては、リソースリークにメモリリークを入れないこともありますが)


この投稿にコメントする

削除パスワード

No.28337

Re:printfでエラーが発生します
投稿者---かずま(2006/10/05 10:52:36)


> おぉ、確かに開いたファイルをクローズしていませんでした。

exit() を実行すると、ファイルはクローズされます。
main から戻ったときも exit() が実行されますから、
ファイルはクローズされます。


この投稿にコメントする

削除パスワード

No.28330

Re:printfでエラーが発生します
投稿者---yoh2(2006/10/05 00:04:23)


表題の件は解決したようですが、ひとつ気になることがあったのでちょっと書いてみます。

>                 for(j=0;*(argv[2]+j) !='\0';j++)
>                {
>                     if(*(argv[2]+j) != *(mozi+i+j)){
>                        i+=j;
>                        break;
>                     }
>                 }
>
>                 if(*(argv[2]+j)=='\0'){
>                      printf("FileName:   %s:Line =%d\n",argv[1],line);
>                 
>                }

ここのi += j; は検索の高速化のためでしょうが、これが悪さをして、行と検索文字列の組み合わせによっては検索漏れを起こします。
例: moji = "aab", argv[2] = "ab"
この手の検索の高速化については、「KMP法」「BM法」というキーワードで調べてみるとよいと思います。
ただ、新人教育という点からはちょっと重い内容かもしれません。
# KMP法については、アルゴリズムを理解できなかったベテランプログラマによって、
# 力まかせな方法に書き換えられたことがあるという逸話もありますし。

あと、
>             if(*argv[2]==*(mozi+i)){     //一番上の文字列がヒット

はなくても正しく動作しますね。

# ありゃ。ひとつと言いながらふたつになっちゃった。


この投稿にコメントする

削除パスワード

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