掲示板利用宣言

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

 私は

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

掲示板2

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

No.25706

ファイル入出力と配列
投稿者---がりんしゃ(2006/01/25 12:10:55)


ファイル入出力について質問があります。

テキストファイル(read.txt)を読み込み、入力データを同一になるように別名で出力するという問題があります。

まず私の書いたソースを見てもらいたいのですが、

//-------------ソース--------------------



int main()
{
 char fnamein[100];
 char fnameout[100];
 FILE *fin;
 FILE *fout;
 char cdata[256];
  //int idata[7][3];



 //ファイルオープン



 printf("入力ファイル名:");
 scanf("%s",fnamein);

 if((fin = fopen(fnamein,"r")) == NULL)
 {
  printf("%sファイルを開けません。\n");
  exit(0);
 }

 printf("出力ファイル名:");
 scanf("%s",fnameout);

 fout = fopen(fnameout,"w");

 while(fgets(cdata,256,fin) != NULL)
 {
  fputs(cdata,fout);
 }

 fclose(fin);
 fclose(fout);

 return(0);

}
//---------------------------------------




//----------------read.txt---------------


123,456,789
234,567,890
345,678,901
45,67,89
56,78,90
1,2,3
4,5,6
//---------------------------------------




上記のソースで、read.txtを読み込み、別名で同一のファイルを作ることはできます。
ただ、
1.read.txtの区切り文字を','としたときのデータ1つ1つをint型の2次元配列に格納してから出力する
2.fputs,fgetsは必ず使う
という2つの条件があるので、私の書いたソースだとただ単に1行ずつ読んでchar型のまま出力しているに過ぎませんよね?

そこで質問なのですが、条件1において、データは見た目では','で区切られていますが、
読み込んだ時は','を勝手に区切り文字として判断しているのですか?
それともchar型の1バイト分の1つの文字として判断しているのですか?
判断していない場合は','を区切り文字として判断するにはどうすればよいのでしょうか?

条件1、2を踏まえた時に、fgetsを使うと、char型のcdataに入れなければなりませんよね?
char型のcdataに入ったデータ1つ1つをint型の2次元配列に格納するというのはどうすれば良いのでしょうか?
atoiを使えばよいのでしょうか?

アルゴリズムは、
 //fgetsで1行目の最初から1つ目の','の前までをchar型cdataに読み込む


 //idata[0][0] = atoi(cdata); int型に変換して[0][0]に格納


 //fgetsで1行目の1つ目の','の後から2つ目の','の前までをchar型cdataに読み込む


 //idata[0][1] = atoi(cdata); int型に変換して[0][1]に格納


 // ・


 // ・


 // ・


 //ファイルの最後までループ?            



のような感じになるのでは、と考えているのですが、
これだと、','から、','までの部分がどのように書いてよいものかわかりません・・・

長文になってしまいました。アドバイス宜しくお願いします。
環境はWindowsXP,MicrosoftVisualC++です。



この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:ファイル入出力と配列 25707 RAPT 2006/01/25 13:08:04
<子記事> Re:ファイル入出力と配列 25708 si 2006/01/25 13:19:06
<子記事> Re:ファイル入出力と配列 25709 iijima 2006/01/25 13:31:08


No.25707

Re:ファイル入出力と配列
投稿者---RAPT(2006/01/25 13:08:04)


> そこで質問なのですが、条件1において、データは見た目では','で区切られていますが、
> 読み込んだ時は','を勝手に区切り文字として判断しているのですか?
> それともchar型の1バイト分の1つの文字として判断しているのですか?

> fputs(cdata,fout);
の代わりに、printf()などで確認すれば良いでしょう。

> 判断していない場合は','を区切り文字として判断するにはどうすればよいのでしょうか?
標準関数 strtok() を調べてみてください。

> 環境はWindowsXP,MicrosoftVisualC++です。
間違って無いけど、VC++6 とか、VC++.NET2003 とかバージョンも書いて、
Cとしてコンパイルしているか、C++としてコンパイルしているか、
あたりも併記するともっと良いです。
# 多分、VC++6/C/Consoleでしょうが。



この投稿にコメントする

削除パスワード

No.25708

Re:ファイル入出力と配列
投稿者---si(2006/01/25 13:19:06)


scanf関数をご存じの様ですが、その仲間で、sscanf関数というのがあるのを知っていますか。
これを使えば、決まったフォーマットで読み込まれる文字列から、数値へ変換するのは簡単です。

