質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.19%

C言語で構造体のデータをバイナリファイルに保存・読み込む方法

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 217

darakuzanmai

score 1

前提・実現したいこと

円の中心位置と半径を3セット入力し、半径の大きい順にソートしたものをバイナリに保存するプログラムと、保存されたバイナリを読み込んで中心位置が原点から近い順にソートして表示するプログラムを作りたいです。

発生している問題・エラーメッセージ

ファイルを読み込んで表示するときに、①で入力した値とは違うものが表示されてしまいます。
テキストファイルに保存したとき(fprintf,fscanfを使ったとき)は問題が起こらなかったので、fwriteやfreadの引数が間違っているのかなと思います。

該当のソースコード

①ファイルを保存するプログラム

#include <stdio.h>
#include <math.h>
struct circle
{
    double x;
    double y;
    double rad;
};
void swap(double *px,double *py)
{
    double tmp=*px;
    *px=*py;
    *py=tmp;
}
int main(void)
{
    int i,j;
    double num[3]={1,2,3};
    struct circle n[3];
    char str[50];
    FILE *fp;

    puts("3つの円の座標と半径を入力");
    for(i=0;i<3;i++)
    {
        printf("円%.0f\n",num[i]);
        printf("座標x="); scanf("%lf",&n[i].x);
        printf("座標y="); scanf("%lf",&n[i].y);
        printf("半径r="); scanf("%lf",&n[i].rad);
    }
    puts("半径の大きい順にソート\n");
    for(i=0;i<3;i++)
    {
        for(j=i+1;j<3;j++)
        {
            if(n[i].rad<n[j].rad)
            {
                swap(&num[i],&num[j]);
                swap(&n[i].x,&n[j].x);
                swap(&n[i].y,&n[j].y);
                swap(&n[i].rad,&n[j].rad);
            }
        }
    }
    for(i=0;i<3;i++)
        printf("円%.0f:(%.2f,%.2f),r=%.2f\n",num[i],n[i].x,n[i].y,n[i].rad);

    //ファイルに出力
    printf("ファイル名を入力:"); scanf("%s",str);
    fp=fopen(str,"wb");
    if(fp==NULL)
        printf("ファイル%sをオープンできませんでした。\n",str);
    else
    {
        printf("半径および中心位置を保存しました。\n");
        fwrite(n,sizeof(n),3,fp);
        fclose(fp);
    }
    return 0;
}


②ファイルを読み込んで表示するプログラム

#include <stdio.h>
#include <math.h>
struct circle
{
    double x;
    double y;
    double rad;
    double len;
};
void len_p(double x,double y,double *len)
{
    *len=sqrt(pow(x,2)+pow(y,2));
}
void swap(double *px,double *py)
{
    double tmp=*px;
    *px=*py;
    *py=tmp;
}
int main(void)
{
    int i,j;
    struct circle n[3];
    char str[50];
    FILE *fp;

    printf("ファイル名を入力:"); scanf("%s",str);
    if((fp=fopen(str,"rb"))==NULL)
        printf("ファイル%sをオープンできませんでした。\n",str);
    else
    {
        fread(n,sizeof(n),3,fp);
        for(i=0;i<3;i++)
        {
            printf("(%.2f,%.2f),r=%.2f\n",n[i].x,n[i].y,n[i].rad);
            len_p(n[i].x,n[i].y,&n[i].len);
        }
        puts("中心位置が原点から近い順にソート");
        for(i=0;i<3;i++)
        {
            for(j=i+1;j<3;j++)
            {
                if(n[i].len>n[j].len)
                {
                    swap(&n[i].x,&n[j].x);
                    swap(&n[i].y,&n[j].y);
                    swap(&n[i].rad,&n[j].rad);
                    swap(&n[i].len,&n[j].len);
                }
            }
        }
        for(i=0;i<3;i++)
            printf("(%.2f,%.2f),r=%.2f,距離%.2f\n",n[i].x,n[i].y,n[i].rad,n[i].len);
        fclose(fp);
    }
    return 0;
}

補足情報(FW/ツールのバージョンなど)

開発環境はwindows10のMinGWです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

