【掲示板ご利用上の注意】

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

 詳しくはこちら


本当はこんなに大きく書きたくはないのですが、なかなか守っていただけなくて…。
 守ってくださいね。お願いします。(by管理人)

C言語ソース⇒HTML形式ツール掲示板2こちら


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

No.22638

ファイルの中身を比較
投稿者---きよし(2005/08/14 23:03:42)


ファイルの中身を比較しているプログラムなのですが、ただ、
馬鹿みたいに上から流れる記述になっています。
関数化とか便利な関数を使用するといったスマートというか
見栄えの良いものではないです。
改善の余地があると思うです。
良いアドバイス等お願いします。


--- file1.txt -----
aaaa
ccc
dddd

--- file2.txt ----
bbb
dddd



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

main()
{
    FILE *fp1 ;
    FILE *fp2 ;
    char buf1[256] ;
    char buf2[256] ;
    char key1[256] ;
    char key2[256] ;
    int flg_end_file1 = 0 ;
    int flg_end_file2 = 0 ;
    int branch = 0 ;

    fp1 = fopen("file1.txt","r") ;
    if (fp1 == NULL) {
        printf("file open error file1.txt\n") ;
        exit(1) ;
    } 
    fp2 = fopen("file2.txt","r") ;
    if (fp2 == NULL) {
        printf("file open error file2.txt\n") ;
        exit(2) ;
    } 
 
    memset(buf1,'\0',sizeof buf1) ;
    memset(key1,'\0',sizeof key1) ;
    memset(buf2,'\0',sizeof buf2) ;
    memset(key2,'\0',sizeof key2) ;

    if (fgets(buf1,256,fp1) != NULL) {
        buf1[strlen(buf1)-1] = '\0' ;
        strcpy(key1,buf1) ; 
    } else {
        memset(key1,0xff,sizeof key1) ;
        flg_end_file1 = 1 ;
    }
    if (fgets(buf2,256,fp2) != NULL) {
        buf2[strlen(buf2)-1] = '\0' ;
        strcpy(key2,buf2) ; 
    } else {
        memset(key2,0xff,sizeof key2) ;
        flg_end_file2 = 1 ;
    }

    while(1) {
        if ((flg_end_file1 == 1) && (flg_end_file2 == 1)) break; 

        branch = strcmp(key1,key2) ;
        if (branch == 0) {
            printf("match file1 and file2 : file1 [%s] file2 [%s]\n",key1,key2) ;

            if (flg_end_file1 != 1) {
                memset(buf1,'\0',sizeof buf1) ;
                memset(key1,'\0',sizeof key1) ;
                if (fgets(buf1,256,fp1) != NULL) {
                    buf1[strlen(buf1)-1] = '\0' ;
                    strcpy(key1,buf1) ; 
                } else {
                    memset(key1,0xff,sizeof key1) ;
                    flg_end_file1 = 1 ;
                }
            }

            if (flg_end_file2 != 1) {
                memset(buf2,'\0',sizeof buf2) ;
                memset(key2,'\0',sizeof key2) ;
                if (fgets(buf2,256,fp2) != NULL) {
                    buf2[strlen(buf2)-1] = '\0' ;
                    strcpy(key2,buf2) ; 
                } else {
                    memset(key2,0xff,sizeof key2) ;
                    flg_end_file2 = 1 ;
                }
            }
        } else if (branch < 0) {
            printf("file1 only  : file1 [%s]\n",key1) ;

            if (flg_end_file1 != 1) {
                memset(buf1,'\0',sizeof buf1) ;
                memset(key1,'\0',sizeof key1) ;
                if (fgets(buf1,256,fp1) != NULL) {
                    buf1[strlen(buf1)-1] = '\0' ;
                    strcpy(key1,buf1) ; 
                } else {
                    memset(key1,0xff,sizeof key1) ;
                    flg_end_file1 = 1 ;
                }
            }
        } else {
            printf("file2 only  : file2 [%s]\n",key2) ;

            if (flg_end_file2 != 1) {
                memset(buf2,'\0',sizeof buf2) ;
                memset(key2,'\0',sizeof key2) ;
                if (fgets(buf2,256,fp2) != NULL) {
                    buf2[strlen(buf2)-1] = '\0' ;
                    strcpy(key2,buf2) ; 
                } else {
                    memset(key2,0xff,sizeof key2) ;
                    flg_end_file2 = 1 ;
                }
            }
        }
    }
}





