掲示板利用宣言

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

 私は

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

掲示板2

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

No.27563

関数化
投稿者---浅瀬(2006/07/06 16:44:37)


関数化する練習をしています。

#include <stdio.h>
#define MAXLEN 256

int main(int argc, char *argv[]){
  
  FILE *fp;
  char str[MAXLEN];
  
  if((fp = fopen(argv[1], "r")) == NULL){
    printf("file open error\n");
    exit(99);
  }
  
  while((fgets(str, sizeof(str), fp)) != NULL){
    printf("%s", str);
  }
  
  fclose(fp);
  
}

とりあえず、上のプログラムを、
1,ファイルをオープンする。
2,ファイルを読み込み、表示する。
3,ファイルをクローズする。
という風に分け、関数化しようと考えましたが、関数間のファイルポインタ(?)の受け渡しが良くわかりません。

いちを、自分なりに(苦し紛れ!?)に以下のようにしてみました。

#include <stdio.h>
#define MAXLEN 256

int open_file(int fp, char filename[]);
int read_file(int fp);
void close_file(int fp);

int main(int argc, char *argv[]){
  
  FILE *fp;
  
  fp = open_file(fp, argv[1]);
  
  fp = read_file(fp);
  
  close_file(fp);

}

int open_file(int fp, char filename[]){
  
  if((fp = fopen(filename, "r")) == NULL){
    printf("file open error\n");
    exit(99);
  }
  return fp;
}

int read_file(int fp){
  
  char str[MAXLEN];
  
  while((fgets(str, sizeof(str), fp)) != NULL){
    printf("%s", str);
  }
  return fp;
}

void close_file(int fp){
  
  fclose(fp);
  
}

これだと期待どおりに実行はされているように見えましたが、warningが出ていますので、きちんとした書き方ではないと思います。

どのようにすればよいかご教授お願いします。

warning 内容
 In function `main':
12:warning: passing arg 1 of `open_file' makes integer from pointer without a cast
12:warning: assignment makes pointer from integer without a cast
14:warning: passing arg 1 of `read_file' makes integer from pointer without a cast
14:warning: assignment makes pointer from integer without a cast
16:warning: passing arg 1 of `close_file' makes integer from pointer without a cast
 In function `open_file':
22:warning: assignment makes integer from pointer without a cast
22:warning: comparison between pointer and integer
 In function `read_file':
35:warning: passing arg 3 of `fgets' makes pointer from integer without a cast
 In function `close_file':
