掲示板利用宣言

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

 私は

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

掲示板2

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

No.26040

ファイル出力について
投稿者---yocchi(2006/02/09 15:54:24)


以下に示すようなソースを書いてみたのですが、ファイル名を
例えばtest.txt, test_1.text, test_2.txt...などというように、連番で出力していくというようなことは可能なのでしょうか。"test.txt"という名称をどのように変えたらよいのか困っています。初心者の私ではどうしたら良いのか分かりません。ご教授、よろしくお願いします。

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

#define ERROR     0
#define NORMAL_END  1

int main(void)
{
  int judge = NORMAL_END;

  FILE *file=NULL;
  char *sp[105];
  int n;

  sp[0] = "P";
          ....
  sp[105] = " }"; 



  if((file=fopen("test.txt","a"))==NULL)
    {
      printf("file open error\n");
      judge=ERROR;
      goto MEMORY_FREE;
    }
  for(n=0;n<=105;n++)
  { 
  fprintf(file,"%s\n", sp[n]);
  }   
    MEMORY_FREE:
    if(file!=NULL) 
      {fclose(file);}
    return(judge);

}




この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:ファイル出力について 26041 nop 2006/02/09 16:48:28
<子記事> Re:ファイル出力について 26042 円零 2006/02/09 16:54:24


No.26041

Re:ファイル出力について
投稿者---nop(2006/02/09 16:48:28)


>以下に示すようなソースを書いてみたのですが、ファイル名を
>例えばtest.txt, test_1.text, test_2.txt...などというように、連番で出力していくというようなことは可能なのでしょうか。

sprintf()でファイル名文字列を生成すればいい。


この投稿にコメントする

削除パスワード

No.26042

Re:ファイル出力について
投稿者---円零(2006/02/09 16:54:24)


fopenの引数にリテラル文字列でファイル名を渡すのをやめにして、
sprintfか何かで作った文字列を渡せば良いでしょう。


この投稿にコメントする

削除パスワード

No.26043

Re:ファイル出力について
投稿者---yocchi(2006/02/09 17:08:41)


>fopenの引数にリテラル文字列でファイル名を渡すのをやめにして、
>sprintfか何かで作った文字列を渡せば良いでしょう。

ご返信ありがとうございます。
例えば、次のようにしてみました。

  int locate;

  srand( (unsigned)time(NULL) );    // 乱数の種をシステム時間に設定
  locate = rand() % 70;    // 剰余で余りが0〜69に設定される
........................
  sprintf(sp[43], "%d", locate);


このようにすると、「値が割り当てられていないローカルな変数 'sp' に対して参照が行われました。」というエラーになるのですが、これは*sp[43]にlocateが入っていないのでしょうか。また別の質問になってしまい申し訳ないですが、教えて頂けませんか。よろしくお願いします。


この投稿にコメントする

削除パスワード

No.26044

Re:ファイル出力について
投稿者---nop(2006/02/09 17:50:59)


> sprintf(sp[43], "%d", locate);

変数「sp」の定義は?
って言うか、文字列の勉強から始めましょう。


この投稿にコメントする

削除パスワード

No.26045

Re:ファイル出力について
投稿者---yocchi(2006/02/09 18:00:25)


>> sprintf(sp[43], "%d", locate);
>
>変数「sp」の定義は?

連番での出力はお陰様でできました。
ありがとうございました。
変数「sp」の定義ですが、
char *sp[105];
のように定義しています。



この投稿にコメントする

削除パスワード

No.26046

Re:ファイル出力について
投稿者---kz3(2006/02/09 18:04:58)


>  int locate;
>
>  srand( (unsigned)time(NULL) );    // 乱数の種をシステム時間に設定
>  locate = rand() % 70;    // 剰余で余りが0〜69に設定される
>........................
>  sprintf(sp[43], "%d", locate);
>
>このようにすると、「値が割り当てられていないローカルな変数 'sp' に対して参照が行われました。」というエラーになるのですが、これは*sp[43]にlocateが入っていないのでしょうか。

ポインタ sp[43] が示す領域がしっかりと確保されているのでしょうか?