この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:ファイルの中身を比較 22639 まきじ 2005/08/14 23:38:37
<子記事> Re:ファイルの中身を比較 22640 かずま 2005/08/15 00:40:13
<子記事> Re:ファイルの中身を比較 22643 まきじ 2005/08/15 01:03:38
<子記事> Re:ファイルの中身を比較 22644 まきじ 2005/08/15 02:26:27
<子記事> Re:ファイルの中身を比較 22715 2005/08/18 12:40:59
<子記事> Re:ファイルの中身を比較 22716 2005/08/18 12:43:03


No.22639

Re:ファイルの中身を比較
投稿者---まきじ(2005/08/14 23:38:37)


>改善の余地があると思うです。
>良いアドバイス等お願いします。

バグがあります。

file1.txt

dddd
aaaa
bbb

file2.txt

aaaa
dddd
bbb

である時

match file1 and file2 : file1 [dddd] file2 [dddd]
match file1 and file2 : file1 [aaaa] file2 [aaaa]
match file1 and file2 : file1 [bbb] file2 [bbb]

となるのを期待されていると思いますが、

file2 only : file2 [aaaa]
match file1 and file2 : file1 [dddd] file2 [dddd]
file1 only : file1 [aaaa]
match file1 and file2 : file1 [bbb] file2 [bbb]

となります。


この投稿にコメントする

削除パスワード

No.22640

Re:ファイルの中身を比較
投稿者---かずま(2005/08/15 00:40:13)


> ファイルの中身を比較しているプログラムなのですが、

ソート済みの2つのファイルを比較するんですね。ちゃんと仕様を書きましょう。
バグがあります。
memset(key1,0xff,sizeof key1) だと文字列の終端の '\0' がないので、
strcmp(key1,key2) が実行できません。

> 関数化とか便利な関数を使用するといったスマートというか
> 見栄えの良いものではないです。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void getline(char *buf, size_t size, FILE *fp)
{
    if (fgets(buf, size, fp)) {
        char *p = strchr(buf, '\n');
        if (p) *p = '\0';
    }
}

void print_get(const char *name, char *buf, size_t size, FILE *fp)
{
    printf("%s only  : %s [%s]\n", name, name, buf);
    getline(buf, size, fp);
}

void compare_files(FILE *fp1, FILE *fp2)
{
    char buf1[256], buf2[256];  int diff;

    getline(buf1, sizeof buf1, fp1);
    getline(buf2, sizeof buf2, fp2);
    while (!feof(fp1) && !feof(fp2))
        if ((diff = strcmp(buf1, buf2)) == 0) {
            printf("match file1 and file2 : file1 [%s] file2 [%s]\n", buf1, buf2);
            getline(buf1, sizeof buf1, fp1);
            getline(buf2, sizeof buf2, fp2);
        } else if (diff < 0)
            print_get("file1", buf1, sizeof buf1, fp1);
        else
            print_get("file2", buf2, sizeof buf2, fp2);
    while (!feof(fp1)) print_get("file1", buf1, sizeof buf1, fp1);
    while (!feof(fp2)) print_get("file2", buf2, sizeof buf2, fp2);
}

int main(void)
{
    FILE *fp1, *fp2;

    fp1 = fopen("file1.txt","r");
    if (!fp1) printf("file open error file1.txt\n"), exit(1);
    fp2 = fopen("file2.txt","r");
    if (!fp2) printf("file open error file2.txt\n"), exit(2);
    compare_files(fp1, fp2);
    return 0;
}



この投稿にコメントする

削除パスワード

No.22641

Re:ファイルの中身を比較
投稿者---かずま(2005/08/15 00:43:51)


< バグがあります。
< memset(key1,0xff,sizeof key1) だと文字列の終端の '\0' がないので、
< strcmp(key1,key2) が実行できません。

