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

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

ただいまの
回答率

88.23%

ポインタ内の数値を一つずらして、別のポインタに代入するための処理について

解決済

回答 2

投稿

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

AbeshiGF

score 1

前提・実現したいこと

pythonで作成したfloatの数値が1000個入っているバイナリファイルを読み取り、
自己相関関数にかけ、出力された数値をまたバイナリファイルとして出力するプログラムです
自己相関関数であるため、fの数値を一つずらしてgに代入する処理をバイナリファイル内の個数(1000)回繰り返しています

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

問題はうまくfの数値を一つずらしてgに代入する処理ができていないことです
fseek(fp,0,SEEK_SET);
fread(f,sizeof(float),nNum,fp);

fseek(fp,sizeof(float)*(i+1),SEEK_SET);
fread(g,sizeof(float),nNum-i,fp);
g[nNum-i] = f[i];
この部分がfへの代入、gへ一つずらし代入という処理を行っています

途中の
for (int k=0;k<nNum;k++) 
{
  printf("%f %f\n", f[k], g[k]); //確認用コード
}
で中の配列がどのようになっているのかを確認してみたのですが、
うまく組めていないのか、gへの代入ができておらず、
0だけしか出力されていない状態です

関係ないかもしれませんが、このプログラムを動作させるとほぼ必ずNortonセキュリティ遮断がかかります
ファイル自体は出力されているので大丈夫かと思っていますが自動保護を無効にしても動くので気になっています


考えてはみたのですが、結局わからなかったので質問させていただきます
解決方法か、なにか解決につながるような考え方や、デバッグ方法など教えていただければ幸いです

該当のソースコード

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

size_t get_file_size(const char *pFilename)
{
  FILE *fp=NULL;
  size_t nRet=0;
  if (pFilename!=NULL) {
    if ((fp=fopen(pFilename,"rb"))!=NULL) {
      fseek(fp,0,SEEK_END);
      nRet=ftell(fp);
      fseek(fp,0,SEEK_SET);
      nRet-=ftell(fp);
      fclose(fp);
    }
  }
  return (nRet);
}

float correlation(float f[], float g[], int N)
{
    float Rt = 0;
    for(int n = 0; n < N; n++)
    {
        Rt = Rt + f[n] * g[n];
//        printf("%.20f\n", Rt);
    }

    return Rt;
}