char *sp[105]; sp[0] = "P"; /* ... は何?プログラム中で sp[43] を使用するなら sp[43] を設定しているコードを載せるべき */ sp[105] = " }" /* こういう間違い初心者さん多いですねーー; */
char *sp[105]; と宣言しただけではポインタ変数のための領域はメモリに確保されるけど ポインタ変数はでたらめな領域を指していますよね。 ...が省略を意味するものだとして sp[43] を以下のように sp[43] = "HELLO"; と文字列リテラルで初期化しているとする。 ( sp[0] と sp[105] をリテラルで初期化しているから ) とりあえず sp[43] は有効な領域を指すポインタなので sprintf(sp[30], "%3d", locate); なんて書いたら文法は合ってるかも知れないけどエラーが出るかもです。 文字列リテラルが書き込み禁止領域に配置されているかも知れないからです。




この投稿にコメントする

削除パスワード

No.26048

Re:ファイル出力について
投稿者---kz3(2006/02/09 18:10:35)


あ、解決ですかorz
もしよければ解決コードを添えてください。
( sp の行方が気になる )


この投稿にコメントする

削除パスワード

No.26049

Re:ファイル出力について
投稿者---yocchi(2006/02/09 18:28:22)


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

#define ERROR     0
#define NORMAL_END  1


int main(void)
{ 
  int i, n, locate;
  int judge = NORMAL_END;
  FILE *file=NULL;
  char *sp[105];
  char str[50];

  for(i=0; i<10; i++)
  { 
    sprintf(str, "test_%d.txt", i);

    srand( (unsigned)time(NULL) );   // 乱数の種をシステム時間
    locate = rand() % 70;    // 剰余で余りが0〜69に設定される
 
    sp[0] = "PHANTOM{";
        //sp[1]からsp[104]まで省略
    sp[105] = " }"; 

//sp[43]は上では何も定義していません
    sprintf(sp[43], "%d", locate);
 
    if((file=fopen(str,"a"))==NULL)
      {
        printf("file open error\n");
        judge=ERROR;
        goto MEMORY_FREE;
      }
    for(n=0;n<=105;n++)
    { 
      fprintf(file,"%s", sp[n]);
    } //n loop end
  } //i loop end
    MEMORY_FREE:
    if(file!=NULL) 
      {fclose(file);}
    return(judge);
  
}



上がソースです。省略してしまい申し訳ありませんでした。
回答にあった文章から質問ですが、
sp[105] = " }"
この文は何がおかしいのでしょうか。
確かにテキストファイルを見ると「・7」と変換されています。

また、
sprintf(sp[43], &quot;%d&quot;, locate);
の文が書き込み禁止領域となっている可能性があるとおっしゃいましたが、これを書き込み可能な領域へと変更することはできるのですか?
malloc関数などを使えば良いのですか?





この投稿にコメントする

削除パスワード

No.26047

Re:ファイル出力について
投稿者---円零(2006/02/09 18:09:01)


別の質問になるのはまだしも、「例えば」で別の話を始めるのはどうかという気が。

>これは*sp[43]にlocateが入っていないのでしょうか。
いや、入ってますよ。ただし、入れてはいけない場所に。

sprintfは作成した文字列をどこに収めたらいいのか知るためにsp[43]を参照します。
しかしsp[43]は初期化もされておらず、値の代入もされていません。
勿論、ここでやろうとしている操作がsp[43]に何かを入れるものならばそれで問題ありませんが、
残念ながら今値を入れようとしているのはsp[43]自身ではなくsp[43]が示すメモリ上のとある領域です。
sp[43]がわけのわからない場所を示している状態(初期化してませんから)でそんなことをしてはいけません。

今回の場合は、sp[105][3];のように二次元配列で宣言すればいいでしょう。


この投稿にコメントする

削除パスワード

No.26050

Re:ファイル出力について
投稿者---yocchi(2006/02/09 19:17:36)