key1 と key2 のどちらか一方には '\0' で終わる文字列が入っていて、
そこで比較が必ず終了するので、バグとはいえませんね。失礼しました。



この投稿にコメントする

削除パスワード

No.22645

Re:ファイルの中身を比較
投稿者---きよし(2005/08/15 15:10:29)


まきじさん、かずまさん、アドバイス及びサンプルありがとうございます。

仕様を明確に書かなくて申し訳ありません。

ソート済みの2つのファイルの比較です。


この投稿にコメントする

削除パスワード

No.22699

Re:ファイルの中身を比較
投稿者---きよし(2005/08/17 23:46:46)


void getline(char *buf, size_t size, FILE *fp)
{
    if (fgets(buf, size, fp)) {
        char *p = strchr(buf, '\n');
        if (p) *p = '\0';
    }
}


サンプルソースで教えて頂きたいことがあるのですが、
if (p) *p = '\0';
はキャストをしていると思うのですが、
「(p)」はどこから出てきたのですか。
また、どのような意味があるのですか。



この投稿にコメントする

削除パスワード

No.22702

Re:ファイルの中身を比較
投稿者---まきじ(2005/08/17 23:50:54)


>if (p) *p = '\0';
>はキャストをしていると思うのですが、

キャストじゃありません。
p は if 文の条件式です。
「p が NULL でなければ」という意味です。


この投稿にコメントする

削除パスワード

No.22703

Re:ファイルの中身を比較
投稿者---きよし(2005/08/18 00:48:56)


>キャストじゃありません。
>p は if 文の条件式です。
>「p が NULL でなければ」という意味です。

注意力がたりませんでした。
変な質問してすみません。


この投稿にコメントする

削除パスワード

No.22697

Re:ファイルの中身を比較
投稿者---あきき(2005/08/17 23:23:03)


かずまさんへ。いつも、分かりやすい関数で勉強をさせてもらってます。
早速ですが、次の関数で、以下の点で悩んでいます

・変数「p」はいつ宣言されたのですか?

void getline(char *buf, size_t size, FILE *fp)
{
    if (fgets(buf, size, fp)) {
        char *p = strchr(buf, '\n');
        if (p) *p = '\0';
    }
}



この投稿にコメントする

削除パスワード

No.22698

Re:ファイルの中身を比較
投稿者---Blue(2005/08/17 23:28:04)


●C言語編 第22章 変数のスコープの ローカル変数 を参考にどうぞ



この投稿にコメントする

削除パスワード

No.22700

Re:ファイルの中身を比較
投稿者---あきき(2005/08/17 23:47:22)


>
●C言語編 第22章 変数のスコープの ローカル変数 を参考にどうぞ


関数の仮引数もローカル変数なんですね。やっとわかりました。Blueさんありがとうございます。



この投稿にコメントする

削除パスワード

No.22713

Re:ファイルの中身を比較
投稿者---nop(2005/08/18 09:47:50)


>・変数「p」はいつ宣言されたのですか?
> void getline(char *buf, size_t size, FILE *fp)
> {
>     if (fgets(buf, size, fp)) {
>         char *p = strchr(buf, '\n'); /* ← */
>         if (p) *p = '\0';
>     }
> }



この投稿にコメントする

削除パスワード

No.22717

Re:ファイルの中身を比較
投稿者---あきき(2005/08/18 14:22:31)


><pre>>・変数「p」はいつ宣言されたのですか?
> void getline(char *buf, size_t size, FILE *fp)
> {
> if (fgets(buf, size, fp)) {
> <strong>char *p = strchr(buf, '\n');</strong> /* ← */
> if (p) *p = '\0';
> }
> }</pre>

以前、関数の先頭で変数を宣言せず、使用直前に宣言したところ、”変数が宣言されていません”とのメッセージが出たので、投稿したところ
「変数の宣言は関数の先頭でするもの。」との指摘があり、プログラムを修正したところコンパイルがとおったのですが・・・



この投稿にコメントする

削除パスワード

No.22719

Re:ファイルの中身を比較
投稿者---nop(2005/08/18 14:30:04)


