C言語関係掲示板

過去ログ

No628 ファイルの内容を任意の文字数で改行させる

[戻る] [ホームページ]
No.6471

ファイルの内容を任意の文字数で改行させる
投稿者---BEE(2003/05/16 22:51:01)


いつもお世話になりっぱなしで、とても感謝しております。
続けての質問、失礼ながらさせていただきます。

あるファイルの内容を、任意の文字数で改行させる、
というプログラムを書いてみました。
例えば、
aaaa
bbbb
という内容のa.txtというファイルがあったとき、
「a.txt 3」という引数をとって実行すると、
aaa
abb
bb
となるように動作するプログラムです。

以下のようにしてみたのですが、
実行してみたところ、ファイルの内容が消えるだけで、
うまい具合に改行をしてくれません。
どこが違うのかご指摘いただけると幸いです。
環境は、WinME、コンパイラはBorland C++ 5.5です。

#include<stdio.h>
#include<stdlib.h>
#define need 128

int main(int argc,char *argv[]){
	FILE *fp;
	char line[need],*line2[need];
	int a,b=0,i,j,m=0,n=0,x;
	  a=atoi(argv[2]);
	  /*line2のそれぞれの要素に、a個の文字分のメモリを確保*/
	for(i=0;i<need;i++){
	line2[i]=(char*)malloc(sizeof(char)*a);
}
 	if(argc==3){
	 	/*ファイルをrモードで開く*/
 	 if((fp=fopen(argv[1],"r"))==NULL){
    printf("FILE OPEN ERROR\n");
  }
    else{ 
	/*a個ずつline2[]に格納することを、ファイル内容が空になるまで繰り返す*/
	while((x=fgetc(fp))!=EOF ){
		if(m==a){
			line2[n]=line;
			n++;
			b++;
		}
		else{
		line[m]=x;
	    m++;
     }
	 fclose(fp);
	 /*今度は書き込むため、wモードでファイルを開く*/
	 fp=fopen(argv[1],"w");
	 /*読み込んだ行を書き込む*/
	 for (j=0;j<b;j++){
	fprintf(fp,"%s\n",line2[j]);
     }
	 printf("FILE WRITE OK !!\n");
   }
}
}
else{
		;
	}
	return 0;
}







No.6478

Re:ファイルの内容を任意の文字数で改行させる
投稿者---XYZ(2003/05/16 23:15:34)


whileの括弧の閉じる位置がおかしいと思われます。
あと、fprintf(fp,"%s\n",line2[j]);
でline2の文字列の最後に'\0'入ってますか?


この投稿にコメントする

削除パスワード

No.6486

Re:ファイルの内容を任意の文字数で改行させる
投稿者---BEE(2003/05/16 23:42:29)


>whileの括弧の閉じる位置がおかしいと思われます。
>あと、fprintf(fp,"%s\n",line2[j]);
>でline2の文字列の最後に'\0'入ってますか?
whileの括弧の位置…確かにおかしいですね。
なるほど、ありがとうございます。

line2の文字列の最後に、\0…。
これでは入っていないのですね。
line[m]='\n'の一文を、
while((x=fgetc(fp))!=EOF ){
		if(m==a){
			line[m]='\0';
			line2[n]=line;
			n++;
			b++;
		}
		else{
		line[m]=x;
	    m++;
     }
	}

というように入れてみたところ、
うまくいったか…と思いましたが、
aaaaa
bbbbb
が、「a.txt 3」実行したのち、
aaa
aaa

aaa
と、aaaが9つ表示されてしまいました。
う〜ん。

No.6489

Re:ファイルの内容を任意の文字数で改行させる
投稿者---しんちー(2003/05/17 00:04:06)


m リセットをかけていないのが原因ですかね。

No.6490

Re:ファイルの内容を任意の文字数で改行させる
投稿者---XYZ(2003/05/17 00:05:27)


mallocの後のfreeはどこへ?
>line2[n]=line;
はアドレスの代入(?)なのでmallocで確保した領域はどこへ行ったのでしょう?
先に書かれてしまったけど
問題は多分、mがリセットされていない。だと思います。

No.6491

Re:ファイルの内容を任意の文字数で改行させる
投稿者---BEE(2003/05/17 00:42:20)


えっと…、line2[n]=line で、
line[m](1<=m<=a)の先頭アドレスがline2[n]に格納されて、
そのことにより、mallocで確保した領域は、
結果的には無意味になってしまった、ということでしょうか。

重ね重ねで申し訳ないですが、
mをリセット、とはどういった手順でやれば良いのでしょうか。

