再びつまずいてしまいました;;よろしくお願いします。
CSVに書き換える課題です。
JZK-30 jizake_tsumeawase 4500
BSP-15 body_soap_set 3000
というファイルを
JZK-30, 4500, jizake_tsumeawase
BSP-15, 3000, body_soap_set
というように順番を入れ替えつつカンマをつけて指定したファイルに書き込む課題なんですが、やはり実行して書き込むファイル名を指定したとたんセグメントエラーになってしまいます;;
ご指摘おねがいします。
方法としては一端fpというファイルに一行ずつ書き込んでからfp2に書き込んでいます。
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
int main()
{
FILE *fp1,*fp2,*fp;
char s[256],data1[20],data2[20],data3[20];
char fname1[20],fname2[20];
int i;
printf("Input filename:");
scanf("%s",fname1);
printf("Output filename:");
scanf("%s",fname2);
if ((fp1 =fopen(fname1,"r"))==NULL){
printf("file open error!!\n");
exit(1);
}
fp2=fopen(fname2,"a+");
while(fgets(s,256,fp1)!=NULL){
for (i = 0; s !='\0'; i++){
fputs(s,fp);
fscanf(fp,"%s %s %s",data1,data2,data3);
fprintf(fp2,"%s, %s, %s\n",data1,data3,data2);
}
}
fclose(fp1);
fclose(fp2);
printf("Conversion finished\n");
return 0;
}
CSVに書き換える
Re:CSVに書き換える
こんな感じかな・・・
fp2 = fopen(fname2, "a+"); while (fgets(s, sizeof s, fp1) != NULL) { sscanf(s, "%s %s %s", data1, data2, data3); fprintf(fp2, "%s, %s, %s\n", data1, data3, data2); }ところで、書き込みモードは "a+" でいいんですよね。
Re:CSVに書き換える
前のデーターが消えてしまうのが嫌だったのでa+にしてます。
ご指摘の通りこのように書き換えてみたんですが
fp2=fopen(fname2,"a+");
while(fgets(s,256,fp1)!=NULL){
sscanf(s,"%s %s %s",data1,data2,data3);
fprintf(fp2,"%s, %s, %s\n",data1,data3,data2);
}
実行後に書き込んだファイルの中身を見てみると
JZK-30, 4500, jizake_tsumeawase
BSP-15, 3000, body_soap_set
BSP-15, 3000, body_soap_set
という感じで最後だけ二回書き込まれてるんですが、これはどのように修正すれば良いでしょうか?
ご指摘の通りこのように書き換えてみたんですが
fp2=fopen(fname2,"a+");
while(fgets(s,256,fp1)!=NULL){
sscanf(s,"%s %s %s",data1,data2,data3);
fprintf(fp2,"%s, %s, %s\n",data1,data3,data2);
}
実行後に書き込んだファイルの中身を見てみると
JZK-30, 4500, jizake_tsumeawase
BSP-15, 3000, body_soap_set
BSP-15, 3000, body_soap_set
という感じで最後だけ二回書き込まれてるんですが、これはどのように修正すれば良いでしょうか?
Re:CSVに書き換える
JZK-30 jizake_tsumeawase 4500
BSP-15 body_soap_set 3000
のファイルの最後に改行を入れているのが原因でした。ご迷惑をおかけしました;;
あと、このプログラムをキーボード入力ではなく、コマンド引数に指定することで動作するようにしたいんですが、全然検討もつきません。ちなみに例をあげるとこんな感じです。
% ./change smpl.txt smpl.csv
ご指導のほどよろしくお願いします。
BSP-15 body_soap_set 3000
のファイルの最後に改行を入れているのが原因でした。ご迷惑をおかけしました;;
あと、このプログラムをキーボード入力ではなく、コマンド引数に指定することで動作するようにしたいんですが、全然検討もつきません。ちなみに例をあげるとこんな感じです。
% ./change smpl.txt smpl.csv
ご指導のほどよろしくお願いします。
Re:CSVに書き換える
こんな感じでどうでしょう?ちょっと遊んではいますが(^^;
#include<stdio.h> #include<stdlib.h> int main(int argc, char **argv) { FILE *fp[/url] = {NULL,stdin, stdout}; char s[256]; char *mode[/url] = {NULL,"r","a+"}; int i; for (i = 1; i < argc && i < 3; i++) { fp = fopen(argv,mode); if (fp == NULL) { fprintf(stderr,"file open error %s\n",argv); exit(1); } } while (fgets(s, sizeof s, fp[1]) != NULL) { char data1[20], data2[20], data3[20], check; i = sscanf(s, "%19s %19s %19s %c", data1, data2, data3, &check); if (i != 3) { fprintf(stderr,"input error\n"); exit(1); } fprintf(fp[2], "%s, %s, %s\n", data1, data3, data2); } fclose(fp[1]); fclose(fp[2]); printf("Conversion finished\n"); return 0; }
Re:CSVに書き換える
ちょっと難しいので少しずつでも理解していこうと思います!
あと、すいませんが引数の数を数えて、引数の数を間違えて入力された時のエラーメッセージ(使用方法を表示する)も出したいんですが、可能でしょうか?こんな感じです↓
% ./change smpl.txt (読み取るファイル名しか入力されてない)
Usage: change INFILE OUTFILE (使用方法を表示して終了)
あと、すいませんが引数の数を数えて、引数の数を間違えて入力された時のエラーメッセージ(使用方法を表示する)も出したいんですが、可能でしょうか?こんな感じです↓
% ./change smpl.txt (読み取るファイル名しか入力されてない)
Usage: change INFILE OUTFILE (使用方法を表示して終了)
Re:CSVに書き換える
普通にこんな感じでいいんではないでしょうか?
// パラメータのチェック if (argc != 3) { printf("usage: %s change INFILE OUTFILE\n", argv[0]); exit(1); }
Re:CSVに書き換える
argcに引数の数、argvに引数の名前が入るんですよね?
FILE *fp[/url] = {NULL,stdin, stdout};
char *mode[/url] = {NULL,"r","a+"};
i = sscanf(s, "%19s %19s %19s %c", data1, data2, data3, &check);
の行が何を行っているのかわからないんですが、使いかたの説明もふまえて教えていただけるとありがたいです。
FILE *fp[/url] = {NULL,stdin, stdout};
char *mode[/url] = {NULL,"r","a+"};
i = sscanf(s, "%19s %19s %19s %c", data1, data2, data3, &check);
の行が何を行っているのかわからないんですが、使いかたの説明もふまえて教えていただけるとありがたいです。
Re:CSVに書き換える
遊んでる所ですね。
int main(int argc, char **argv)
例えば、
c:\bin\foo.exe foo.txt bar.txt
とした場合、
argv[0] -> プログラム名 -> c:\bin\foo.exe
argv[1] -> foo.txt
argv[2] -> bar.txt
だから、
0 の時、無視 -> NULL でうめておく
argv[1] に対応する時、argv[2] に対応する時
FILE *fp[/url] = {NULL,stdin, stdout};
で、入力ファイルが指定されない時は、stdin
出力ファイルが指定されなければ、stdout をデフォルトで当てています。
foo.exe foo.txt などとしておけば、bar.txt を開かなくてもコンソールに出てくるので楽だから(^^;
char *mode[/url] = {NULL,"r","a+"};
これは、argv[1],argv[2] の時のファイルのオープンモードの指定だけです。
fopen(argv[1],mode[1])
の様に、同じ添え字で済まそうと言う手抜きです。
i = sscanf(s, "%19s %19s %19s %c", data1, data2, data3, &check);
if (i != 3) {
これは、sscanf で変換された物が、3 個である事をチェックしています。
%19s は、バッファが 20byte なので、19文字 + null文字 の範囲しか入らないようにです。
最後の %c と、&check は、変換されないはずですが、変換されたら i が 4 になるのでエラーにしています。
少ない場合も、当然エラーです。
前回の、改行だけの時表示してしまった事への対策です。
int main(int argc, char **argv)
例えば、
c:\bin\foo.exe foo.txt bar.txt
とした場合、
argv[0] -> プログラム名 -> c:\bin\foo.exe
argv[1] -> foo.txt
argv[2] -> bar.txt
だから、
0 の時、無視 -> NULL でうめておく
argv[1] に対応する時、argv[2] に対応する時
FILE *fp[/url] = {NULL,stdin, stdout};
で、入力ファイルが指定されない時は、stdin
出力ファイルが指定されなければ、stdout をデフォルトで当てています。
foo.exe foo.txt などとしておけば、bar.txt を開かなくてもコンソールに出てくるので楽だから(^^;
char *mode[/url] = {NULL,"r","a+"};
これは、argv[1],argv[2] の時のファイルのオープンモードの指定だけです。
fopen(argv[1],mode[1])
の様に、同じ添え字で済まそうと言う手抜きです。
i = sscanf(s, "%19s %19s %19s %c", data1, data2, data3, &check);
if (i != 3) {
これは、sscanf で変換された物が、3 個である事をチェックしています。
%19s は、バッファが 20byte なので、19文字 + null文字 の範囲しか入らないようにです。
最後の %c と、&check は、変換されないはずですが、変換されたら i が 4 になるのでエラーにしています。
少ない場合も、当然エラーです。
前回の、改行だけの時表示してしまった事への対策です。