printfとscanf関数の仲間を知っていると、プログラムが簡単になる場合が多いですよ。


この投稿にコメントする

削除パスワード

No.25709

Re:ファイル入出力と配列
投稿者---iijima(2006/01/25 13:31:08)


> アルゴリズムは、
> (略)
> のような感じになるのでは、と考えているのですが、

fgetsには任意の区切り文字で区切りながら読む機能はありません。
ですから、

1行読む(fgets)
1行を','で区切り(strtok)、整数値に変換(atio)して配列の要素に代入する
次の行を読む
:
:

といった手順が考えられます。



この投稿にコメントする

削除パスワード

No.25731

Re:ファイル入出力と配列
投稿者---がりんしゃ(2006/01/26 09:55:47)


アドバイスありがとうございます。

RAPTさん、
>> 判断していない場合は','を区切り文字として判断するにはどうすればよいのでしょうか?
>標準関数 strtok() を調べてみてください。

strtokの存在は知っていましたが、使いどころ忘れてました・・・これ使えば簡単ですね。

>間違って無いけど、VC++6 とか、VC++.NET2003 とかバージョンも書いて、
>Cとしてコンパイルしているか、C++としてコンパイルしているか、
>あたりも併記するともっと良いです。

すいません。
環境は、VisualC++6.0で、C++としてコンパイルしてます。
正直、未だにCとC++の違いがよくわかっていませんが。


siさん、
>sscanf関数というのがあるのを知っていますか。

sscanfの存在は知ってましたが、使い方は良くわかってませんでした。
調べて見ましたが、文字と数値を分けて読み込めるんですね。
今回できたソースは使ってませんがこれを使ってもできそうです。


iijimaさん、
>1行読む(fgets)
>1行を','で区切り(strtok)、整数値に変換(atio)して配列の要素に代入する
>次の行を読む

まさにその手順で考えてみて、できました。
ありがとうございました。

ただ、わざわざint型に変換した数値を、再びchar型に変えてfputsで読み込むというのが理解できなかったのでfputsは使えませんでした。。

strtokの存在を思い出せたことが良かったみたいです・・・。



以下ができたソースです。


//------------------------------------

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

#define LINE_CNT 7
#define ROW_CNT  3

int main()
{
 char fnamein[100];
 char fnameout[100];
 FILE *fin;
 FILE *fout;

 //オープンするファイルを指定

 printf("入力ファイル名:");
 scanf("%s",fnamein);

 //ファイルオープンに失敗

 if((fin = fopen(fnamein,"r")) == NULL)
 {
  printf("%sファイルを開けません\n",fnamein);
  exit(0);
 }

 printf("出力ファイル名:");
 scanf("%s",fnameout);

 fout = fopen(fnameout,"w");

 int data[LINE_CNT][ROW_CNT];
 char cdata[256];
 char *comma_ptr;
 int idata = 0;
 int cntA = 0;
 int cntB = 0;

 while(fgets(cdata,256,fin) != NULL)
 {
  cntB = 0;

  comma_ptr = strtok(cdata,",");
  idata = atoi(comma_ptr);
  data[cntA][cntB] = idata;
  cntB++;

  while((comma_ptr = strtok(NULL,",")) != NULL)
  {
   idata = atoi(comma_ptr);
   data[cntA][cntB] = idata;
   cntB++;
  }
  cntA++;
 }

 for(cntA=0;cntA<LINE_CNT;cntA++)
 {
  for(cntB=0;cntB<ROW_CNT;cntB++)
  {
   fprintf(fout,"%d",data[cntA][cntB]);
   if(cntB != 2)
   {
    fprintf(fout,",");
   }
  }
  fprintf(fout,"\n");
 }

 fclose(fin);
 fclose(fout);

 return(0);
}

//------------------------------------




この投稿にコメントする

削除パスワード

No.25734

Re:ファイル入出力と配列
投稿者---shu(2006/01/26 10:23:07)


>ただ、わざわざint型に変換した数値を、再びchar型に変えてfputsで読み込むというのが理解できなかったのでfputsは使えませんでした。。

そのあたりのことを「億足」ですが考えてみたんです。

一番最初に、載せていたソースですが、あれはあれで間違い無いと思います。
ただ、int型二次元配列に読み込むことが足りない。

