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

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

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

2回答

989閲覧

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

AbeshiGF

総合スコア2

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2020/06/08 09:52

前提・実現したいこと

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セキュリティ遮断がかかります ファイル自体は出力されているので大丈夫かと思っていますが自動保護を無効にしても動くので気になっています 考えてはみたのですが、結局わからなかったので質問させていただきます 解決方法か、なにか解決につながるような考え方や、デバッグ方法など教えていただければ幸いです

該当のソースコード

Python

1#include <stdio.h> 2#include <string.h> 3#include <stdlib.h> 4#include <math.h> 5#include <time.h> 6#include <unistd.h> 7 8size_t get_file_size(const char *pFilename) 9{ 10 FILE *fp=NULL; 11 size_t nRet=0; 12 if (pFilename!=NULL) { 13 if ((fp=fopen(pFilename,"rb"))!=NULL) { 14 fseek(fp,0,SEEK_END); 15 nRet=ftell(fp); 16 fseek(fp,0,SEEK_SET); 17 nRet-=ftell(fp); 18 fclose(fp); 19 } 20 } 21 return (nRet); 22} 23 24float correlation(float f[], float g[], int N) 25{ 26 float Rt = 0; 27 for(int n = 0; n < N; n++) 28 { 29 Rt = Rt + f[n] * g[n]; 30// printf("%.20f\n", Rt); 31 } 32 33 return Rt; 34} 35 36int main(void) 37{ 38 FILE *fp=NULL; 39 float *p=NULL; 40 char pFilename[]="correlation.float"; 41 size_t sz=0; 42 int nNum=0; 43 int i; 44 float *f = NULL; 45 float *g = NULL; 46 float *Rt = NULL; 47 48 sz=get_file_size(pFilename); 49 nNum=sz/sizeof(float); 50// printf("%d %d", sz, nNum); //確認用コード 51 52 53 if ((fp=fopen(pFilename,"rb"))==NULL) { 54 goto Release; 55 printf("ファイルが空です\n"); 56 } 57 if ((p=(float*)malloc(nNum*sizeof(float)))==NULL) { 58 goto Release; 59 printf("ファイル内のデータサイズが不正です\n"); 60 } 61 62 remove("function.float"); 63 FILE *fp3 = NULL; 64 if ((fp3=fopen("function.float","rb"))==NULL) { 65 printf("正常\n"); 66 } 67 fclose(fp3); 68 69 70 71 for(i = 0; i < nNum; i++) 72 { 73 fread(p,sizeof(float),nNum,fp); 74 f = (float*)malloc(nNum*sizeof(float)); 75 g = (float*)malloc(nNum*sizeof(float)); 76 Rt = (float*)malloc(sizeof(float)); 77 fseek(fp,0,SEEK_SET); 78 fread(f,sizeof(float),nNum,fp); 79 80 fseek(fp,sizeof(float)*(i+1),SEEK_SET); 81 fread(g,sizeof(float),nNum-i,fp); 82 g[nNum-i] = f[i]; 83 84 /*for (int k=0;k<nNum;k++) 85 { 86 printf("%f %f\n", f[k], g[k]); //確認用コード 87 }*/ 88 89 Rt[0] = correlation(f, g, nNum); 90 Rt[0] = Rt[0] / (nNum + 1); 91 //printf("%.20f\n", Rt[0]); //確認用コード 92 FILE *fp2 = NULL; 93 fp2 = fopen("function.float", "ab"); 94 fwrite(Rt,sizeof(float),1,fp2); 95 free(f); 96 free(g); 97 free(Rt); 98 fclose(fp2); 99 } 100 101 //printf("%f %f\n", f[nNum - 1], g[nNum - 1]); //確認用コード 102 103 Release: 104 if (p!=NULL) { 105 free(p); 106 } 107 if (fp!=NULL) { 108 fclose(fp); 109 } 110 return (0); 111}

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

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

C

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

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

C

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

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


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

C

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

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


C

1fseek(fp,sizeof(float)*(i+1),SEEK_SET);//80行目 2fread(g,sizeof(float),nNum-i,fp);//81行目 3g[nNum-i] = f[i];//82行目 4この部分が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]にf0を入れようとしています。メモリの確保は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の登場するところを抜粋すると

C

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

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

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

C

1 float *f = NULL;//44行目 2//71行目からのforループに入って... 3 f = (float*)malloc(nNum*sizeof(float));//74行目 4 fseek(fp,0,SEEK_SET);//77行目 5 fread(f,sizeof(float),nNum,fp);//78行目 6 g[nNum-i] = f[i];//82行目 7 Rt[0] = correlation(f, g, nNum);//89行目 8 free(f);//95行目 9//forループの後 10 //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;じゃいけないんでしょうか?

投稿2020/06/09 00:25

thkana

総合スコア7703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

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

c

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

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

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

投稿2020/06/08 14:04

hope_mucci

総合スコア4447

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

AbeshiGF

2020/06/09 13:29

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

2020/06/09 13:53

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問