43:warning: passing arg 1 of `fclose' makes pointer from integer without a cast

実行環境:SLES 9 FP03
コンパイラ:cygwin gcc



この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:関数化 27564 ruby 2006/07/06 16:46:56
<子記事> Re:関数化 27571 shu 2006/07/06 21:29:48


No.27564

Re:関数化
投稿者---ruby(2006/07/06 16:46:56)


ファイルを扱うための関数の型や戻り値が、どうしてint型なのでしょうか?


この投稿にコメントする

削除パスワード

No.27566

Re:関数化
投稿者---浅瀬(2006/07/06 17:24:32)


>ファイルを扱うための関数の型や戻り値が、どうしてint型なのでしょうか?
はじめは、

#include <stdio.h>
#define MAXLEN 256

void open_file(FILE *fp, char filename[]);
void read_file(FILE *fp);
void close_file(FILE *fp);

int main(int argc, char *argv[]){
  
  FILE *fp;
  
  open_file(fp, argv[1]);
  
  read_file(fp);
  
  close_file(fp);

}

void open_file(FILE *fp, char filename[]){
  
  if((fp = fopen(filename, "r")) == NULL){
    printf("file open error\n");
    exit(99);
  }
}

void read_file(FILE *fp){
  
  char str[MAXLEN];
  
  while((fgets(str, sizeof(str), fp)) != NULL){
    printf("%s", str);
  }
}

void close_file(FILE *fp){
  
  fclose(fp);
  
}

と考えたのですが、これだと関数間でファイルポインタの受け渡しができませんでした。
ファイルポインタをファイルポインタで受け取って扱えば、ポインタなので、渡した方のファイルポインタにも反映されると思ったのですが・・・

いろいろ試して、唯一int型で動いたので動いたソースを載せました。
(アドレスだからint型でもfgetsとかできるのかなぁと・・・)




この投稿にコメントする

削除パスワード

No.27567

Re:関数化
投稿者---kafuka(2006/07/06 17:48:18)


> int open_file(int fp, char filename[]);
rubyさんが指摘さている通り、引数・戻り値の型をファイルポインタと合わせてやればよろしいかと。
ただこの場合、引数にファイルポインタを指定する必要がなくなりますけど。。。


----- 参考(になるかなぁ) -----
#include <stdio.h>
#include <string.h>

#define M_READ  0x01
#define M_WRITE 0x02


int U_OpenFile(FILE** fp, char* filename, int mode)
{
    char strmode[4];
    memset(strmode, '\0', sizeof(strmode));

    if (mode & M_READ)
        strcat(strmode, "r");

    if (mode & M_WRITE)
        strcat(strmode,"w");

    *fp = fopen(filename, strmode);
    if (fp == NULL) {
        printf("file open error. %s\n", filename);
        return -1;
    }

    return 0;
}

int U_ReadFile(FILE* fp)
{
    char strbuf[256];

    if (fp == NULL) {
        printf("file pointor NULL.\n");
        return -1;
    }

    while (NULL != fgets(strbuf, sizeof(strbuf),fp))
        printf("%s", strbuf);

    return 0;
}

void U_CloseFile(FILE* fp)
{
    if (fp != NULL) {
        fclose(fp);
    }
}

int main(int argc, char* argv[])
{
    int rtncd;
    FILE *fp;

    //
    rtncd = U_OpenFile(&fp, "data.txt", M_READ);
    if (rtncd < 0) {
        printf("function error. [U_OpenFile]\n");
        return -1;
    }

    //
    rtncd = U_ReadFile(fp);
    if (rtncd < 0) {
        printf("function error. [U_ReadFile]\n");
        return -1;
    }

    //
    U_CloseFile(fp);

    return 0;
}




この投稿にコメントする

削除パスワード

No.27568

Re:関数化
投稿者---kafuka(2006/07/06 18:03:38)



> if (mode & M_READ)
>  strcat(strmode, "r");
> if (mode & M_WRITE)
>  strcat(strmode,"w");

この辺ちょっとおかしい。
ビット演算でモード指定できるようにしたつもりだったけど、
これだと "wr" なんてことになってしまう。。。まぁいいや。


この投稿にコメントする

削除パスワード

No.27569

Re:関数化
投稿者---REE(2006/07/06 18:40:23)


>ファイルポインタをファイルポインタで受け取って扱えば、ポインタなので、渡した方のファイルポインタにも反映されると思ったのですが・・・

初心者にありがちな勘違いですね。
ポインタを渡せば、ポインタの指す先の変更が反映されますが、
渡したポインタ自身の変更は反映されません。

ポインタの変更を反映したければ、ポインタを指すポインタを渡す必要があります。
(kafukaさんの投稿参照)



この投稿にコメントする

削除パスワード

No.27570

Re:関数化
投稿者---ruby(2006/07/06 21:26:20)


>と考えたのですが、これだと関数間でファイルポインタの受け渡しができませんでした。
>ファイルポインタをファイルポインタで受け取って扱えば、ポインタなので、渡した方のファイルポインタにも反映されると思ったのですが・・・

修正版プログラムは他の方々の投稿を参考にしていただくとして…。

>いろいろ試して、唯一int型で動いたので動いたソースを載せました。

動いたとは、にわかに信じがたいです。
「仮に」動いたのだとしても、それは「たまたまそうなった」に過ぎない、
というレベルです。


この投稿にコメントする

削除パスワード

No.27571

Re:関数化
投稿者---shu(2006/07/06 21:29:48)


//
//	窮屈目に
//

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

//
FILE *file_open_check(const char *fname, const char *mode);
FILE *file_stream_io(FILE *fp, FILE *fp2);
void file_close(FILE *fp);

////////////////////////////////
int main(int argc, char *argv[])
{
    file_close(file_stream_io(file_open_check(argv[1], "r"), stdout));
    return 0;
}

//
FILE *file_open_check(const char *fname, const char *mode)
{
    FILE *fp;
    
    if ((fp = fopen(fname, mode)) == NULL) {
        perror("file open error");
        exit(1);
    }
    return fp;
}
//
FILE *file_stream_io(FILE *fp, FILE *fp2)
{
    char buf[256];
    
    while (fgets(buf, sizeof(buf), fp))
        fputs(buf, fp2);
    return fp;
}
//
void file_close(FILE *fp)
{
    if (fp)
        fclose(fp);
}



この投稿にコメントする

削除パスワード

No.27576

Re:関数化
投稿者---浅瀬(2006/07/07 10:36:36)


レス遅くなりました。

shuさん、kafukaさん、ソースの提示ありがとうございました。
正直、私には難しく、全てを理解できたわけではありませんが、勉強させていただきました。

またREEさんのコメントからもう一度「ポインタのポインタ」を読み直し、以下のソースまでたどりつきました。

間違いがありましたらお願いします。

#include <stdio.h>
#define MAXLEN 256

void open_file(FILE **fpp, char filename[]);
void read_file(FILE **fpp);
void close_file(FILE **fpp);

int main(int argc, char *argv[]){
  
  FILE *fp;
  
  open_file(&fp, argv[1]);
  
  read_file(&fp);
  
  close_file(&fp);

}

void open_file(FILE **fpp, char filename[]){
  
  if((*fpp = fopen(filename, "r")) == NULL){
    printf("file open error\n");
    exit(99);
  }
}

void read_file(FILE **fpp){
  
  char str[MAXLEN];
  
  while((fgets(str, sizeof(str), *fpp)) != NULL){
    printf("%s", str);
  }
}

void close_file(FILE **fpp){
  
  fclose(*fpp);
  
}

また、とんちんかんな事を言っているかもしれませんが、
rudyさんのコメント、
>>いろいろ試して、唯一int型で動いたので動いたソースを載せました。
>動いたとは、にわかに信じがたいです。
>「仮に」動いたのだとしても、それは「たまたまそうなった」に過ぎない、というレベルです。
を受けて、私なりに考えてみました。

int a = 10;
int *ap = &a;
とした場合、
printf("%d", *ap);
では、apの持ってる値(aのアドレス)の中身(10)を参照して、
printf("%d", ap);
では、apの持ってる値(aのアドレス)を参照しますよね?

という事は、
FILE *fp"を宣言し、使う時は"*fp"ではなく"fp"だからアドレスを使っているものだと考え、
そうするとアドレスの受け渡しができればよいわけですから、
int型で動くことも十分考えられないのでしょうか?



この投稿にコメントする

削除パスワード

No.27577

Re:関数化
投稿者---ruby(2006/07/07 11:47:18)


>FILE *fp"を宣言し、使う時は"*fp"ではなく"fp"だからアドレスを使っているものだと考え、
>そうするとアドレスの受け渡しができればよいわけですから、
>int型で動くことも十分考えられないのでしょうか?

「いろいろ試して唯一int型で動いた」という記述がありました。
これは、お使いの処理系がたまたま sizeof(FILE *) == sizeof(int)
であるからだと思います。
世の中の処理系がすべてそうであるとは限りません。そうでない処理系で
動かそうとすると破綻すると思います。

FILE *型をint型で受けているために、コンパイラからの警告という形で
弊害が出ています。
関数の引数でFILE *型が来ることを想定しているのですから、
ここは素直にFILE *型の変数を使うべきでしょう。

また、(int型の)fpをNULLと比較している箇所がありますが、
これに対する警告をなくすためにはどうしますか?NULLのかわりにゼロを
持ってきますか?残念なことに、「NULL == ゼロ」とは限らないのです。
よって、fpとゼロとの比較は真になる場合もあるでしょうし、
偽になってしまう場合もあるでしょう。結局、「どういう実行結果になるかは
処理系しだい」となってしまうのではないかと思います。


この投稿にコメントする

削除パスワード

No.27578

Re:関数化
投稿者---iijima(2006/07/07 14:14:17)


> 間違いがありましたらお願いします。

exit関数を使うのに必要なライブラリヘッダファイル<stdlib.h>がインクルードされていません。
エラーとしない処理系もあるかも知れませんが、必要なヘッダはインクルードするのが基本です。

それから、間違いではありませんが、read_file関数とclose_file関数の引数はポインタのポインタ
にしなくても良いです。

open_fileは、fopen関数によってFILEポインタの値を書き換えるため、FILEポインタを指すポインタ
を渡さなくてはならないのに対し、read_fileとclose_fileはFILEポインタが指すファイル構造体を操作
するだけだからです。


この投稿にコメントする

削除パスワード

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