int main(void)
{
  FILE   *fp=NULL;
  float  *p=NULL;
  char   pFilename[]="correlation.float";
  size_t sz=0;
  int    nNum=0;
  int    i;
  float  *f = NULL;
  float  *g = NULL;
  float  *Rt = NULL;

  sz=get_file_size(pFilename);
  nNum=sz/sizeof(float);
//  printf("%d %d", sz, nNum); //確認用コード


  if ((fp=fopen(pFilename,"rb"))==NULL) {
    goto Release;
    printf("ファイルが空です\n");
  }
  if ((p=(float*)malloc(nNum*sizeof(float)))==NULL) {
    goto Release;
    printf("ファイル内のデータサイズが不正です\n");
  }

  remove("function.float");
  FILE  *fp3 = NULL;
  if ((fp3=fopen("function.float","rb"))==NULL) {
    printf("正常\n");
  }
  fclose(fp3);



  for(i = 0; i < nNum; i++)
  {
    fread(p,sizeof(float),nNum,fp);
    f = (float*)malloc(nNum*sizeof(float));
    g = (float*)malloc(nNum*sizeof(float));
    Rt = (float*)malloc(sizeof(float));
    fseek(fp,0,SEEK_SET);
    fread(f,sizeof(float),nNum,fp);

    fseek(fp,sizeof(float)*(i+1),SEEK_SET);
    fread(g,sizeof(float),nNum-i,fp);
    g[nNum-i] = f[i];

    /*for (int k=0;k<nNum;k++) 
    {
      printf("%f %f\n", f[k], g[k]); //確認用コード
    }*/

    Rt[0] = correlation(f, g, nNum);
    Rt[0] = Rt[0] / (nNum + 1);
    //printf("%.20f\n", Rt[0]); //確認用コード
    FILE *fp2 = NULL;
    fp2 = fopen("function.float", "ab");
    fwrite(Rt,sizeof(float),1,fp2);
    free(f);
    free(g);
    free(Rt);
    fclose(fp2);
  }

  //printf("%f %f\n", f[nNum - 1], g[nNum - 1]); //確認用コード

 Release:
  if (p!=NULL) {
    free(p);
  }
  if (fp!=NULL) {
    fclose(fp);
  }
  return (0);
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

0

私の手元では、質問のプログラムはsegmentation faultで落ちます。

 remove("function.float");
 FILE *fp3 = NULL;
 if ((fp3 = fopen("function.float", "rb")) == NULL) {
   printf("正常\n");
 }
 fclose(fp3);


のところ、出力ファイルを消しているのでfpがNULLでfclose(fp)に入りますから。せめて

 if ((fp3 = fopen("function.float", "rb")) == NULL) {
   printf("正常\n");
 }else
 fclose(fp3);


とかじゃないでしょうか。(ファイルが消えてなかった時にどうするかはまた別の話として)


Nortonセキュリティ遮断がかかります

//1000回のforループ中で
    FILE *fp2 = NULL;
    fp2 = fopen("function.float", "ab");
<略>
    fclose(fp2);


ループ中で出力用ファイルを一回ごとにオープン/クローズしているので、この異常に頻繁なファイル操作がマルウェア対策ソフトを反応させているのではないか、と疑いますがどうでしょう。特別な理由がなければ、オープン/クローズはループの外で行えばよいのではないかと思います。


fseek(fp,sizeof(float)*(i+1),SEEK_SET);//80行目
fread(g,sizeof(float),nNum-i,fp);//81行目
g[nNum-i] = f[i];//82行目
この部分がfへの代入、gへ一つずらし代入という処理を行っています


デバッグ方法...ですか。プログラムの動作を逐一追ってみてはいかがでしょうか。

iが0の時、
80行目でファイルポインタはindex 1のデータ(以降データ[index]と表記します)を指します。
81行目で、ファイルからnNum-0=nNum個のデータを読み出してg[0]から格納しようとします...
ファイルに入っているのは全部でnNum個のデータです。ファイルポインタを1データ分ずらしたらそれ以降のデータはnNum-1個しかありません。nNum個のデータを読み込もうとしたら、帳尻が合いません。
ファイルが途中で終わってしまうので、g[nNum-1]のデータは変更されません。mallocで確保されたデータの内容は「不定(プログラムが実行されるまで確定しない)」ですから、g[nNum-1]のデータは不定のまま。何が入っているかわかりません。
82行目で、g[nNum]にf[0](つまりデータ[0])を入れようとしています。メモリの確保はmalloc(nNum*sizeof(float))で行っていますから、g[nNum]は確保したメモリ領域の外です。アクセスしてはいけません。

(ちょっと飛ばして)iが3の時、
80行目でファイルポインタはindex 4のデータを指します。
81行目でファイルからnNum-3個のデータを読み出そうとしますが先程と同様途中でEOF。g[nNum-4]以降は不定のままになります。
82行目で、g[nNum-3]にf[3]が入ります。
結果、
g[0]にデータ[4], g[1]にデータ[5], ..., g[nNum-5]にデータ[nNum-1],
g[nNum-4]は不定, g[nNum-3]はデータ[3], g[nNum-2]とg[nNum-1]は何も操作していないので不定
ということになります。

これは、どうもよろしくないと思えますがいかがですか?
(gが0になる、という症状と合わないのは気になるところですが。そもそものデータが0.00なわけではないですよね?)


質問の主題から離れますが、プログラムの目的とかは置いといて、プログラムの「構造」を眺めた時に

変数pの登場するところを抜粋すると

  float *p = NULL;//39行目
  if ((p = (float *)malloc(nNum * sizeof(float))) == NULL) {//57行目
//71行目からのforループに入って...
    fread(p, sizeof(float), nNum, fp);//73行目
//forループの後
  if (p!=NULL) {//105行目
    free(p);//106行目


メモリ確保して、そこにファイルからデータを読み込んでいますが、そのデータは一切使われないまま領域が解放されています。変数pと確保した領域の存在理由はなんでしょう?

同様に、変数fについて抜粋すると、

  float  *f = NULL;//44行目
//71行目からのforループに入って...
    f = (float*)malloc(nNum*sizeof(float));//74行目
    fseek(fp,0,SEEK_SET);//77行目
    fread(f,sizeof(float),nNum,fp);//78行目
    g[nNum-i] = f[i];//82行目
    Rt[0] = correlation(f, g, nNum);//89行目
    free(f);//95行目
//forループの後
  //printf("%f %f\n", f[nNum - 1], g[nNum - 1]); //確認用コード 101行目


74行目、77行目にはループで変化する要素は含まれていません。78~89行目ではfの要素を変化させません。つまり、fはループが回るあいだ、全く同じデータを読み込んでは捨てられています。毎回読み直す必要があるのでしょうか。
また、101行目は、f(gも)に確保された領域は解放されたあとになるので、ここでアクセスしてはいけません(現状ではコメントアウトされていますが)。

もひとつ、Rt = (float *)malloc(sizeof(float));ってのは、float Rt;じゃいけないんでしょうか?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

fにもgにもmallocで新しい配列領域を作る必要はないです。
pにデータを読み込んだ後、fにp(読み込んでたデータの先頭アドレス)、gにf+1(読み込んだデータの次のfloatのアドレス)を渡してやればそれで済みます。

// pにfreadした後
    f = p;
    g = f+1;
    // とりあえずfとgを順番に出力してみる
    for(i=0;i<999;i++){
        printf("%f %f\n", *f,*g);
        ++f,++g;  // 同時にアドレスを+1することで参照先をずらしていく
    }


gが1001番目を読まないようにだけ注意すること。

fとgの参照さえ片づけばあとは大丈夫かな?と思いますので、頑張ってください。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/06/09 22:29

    私の説明不足をお詫びします
    mallocで配列領域を確保する理由は、
    読み込む"correlation.float"の中身が1000個のデータであるとは限らないため、
    ファイルサイズに応じて配列領域を確保しています

    キャンセル

  • 2020/06/09 22:53

    別に中身が1000個だろうが5000兆個あろうがmallocで確保した領域を突き抜けないよう気を付けてねというだけで本質は変わりません。nNumで十分制御できるでしょう。

    キャンセル

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

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

関連した質問

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

  • トップ
  • Cに関する質問
  • ポインタ内の数値を一つずらして、別のポインタに代入するための処理について