fgets(),fputs()でやっているのは、元のデータのバックアップ処理ではないでしょうか?
実際に、例えば表計算などに使うための値が、int型二次元配列ということだとすると、つじつまが合うような気がします。


この投稿にコメントする

削除パスワード

No.25735

Re:ファイル入出力と配列
投稿者---かずま(2006/01/26 10:34:03)


> sscanfの存在は知ってましたが、使い方は良くわかってませんでした。
> 調べて見ましたが、文字と数値を分けて読み込めるんですね。

sscanf の代わりに、fscanf を使ってみました。
#include <stdio.h>
#include <stdlib.h>

#define ROW_CNT  7
#define COL_CNT  3

int main(void)
{
    int data[ROW_CNT][COL_CNT], i, j;
    char fnamein[256], fnameout[256];
    FILE *fin, *fout;

    printf("入力ファイル名: "), scanf("%s", fnamein);
    fin = fopen(fnamein, "r");
    if (!fin) printf("%sファイルを開けません\n", fnamein), exit(1);

    printf("出力ファイル名: "), scanf("%s", fnameout);
    fout = fopen(fnameout, "w");
    if (!fout) printf("%sファイルを開けません\n", fnameout), exit(1);

    for (i = 0; i < ROW_CNT; i++)
        for (j = 0; j < COL_CNT; j++)
            if (fscanf(fin, "%d%*c", &data[i][j]) != 1)
                printf("read error at (%d, %d)\n", i, j), exit(1);

    for (i = 0; i < ROW_CNT; i++)
        for (j = 0; j < COL_CNT; j++)
            fprintf(fout, "%d%c", data[i][j], ",\n"[j == COL_CNT-1]);

    fclose(fin);
    fclose(fout);
    return 0;
}
なお、模範解答とはならないコーディングをしていますので、ご注意を。


この投稿にコメントする

削除パスワード

No.25771

Re:ファイル入出力と配列
投稿者---がりんしゃ(2006/01/27 16:01:33)


>fgets(),fputs()でやっているのは、元のデータのバックアップ処理ではないでしょうか?
>実際に、例えば表計算などに使うための値が、int型二次元配列というこ
>とだとすると、つじつまが合うような気がします。

int型二次元配列は、プログラム内で計算に使う値で、
ファイルとして同じデータを出力するにはfgets,fputsを使うということですか?

出題者の意図は正直わかりませんが、そういうことだと両方使えますね。。

>sscanf の代わりに、fscanf を使ってみました。
fgets,fputs使わないとそういう方法もありますね。参考になります。ありがとうございました。



この投稿にコメントする

削除パスワード

No.25774

Re:ファイル入出力と配列
投稿者---とろり(2006/01/27 20:37:09)


こんばんは。

>int型二次元配列は、プログラム内で計算に使う値で、
>ファイルとして同じデータを出力するにはfgets,fputsを使うということですか?
>出題者の意図は正直わかりませんが、そういうことだと両方使えますね。。

単純に

1.fgets()で読込み
2.数値を分解
3.数値を文字列にもどしてfputs()で書込み

ということだと思うんですけどねぇ。。。


>>sscanf の代わりに、fscanf を使ってみました。
>fgets,fputs使わないとそういう方法もありますね。参考になります。ありがとうございました。

完結されたような印象を受けますが、本当に大丈夫ですか?
提示されたソースでは fputs() を使用しておらず、十中八九「不可」になると思うのですが。。。
その時に「だめでした、アドバイスおねがいします。」ってことになりませんかね。



この投稿にコメントする

削除パスワード

No.25786

Re:ファイル入出力と配列
投稿者---がりんしゃ(2006/01/29 15:40:46)


>完結されたような印象を受けますが、本当に大丈夫ですか?
>提示されたソースでは fputs() を使用しておらず、十中八九「不可」になると思うのですが。。。
>その時に「だめでした、アドバイスおねがいします。」ってことになりませんかね。

正直、大丈夫ではありません。fgets,fputsを使えという指示の他に、サンプルソースを渡されておりまして、そのソースに手を加えて作らなければならないので、上で書いたようなものだけではダメだと思います。

とろりさんのおっしゃられたようにfputsも使ってないのでこのまま提出すると不可になると思います。が、そこまで聞くと丸投げになりそうな感がありましたので、ありがとうございましたと完結させ何とか自分で考えてみてます・・・




この投稿にコメントする

削除パスワード

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