while((x=fgetc(fp))!=EOF ){
		if(m==a){
			line[m]='\0';
			line2[n]=line;
			n++;
			b++;
			m=0;
		}
		else{
		line[m]=x;
	    m++;
     }
	}
		for(i=0;i<need;i++){
		free (line2[i]);
	}


といった風にやってみたのですが、
駄目でした。


No.6492

Re:ファイルの内容を任意の文字数で改行させる
投稿者---XYZ(2003/05/17 00:52:52)


>line[m](1<=m<=a)の先頭アドレスがline2[n]に格納されて、
>そのことにより、mallocで確保した領域は、
>結果的には無意味になってしまった、ということでしょうか。

無意味になっただけでなく、lineの先頭アドレスがline2[n]に格納されているのに、
後でlineの内容を変えるとlineを参照するline2[n]にも反映されてしまうということです。(実際にはコピーされていない)

う〜ん、自分で読んでもわかりにくい。(笑)

No.6493

Re:ファイルの内容を任意の文字数で改行させる
投稿者---BEE(2003/05/17 01:28:36)


>無意味になっただけでなく、lineの先頭アドレスがline2[n]に格納されているのに、
>後でlineの内容を変えるとlineを参照するline2[n]にも反映されてしまうということです。(実際にはコピーされていない)
>
>う〜ん、自分で読んでもわかりにくい。(笑)