check解決した方法

0

ファイルに保存するデータがx,y,radの3つなのに対し、②の構造体がx,y,rad,lenと4つになっていたのがエラーの原因かも知れないと思ったので修正してみました。
また、回答からsizeof(n)の部分をsizeof(*n)に直しました。
回答者さんありがとうございます。問題なく動作するようになりましたが、まだココがおかしいという点がありましたら指摘してください。

↓以下コード

#include <stdio.h>
#include <math.h>
struct circle
{
    double x;
    double y;
    double rad;
};
void swap(double *px,double *py)
{
    double tmp=*px;
    *px=*py;
    *py=tmp;
}
int main(void)
{
    int i,j;
    double num[3]={1,2,3};
    struct circle n[3];
    char str[50];
    FILE *fp;

    puts("3つの円の座標と半径を入力");
    for(i=0;i<3;i++)
    {
        printf("円%.0f\n",num[i]);
        printf("座標x="); scanf("%lf",&n[i].x);
        printf("座標y="); scanf("%lf",&n[i].y);
        printf("半径r="); scanf("%lf",&n[i].rad);
    }
    puts("半径の大きい順にソート\n");
    for(i=0;i<3;i++)
    {
        for(j=i+1;j<3;j++)
        {
            if(n[i].rad<n[j].rad)
            {
                swap(&num[i],&num[j]);
                swap(&n[i].x,&n[j].x);
                swap(&n[i].y,&n[j].y);
                swap(&n[i].rad,&n[j].rad);
            }
        }
    }
    for(i=0;i<3;i++)
        printf("円%.0f:(%.2f,%.2f),r=%.2f\n",num[i],n[i].x,n[i].y,n[i].rad);

    //ファイルに出力
    printf("ファイル名を入力:"); scanf("%s",str);
    fp=fopen(str,"wb");
    if(fp==NULL)
        printf("ファイル%sをオープンできませんでした。\n",str);
    else
    {
        printf("半径および中心位置を保存しました。\n");
        fwrite(n,sizeof(*n),3,fp);
        fclose(fp);
    }
    return 0;
}

#include <stdio.h>
#include <math.h>
struct circle
{
    double x;
    double y;
    double rad;
};
void len_p(double x,double y,double *len)
{
    *len=sqrt(pow(x,2)+pow(y,2));
}
void swap(double *px,double *py)
{
    double tmp=*px;
    *px=*py;
    *py=tmp;
}
int main(void)
{
    int i,j;
    struct circle n[3];
    double len[3];
    char str[50];
    FILE *fp;

    printf("ファイル名を入力:"); scanf("%s",str);
    if((fp=fopen(str,"rb"))==NULL)
        printf("ファイル%sをオープンできませんでした。\n",str);
    else
    {
        fread(n,sizeof(*n),3,fp);
        for(i=0;i<3;i++)
        {
            printf("(%.2f,%.2f),r=%.2f\n",n[i].x,n[i].y,n[i].rad);
            len_p(n[i].x,n[i].y,&len[i]);
        }
        puts("中心位置が原点から近い順にソート");
        for(i=0;i<3;i++)
        {
            for(j=i+1;j<3;j++)
            {
                if(len[i]>len[j])
                {
                    swap(&n[i].x,&n[j].x);
                    swap(&n[i].y,&n[j].y);
                    swap(&n[i].rad,&n[j].rad);
                    swap(&len[i],&len[j]);
                }
            }
        }
        for(i=0;i<3;i++)
            printf("(%.2f,%.2f),r=%.2f,距離%.2f\n",n[i].x,n[i].y,n[i].rad,len[i]);
        fclose(fp);
    }
    return 0;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

 fwrite(n,sizeof(n),3,fp);

sizeof(n)ってポインタのサイズですよ。
sizeof(*n)でいこう


ああちがうわ。sizeof(n) は配列全体のサイズになりますね
それだと、書き込みはともかく、読み出しのときにアクセス違反となりますな。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2021/01/22 15:14

    回答ありがとうございます!早速直してみます

    キャンセル

  • 2021/01/22 15:17

    回答修正

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.19%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る