>「変数の宣言は関数の先頭でするもの。」との指摘があり、プログラムを修正したところコンパイルがとおったのですが・・・

正確にはブロックの先頭です。
この場合はif文のブロックの先頭に書かれているため、
問題なくコンパイル可能です。

# ちなみに、これらの変数は、
# そのブロックの内側のみで参照可能です。


この投稿にコメントする

削除パスワード

No.22723

Re:ファイルの中身を比較
投稿者---あきき(2005/08/18 15:17:26)


>>「変数の宣言は関数の先頭でするもの。」との指摘があり、プログラムを修正したところコンパイルがとおったのですが・・・
>
>正確にはブロックの先頭です。
>この場合はif文のブロックの先頭に書かれているため、
>問題なくコンパイル可能です。
>
># ちなみに、これらの変数は、
># そのブロックの内側のみで参照可能です。

>正確にはブロックの先頭です。
>この場合はif文のブロックの先頭に書かれているため、

今回だけではなく、前回の質問の回答の意味するものがやっと分かりました。
ブロック単位でその先頭ですね。ありがとうございます。



この投稿にコメントする

削除パスワード

No.22724

Re:ファイルの中身を比較
投稿者---まきじ(2005/08/18 15:25:48)


>「変数の宣言は関数の先頭でするもの。」との指摘があり、
> プログラムを修正したところコンパイルがとおったのですが・・・

過去ログの No.22069 の私のレスの事だと思いますが、
「ブロックの先頭」と記述しています。


この投稿にコメントする

削除パスワード

No.22725

Re:ファイルの中身を比較
投稿者---あきき(2005/08/18 15:45:24)


>>「変数の宣言は関数の先頭でするもの。」との指摘があり、
>> プログラムを修正したところコンパイルがとおったのですが・・・
>
>過去ログの No.22069 の私のレスの事だと思いますが、
>「ブロックの先頭」と記述しています。

過去ログ「No.22069」を見て確認したところ、確かに、「ブロックの先頭」と記述しています。いつの間にか、それが「関数の先頭」とすりかわっていました。せっかく回答して頂いたのに申し訳ありませんでした。
もう少し整理してみます。


この投稿にコメントする

削除パスワード

No.22726

Re:ファイルの中身を比較
投稿者---Blue(2005/08/18 15:53:28)


というか、私のNo.22698のレスのリンク先に書いてあるんですけどね。。。

C言語のルールで、ローカル変数は、ブロックの先頭部分で宣言しなければなりません
(C++では関数内のどこでも宣言できる)。ブロックとは{ と }で囲まれた範囲のことを
いいます。ブロックは好きな位置に書くことができます。
これを示すためにリンク先をはったつもりだったりして。 # なんか、違うように解釈されたらしい。 # > まきじさんへ # aタグを使うときに、target属性で _blank を指定してもらうとうれしいです。



この投稿にコメントする

削除パスワード

No.22727

Re:ファイルの中身を比較
投稿者---まきじ(2005/08/18 15:57:52)


># aタグを使うときに、target属性で _blank を指定してもらうとうれしいです。

解りました。
次からは target 属性を指定しておきます。


この投稿にコメントする

削除パスワード

No.22728

Re:ファイルの中身を比較
投稿者---あきき(2005/08/18 16:59:06)


Blueさんから教えて頂いたサイトでヒントを得る事ができなかったので、もう一度みて見ます。

ちなみになんですが、宣言時の初期化と思うのですが、下の様に関数を用いる事もできるのですか?

char *p = strchr(buf, '\n');



この投稿にコメントする

削除パスワード

No.22643

Re:ファイルの中身を比較
投稿者---まきじ(2005/08/15 01:03:38)


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

#define N 256