>残念ながら今値を入れようとしているのはsp[43]自身ではなくsp[43]が示すメモリ上のとある領域です。
>sp[43]がわけのわからない場所を示している状態(初期化してませんから)でそんなことをしてはいけません。
>
>今回の場合は、sp[105][3];のように二次元配列で宣言すればいいでしょう。
sp[43]="5";と宣言する場合と
sprintf(sp[43], "%d", locate);
と宣言する場合とでは何が違うのでしょうか。
後者はsp[43]のアドレスのメモリ領域のどこかに"5"が入るということでしょうか。すみませんが、教えていただけますか?


この投稿にコメントする

削除パスワード

No.26051

Re:ファイル出力について
投稿者---iijima(2006/02/09 20:08:56)


> sp[43]="5";と宣言する場合と
> sprintf(sp[43], "%d", locate);
> と宣言する場合とでは何が違うのでしょうか。

(1) sp[43]="5";
文字列リテラル"5"をどこかのメモリ領域に確保し、その場所を指すポインタの値を
sp[43]に代入する。

(2) sprintf(sp[43], "%d", locate);
sp[43]が指している領域を、locateの値を変換した文字列(locate=5なら"5")に書
き換える。

(1)の後、sp[43]が指す領域は文字列リテラルですから書き換えてはいけません。
(2)をする場合は、sp[43]が、書き換え可能で、かつ、書き換え後の文字列を格納す
るのに十分なサイズの領域を指していなければなりません。

なお、(1)は代入、(2)は関数呼び出しであって、どちらも「宣言」とは言いません。



この投稿にコメントする

削除パスワード

No.26053

解決致しました
投稿者---yocchi(2006/02/09 20:52:38)


ようやくみなさんの言っていることが理解できました。
sp[43]の指すアドレスが直接locateの値に変換されていたのですね。
データが指す意味を取り違えていました。

どうもありがとうございました。
ちなみに以下のように修正しました。
char s[20];
sprintf(s, "%d", locate);
sp[43] = s;


この投稿にコメントする

削除パスワード

No.26062

Re:解決致しました
投稿者---kz3(2006/02/10 03:20:18)


> ようやくみなさんの言っていることが理解できました。

# どう解決したのか教えて欲しい;;( 個人的に )

まだまだ不十分なところ( 意図不明なところ )があったりなので話を続けますが・・・

まず配列要素 n 個の添え字は 0 から n-1 ということを思い出して欲しい。
( 以下 sp[105] のままで話を進めますが適宜読み替えてください。 )
結局何がやりたいのかというと、ファイルには

PHANTOM{ 13 42 65 34 22 }
というテキストデータを順次ファイルに書き出したいということでしょうか。 for( i=0; i<10 ; i++ ) { /* 前省略 */ sp[0] = "PHANTOM{"; //sp[1]からsp[104]まで省略 sp[105] = " }"; /* 後省略 */ } i ループ中で sp[0] と sp[105] の値を設定していますが、 これはほとんど無駄なのでループ外で設定するべきだと思います。 for( n=0 ; n<=105 ; n++ ) { fprintf( file , "%s" , sp[n] ); } //n loop end 今使っているのは sp[0] と sp[43] と sp[105] だけですよね。 出力したファイルにゴミは書き出されていないのかな。 書き出されていなくても( たまたまそこが'\0'だっただけの話 ) 3つしかポインタを使っていないのに105個も要素を確保するのは無駄ではないですか? for( i=0; i<10 ; i++ ) { /* ファイル名 str の設定( 省略 ) */ if(( file = fopen( str , "a" )) == NULL ) { printf( "file open error\n" ); judge=ERROR; goto MEMORY_FREE; } /* 出力( 省略 ) */ } MEMORY_FREE: if( file != NULL ) { fclose( file ); } 一度に開けるファイルの数は limits.h 内の OPEN_MAX で定義されています。 ( limits.h 内で別のファイルをインクルードして場合はそちらに ) 今は無制限に開こうとしているのですが、 問題はそれよりもファイルを1つしかクローズしていない点です。 ループ中でファイルを処理するならそのループ内でオープン・クローズで閉じるか、 ファイルポインタの配列を使ってループを抜けてから NULL でない要素をクローズするか しなければなりません。



この投稿にコメントする

削除パスワード

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