成る程!
lineの内容を変えると、それに連動してline2[n]の内容も変わってしまう、
ということですね。
確かにその通りですね。非常に良く分かりました。(笑
となると、line2はポインタ配列にするよりも、
二次元配列にしたほうが良いのでしょうか?
それとも、ポインタ配列のままでやっていく方法があるのでしょうか。
line2[n]=line の後に、lineのアドレスを変える方法…、う〜ん。


No.6494

Re:ファイルの内容を任意の文字数で改行させる
投稿者---XYZ(2003/05/17 02:08:13)


今、コンパイル出来る環境にて原因究明をした結果、問題点が複数ありました。
ソースを書くと早いのですが自分で考えてほしいのであえて載せません。

1,mallocで'\0'の分の領域を確保すること。
2,(m==a)の時、xが無視されている。
3,getc()でデータを取ると'\n'も1字となる。
4,freeの位置がおかしい。printf(...)の処理がまだ残っている。
5,a個ずつ改行していくと最後の行の文字数はa個とは限らない。
6,line2[n]=lineについては<string.h>のstrcpyという関数を利用する方法もあります。
(7,引数がない時不足している時などはエラーが出るかも)

他にもあるかもしれませんがこんなところだと思います。

No.6495

Re:ファイルの内容を任意の文字数で改行させる
投稿者---しんちー(2003/05/17 10:36:54)


>6,line2[n]=lineについては<string.h>のstrcpyという関数を利用する方法もあります。

もしくは、malloc のタイミングを変えてみるのはどうでしょう。
行が変わるときに malloc をして line に割り当てるとか。
(直接 line2[n] に割り当てるのでもいいと思います)

No.6498

Re:ファイルの内容を任意の文字数で改行させる
投稿者---BEE(2003/05/17 10:59:00)


>>6,line2[n]=lineについては<string.h>のstrcpyという関数を利用する方法もあります。
>
>もしくは、malloc のタイミングを変えてみるのはどうでしょう。
>行が変わるときに malloc をして line に割り当てるとか。
>(直接 line2[n] に割り当てるのでもいいと思います)

ふむ、それはこういうことなのでしょうか?
すみません、何か違いますね…。う〜ん…。

	while((x=fgetc(fp))!=EOF ){
		if(x=='\n'){
			kaigyo[k]=x;
			k++;
		}
		else{
		if(m==a){
			line[m]='\0';
			line2[n]=(char*)malloc(sizeof(char)*a+1);
			line2[n]=line;
			n++;
			b++;
			m=0;
			line[m]=x;
			m++;
		}
		else{
		    line[m]=x;
	        m++;
     }
	}
   }


No.6497

Re:ファイルの内容を任意の文字数で改行させる
投稿者---BEE(2003/05/17 10:51:35)


なるほど…、こうしてご指摘いただくと、
確かに問題点がたくさんありますね。
それぞれを参考にさせていただきながら、
ソースを書き直していってみたところ、うまくいきました!
以下のようにしてみました。

>3,getc()でデータを取ると'\n'も1字となる。
というご指摘に関しては、
kaigyo[]という配列を作って、そこに\nを
とりあえず格納しておく、という苦肉の策のようになってしまいましたが…。
他にスマートな方法はありますでしょうか?

そして、本当に参考になりました。
ありがとうございました。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define need 128

int main(int argc,char *argv[]){
	FILE *fp;
	char line[need],*line2[need],kaigyo[1024];
	int a,b=0,i,j,k,m=0,n=0,x;
	  a=atoi(argv[2]);
	  /*line2のそれぞれの要素に、a個の文字分のメモリを確保*/
	for(i=0;i<need;i++){
	line2[i]=(char*)malloc(sizeof(char)*a+1);
}
 	if(argc==3){
	 	/*ファイルをrモードで開く*/
 	 if((fp=fopen(argv[1],"r"))==NULL){
    printf("FILE OPEN ERROR\n");
  }
    else{ 
	
	while((x=fgetc(fp))!=EOF ){
		if(x=='\n'){
			kaigyo[k]=x;
			k++;
		}
		else{
		if(m==a){
			line[m]='\0';
			strcpy(line2[n],line);
			n++;
			b++;
			m=0;
			line[m]=x;
			m++;
		}
		else{
		    line[m]=x;
	        m++;
     }
	}
   }
   /*最後の一行に関して*/
   line[m]='\0';
   strcpy(line2[n],line);
   b++;
	 fclose(fp);
	 /*今度は書き込むため、wモードでファイルを開く*/
	 fp=fopen(argv[1],"w");
	 /*読み込んだ行を書き込む*/
	 for (j=0;j<b;j++){
	fprintf(fp,"%s\n",line2[j]);
     }
	 printf("FILE WRITE OK !!\n");
   }

}
else{
		;
	}
		for(i=0;i<need;i++){
		free (line2[i]);
	}
	return 0;
}





No.6524

Re:ファイルの内容を任意の文字数で改行させる
投稿者---かずま(2003/05/18 18:38:36)


> ソースを書き直していってみたところ、うまくいきました!

argc が 3 かどうかチェックする前に argv[2] を参照するのは
おかしくありませんか。プログラムを起動するときに間違えて
引数にファイル名だけを書くとどうなりますか。


> kaigyo[]という配列を作って、そこに\nを
> とりあえず格納しておく、という苦肉の策のようになってしまいましたが…。

使いもしないのに kaigyou[] に '\n' をため込んでどうする
つもりでしょうか。


> 他にスマートな方法はありますでしょうか?

インデント(字下げ)をちゃんとしましょう。
} を単独で 1行に書くときは、対応する { の行頭とそろえること。
#include <stdio.h>
#include <stdlib.h>

#define BUFSIZE  (128 * 128)

int main(int argc, char *argv[])
{
    static char buf[BUFSIZE];
    FILE *fp;
    int c, len, n, i, k;

    if (argc != 3) { printf("usage: %s file length\n", argv[0]); return 1; }

    fp = fopen(argv[1], "r");
    if (fp == NULL) { printf("can't open %s\n", argv[1]); return 1; }
    len = atoi(argv[2]);
    n = 0;
    while ((c = fgetc(fp)) !=EOF) {
        if (c != '\n') {
            if (n >= BUFSIZE) { puts("file too big"); return 1; }
            buf[n++] = c;
        }
    }
    fclose(fp);

    fp = fopen(argv[1], "w");
    if (fp == NULL) { printf("can't open %s\n", argv[1]); return 1; }
    k = 0;
    for (i = 0; i < n; i++) {
        putc(buf[i], fp);
        if (++k >= len) { putc('\n', fp); k = 0; }
    }
    if (k > 0) putc('\n', fp);
    fclose(fp);

    return 0;
}


No.6534

Re:ファイルの内容を任意の文字数で改行させる
投稿者---BEE(2003/05/18 22:37:14)


>argc が 3 かどうかチェックする前に argv[2] を参照するのは
>おかしくありませんか。プログラムを起動するときに間違えて
>引数にファイル名だけを書くとどうなりますか。
ごもっともです。
引数にファイル名のみを書くと、バグを起こし、
DOS窓が強制終了させられてしまいました。
論理的に考えておかしいことでした。

>使いもしないのに kaigyou[] に '\n' をため込んでどうする
>つもりでしょうか。
なるほど。
「==」ではなくて、「!=」を使えば、簡単に表現できますね。
「==」を使った上でどうしようか、という考え方をしていましたので、
こんな無意味なコードを書いてしまいました。

>インデント(字下げ)をちゃんとしましょう。
>} を単独で 1行に書くときは、対応する { の行頭とそろえること。
分かりました。
たしかに、私のコードは統一性が無く、見にくいものでしたね。
見易さから、ミスが減ることもあるだろうと思いますので、
インデントにも、キチンと注意を払っていきます。

丁寧なご説明、ありがとうございました。