int main(int argc, char **argv){

    FILE *fp1, *fp2;
    char str1[N],str2[N];
    char mutch[100][N];
    int result;
    int m = 0;
    int i;
    
    if(argc != 3) return 1;
    if((fp1 = fopen(*(argv + 1),"r")) == NULL) return 1;
    
    while(fgets(str1, N, fp1) != NULL){
        
        if((fp2 = fopen(*(argv + 2),"r")) == NULL) return 1;
        
        while(fgets(str2, N, fp2) != NULL){
            result = strcmp(str1, str2);
            if(!result){
                printf("mutch : %s\n",str1);
                strcpy(mutch[m++],str1);
                break;
            }
        }
        
        if(result) printf("%s only: %s\n",*(argv + 1),str1);
        fclose(fp2);
    }

    fclose(fp1);
    
    if((fp2 = fopen(*(argv + 2),"r")) == NULL) return 1;
    
    while(fgets(str2, N, fp2) != NULL){
        for(i = 0; i < m && strcmp(mutch[i],str2); i++);
        if(i == m) printf("%s only: %s\n",*(argv + 2),str2);
    }  
    
    fclose(fp2);
}



この投稿にコメントする

削除パスワード

No.22644

Re:ファイルの中身を比較
投稿者---まきじ(2005/08/15 02:26:27)


22643 は、未ソート版。今回は、ソート済み版。
#include<stdio.h>
#include<string.h>

#define N 256

int main(int argc, char **argv){

    FILE *fp1, *fp2;
    char str1[N]={0};
    char str2[N]={0};
    int result;
    
    if(argc != 3) return 1;
    if((fp1 = fopen(*(argv + 1),"r")) == NULL) return 1;
    if((fp2 = fopen(*(argv + 2),"r")) == NULL) return 1;
    
    while(fgets(str1, N, fp1) != NULL){
        
        if(!strcmp(str1, str2)) printf("mutch : %s",str1);
        else{
            while(fgets(str2, N, fp2) != NULL && (result = strcmp(str1, str2)) > 0){ 
                printf("%s only: %s",*(argv + 2),str2);
            }
            
            if(feof(fp2)) break;
            
            if(!result) printf("mutch : %s",str1);
            else if(result < 0) printf("%s only: %s",*(argv + 1),str1);
            
        }
    }
    
    while(!feof(fp1)){
        printf("%s only: %s",*(argv + 1),str1);
        if(fgets(str1, N, fp1) == NULL) break;
    }

    while(!feof(fp2)){
        printf("%s only: %s",*(argv + 2),str2);
        if(fgets(str2, N, fp2) == NULL) break;
    }
    
    fclose(fp2);
    fclose(fp1);
}



この投稿にコメントする

削除パスワード

No.22744

Re:ファイルの中身を比較
投稿者---かずま(2005/08/19 09:03:15)


> 22643 は、未ソート版。今回は、ソート済み版。

そのプログラムに、最初の質問にあった file1.txt と file2.txt を
与えても、正しい結果が出ません。
プログラムを作ったら、テストぐらいするのが当然だと思うのですが。


この投稿にコメントする

削除パスワード

No.22748

Re:ファイルの中身を比較
投稿者---まきじ(2005/08/19 14:02:46)


>そのプログラムに、最初の質問にあった file1.txt と file2.txt を
>与えても、正しい結果が出ません。

本当ですね(^^;

>プログラムを作ったら、テストぐらいするのが当然だと思うのですが。

テスト不足でした。

一応、修正したもの載せときます。

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

#define N 256

int main(int argc, char **argv){

    FILE *fp1, *fp2;
    char str1[N]={0};
    char str2[N]={0};
    int result = 0;;
    
    if(argc != 3) return 1;
    
    if((fp1 = fopen(*(argv + 1),"r")) == NULL) return 1;
    if((fp2 = fopen(*(argv + 2),"r")) == NULL) return 1;

    fgets(str1, N, fp1);
    fgets(str2, N, fp2);
    
    while(!feof(fp1) && !feof(fp2)){
    
        while(!feof(fp2) && (result = strcmp(str1, str2)) > 0){ 
            printf("%s only: %s",*(argv + 2),str2);
            fgets(str2, N, fp2);
        }
        
        if(!result){
            printf("mutch : %s",str1);
            fgets(str2, N, fp2);
            
        }else printf("%s only: %s",*(argv + 1),str1);
        
        fgets(str1, N, fp1);
    }
    
    while(!feof(fp1)){
        printf("%s only: %s",*(argv + 1),str1);
        fgets(str1, N, fp1);
    }

    while(!feof(fp2)){
        printf("%s only: %s",*(argv + 2),str2);
        fgets(str2, N, fp2);
    }
    
    fclose(fp2);
    fclose(fp1);
}




この投稿にコメントする

削除パスワード

No.22715

Re:ファイルの中身を比較
投稿者---仁(2005/08/18 12:40:59)


ファイルから読み込んだ結果がNULLだった場合、変数のkey1とかkey2に
0xffを設定されてますが、strcmpの比較で、0xffが設定されている変数
とファイルから読み込んだ文字列が設定されている変数のと比較が、何故、
上手く、いっているのですか。



この投稿にコメントする

削除パスワード

No.22716

Re:ファイルの中身を比較
投稿者---仁(2005/08/18 12:43:03)


ファイルから読み込んだ結果がNULLだった場合、変数のkey1とかkey2に
0xffを設定されてますが、strcmpの比較で、0xffが設定されている変数
とファイルから読み込んだ文字列が設定されている変数のと比較が、何故、
上手く、いっているのですか。

例えば
strcmp("aaaaa","bbbbb")
strcmp(0xffが設定,"bbbbb")
の戻り値が同じになるのですか。



この投稿にコメントする

削除パスワード

No.22718

Re:ファイルの中身を比較
投稿者---まきじ(2005/08/18 14:26:48)


>0xffが設定されている変数とファイルから読み込んだ文字列が設定されている変数のと比較が、何故、上手く、いっているのですか。

引数などの指定に間違いがなければ(型など)、strcmp() は正常に動作します。

>例えば
>strcmp("aaaaa","bbbbb")
>strcmp(0xffが設定,"bbbbb")
>の戻り値が同じになるのですか。

どちらの strcmp() も 1 以上が返りますが、同じとは限りません。
よって、たまたま同じだったのでしょう。


この投稿にコメントする

削除パスワード

No.22732

Re:ファイルの中身を比較
投稿者---仁(2005/08/18 19:44:10)


    if (fgets(buf1,256,fp1) != NULL) {
        buf1[strlen(buf1)-1] = '\0' ;
        strcpy(key1,buf1) ; 
    } else {
        memset(key1,0xff,sizeof key1) ;
        flg_end_file1 = 1 ;
    }


で、ファイルの中身がなくなり、、比較する変数を「Oxff」でmemsetして、
strcmpで比較していますが、なぜ、上手く処理がされているのですか。
やるべき処理ではないということでしょうか。



この投稿にコメントする

削除パスワード

No.22737

Re:ファイルの中身を比較
投稿者---まきじ(2005/08/18 20:40:54)


>なぜ、上手く処理がされているのですか。

処理というのは、プログラム全体の事でしょうか?
もし、プログラムが結果として質問者の期待通りに、
なぜ動くかを知りたいのであればご自分でトレースしてください。


この投稿にコメントする

削除パスワード

No.22738

Re:ファイルの中身を比較
投稿者---Hermit(2005/08/18 21:34:01)


>>例えば
>>strcmp("aaaaa","bbbbb")
>>strcmp(0xffが設定,"bbbbb")
>>の戻り値が同じになるのですか。
>
>どちらの strcmp() も 1 以上が返りますが、同じとは限りません。
>よって、たまたま同じだったのでしょう。

元のプログラムよく見てませんが、辞書順なので、
strcmp("aaaaa","bbbbb") の結果は負数では無いですか?



この投稿にコメントする

削除パスワード

No.22739

Re:ファイルの中身を比較
投稿者---まきじ(2005/08/18 21:51:59)


>strcmp("aaaaa","bbbbb") の結果は負数では無いですか?

その通りです。
ご指摘ありがとうございます。


この投稿にコメントする

削除パスワード

No.22741

Re:ファイルの中身を比較
投稿者---仁(2005/08/18 22:41:27)


strcmp(0xffが設定,"bbbbb")の結果が負数
strcmp("aaaaa",0xffが設定)の結果が整数
になるのは。

聞く前に自分で動かしてトレースして見てみること。



この投稿にコメントする

削除パスワード

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