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

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

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

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

Q&A

解決済

3回答

1537閲覧

C言語のポインタ渡しなど

sakas1231

総合スコア42

C

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

0グッド

1クリップ

投稿2017/01/26 03:11

fpaの参照しているfnameaファイルから500行2列の数字列を受け取り、posに保存してからそれをexpansionメソッドに代入して数値を変換してfnamebファイルに出力するというプログラムです。

C

1#include <stdio.h> 2 3//double (*expansion(double p[500][2]))[2]; 4void expansion(double x0[500][2]); 5int main(){ 6 int ret, i = 0; 7 FILE *fpa , *fpb; 8 char *fnamea = "data.csv"; 9 char *fnameb = "data2.csv"; 10 double pos[500][2]; 11 double x, y; 12 13 fpa = fopen(fnamea , "r"); 14 if(fpa == NULL){ 15 printf("ファイルが開けません"); 16 return -1; 17 } 18 fpb = fopen(fnameb , "w"); 19 if(fpb == NULL){ 20 printf("ファイルが開けません"); 21 return -1; 22 } 23 24 while((ret = fscanf(fpa, "%lf,%lf", &x , &y)) != EOF){ 25 pos[i][0] = x; 26 pos[i][1] = y; 27 i++; 28 } 29 expansion(pos); 30 31 for(i = 0; i < 500; i++){ 32 fprintf(fpb, "%lf,%lf\n", pos[i][0], pos[i][1]); 33 } 34 fclose(fpa); 35 fclose(fpb); 36} 37 38void expansion(double x0[500][2]) { 39 double H = 3.5; 40 double org = 50; 41 double dt = 0.1; 42 int nk = 20 , i = 0 , j = 0 , k = 0; 43 double vx[500][2] , x[500][2]; 44 for(i = 0; i < 500; i++){ 45 for(j = 0; j < 2; j++){ 46 vx[i][j] = H * x0[i][j]; 47 x[i][j] = x0[i][j] + org; 48 for(k = 0; k < nk; k++){ 49 x[i][j] += vx[i][j] * dt; 50 } 51 } 52 } 53 x0 = x; 54}

このようにするとエラーは吐かないのですが、出力結果がfnameaと同じ数字になってしまいます。
どうしてでしょうか、回答宜しくお願いします。

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

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

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

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

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

guest

回答3

0

ベストアンサー

x0 = x; では配列の中身はコピーされません。

以下のようにするか、x0 = x; の部分をループを使ってコピーするような処理にするなどではどうでしょうか。

c

1 2 x0[i][j] = x0[i][j] + org; 3 for(k = 0; k < nk; k++){ 4 x0[i][j] += vx[i][j] * dt; 5 } 6

投稿2017/01/26 03:21

編集2017/01/26 03:22
qt6hy

総合スコア149

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

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

sakas1231

2017/01/26 03:30

X0の指すアドレスをXの指すアドレスに書き換えることでX0とXが同じところを指す、という解釈をしていたのですがそこが違うということでしょうか
qt6hy

2017/01/26 03:40

expansion の引数としての x0 は仮の変数なので、代入しても元の関数の x0 が変わることはありません。 また、x 自体が expansion 内のローカル変数なので、適切にアドレスが変わるようにしていたとしても、既に存在しないアドレスを示すため、クラッシュします。
qt6hy

2017/01/26 03:41

ご存知だと思いますが、ポインタを書き換えたければ、ポインタのポインタを渡す必要があります。 ポインタの指し示す中身を変える場合 → ポインタを渡す ポインタ自体を変える場合 → ポインタのポインタを渡す
sakas1231

2017/01/26 04:29

>>expansion の引数としての x0 は仮の変数なので、代入しても元の関数の x0 が変わることはありません なるほど、仮変数の場合はそのようなことが出来ないのですね、肝に銘じておきます
sakas1231

2017/01/26 04:39

しかしその場合、一番はじめに回答として仰ったようにx0の値を直接変えたとしてもposには影響を及ぼさないのではないでしょうか?
qt6hy

2017/01/26 06:25

x0は配列へのアドレスを示す変数です。 そのアドレス自体は元の pos 配列を指し示しているので、中身を書き換えれば更新できます。 配列 pos が示すアドレスが 100 だとして、x0 も 100 だという事です。 pos が示すもの {100} x0 が示すもの {100} つまり、同じ 100 という場所を示していて、そこには配列の実体領域があるということです。
sakas1231

2017/01/26 09:13

なるほど、ということはx0=xとしてもx0の指してるアドレスがxになるだけでposは変化しない ということでしょうか? なんだかわかってきた気がします
qt6hy

2017/01/27 08:08

>なるほど、ということはx0=xとしてもx0の指してるアドレスがxになるだけでposは変化しない ということでしょうか? その通りです。
sakas1231

2017/01/29 14:57

ありがとうございました!
guest

0

ポイント配列で渡す様にしてみました。 expansionの計算が????

c

1#include <stdio.h> 2 3void expansion(double (*x0)[500][2]); 4int main(){ 5 int ret, i = 0; 6 FILE *fpa , *fpb; 7 char *fnamea = "data.csv"; 8 char *fnameb = "data2.csv"; 9 double pos[500][2]; 10 double x, y; 11 12 fpa = fopen(fnamea , "r"); 13 if(fpa == NULL){ 14 printf("ファイルが開けません"); 15 return -1; 16 } 17 fpb = fopen(fnameb , "w"); 18 if(fpb == NULL){ 19 printf("ファイルが開けません"); 20 return -1; 21 } 22 23 while((ret = fscanf(fpa, "%lf,%lf", &x , &y)) != EOF){ 24 pos[i][0] = x; 25 pos[i][1] = y; 26 i++; 27 } 28 double (*p)[500][2]; 29 p=(double (*)[500][2])pos; //ポイント配列へ代入 30 expansion(p); 31 32 for(i = 0; i < 500; i++){ 33 fprintf(fpb, "%lf,%lf\n", pos[i][0], pos[i][1]); 34 } 35 fclose(fpa); 36 fclose(fpb); 37} 38 39void expansion(double (*x0)[500][2]) { 40 double H = 3.5; 41 double org = 50; 42 double dt = 0.1; 43 int nk = 20 , i = 0 , j = 0 , k = 0; 44 double vx[500][2]; 45 for(i = 0; i < 500; i++){ 46 for(j = 0; j < 2; j++){ 47 vx[i][j] = H * (*x0)[i][j]; 48 (*x0)[i][j] = (*x0)[i][j] + org; 49 for(k = 0; k < nk; k++){ 50 (*x0)[i][j] += vx[i][j] * dt; 51 } 52 } 53 } 54}

c

1#include <stdio.h> 2 3typedef struct { 4 double x[500][2]; 5}dfpos; 6 7void expansion(dfpos *p); 8int main(){ 9 int ret, i = 0; 10 FILE *fpa , *fpb; 11 char *fnamea = "data.csv"; 12 char *fnameb = "data2.csv"; 13 dfpos pos; 14 double x, y; 15 16 fpa = fopen(fnamea , "r"); 17 if(fpa == NULL){ 18 printf("ファイルが開けません"); 19 return -1; 20 } 21 fpb = fopen(fnameb , "w"); 22 if(fpb == NULL){ 23 printf("ファイルが開けません"); 24 return -1; 25 } 26 27 while((ret = fscanf(fpa, "%lf,%lf", &x , &y)) != EOF){ 28 pos.x[i][0] = x; 29 pos.x[i][1] = y; 30 i++; 31 } 32 expansion(&pos); 33 34 for(i = 0; i < 500; i++){ 35 fprintf(fpb, "%lf,%lf\n", pos.x[i][0], pos.x[i][1]); 36 } 37 fclose(fpa); 38 fclose(fpb); 39} 40 41void expansion(dfpos *p) { 42 double H = 3.5; 43 double org = 50; 44 double dt = 0.1; 45 int nk = 20 , i = 0 , j = 0 , k = 0; 46 double vx[500][2]; 47 for(i = 0; i < 500; i++){ 48 for(j = 0; j < 2; j++){ 49 vx[i][j] = H * p->x[i][j]; 50 p->x[i][j] += org; 51 for(k = 0; k < nk; k++){ 52 p->x[i][j] += vx[i][j] * dt; 53 } 54 } 55 } 56}

投稿2017/01/26 05:09

編集2017/01/26 06:17
A.Ichi

総合スコア4070

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

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

Chironian

2017/01/26 06:41

expansion()関数が呼び出し元のポインタpを書き換えていないので、ポインタのポインタにする意味は特にないですよ。この処理なら元のx0の渡し方で十分と思います。
A.Ichi

2017/01/26 07:17

ご指摘ありがとうございます。x0 = x;で上位に戻したいのかな、と思ってました。
guest

0

こんにちは。

蛇足のような気もしますが、少し補足してみます。

void expansion(double x0[500][2])

まず、C言語では、配列を渡すと自動的に配列先頭へのポインタに成り下がってしまいます。上記のように要素数を明記していてもです。この場合、x0の型はdouble (*)[2]になってしまいます。(double型2つの配列へのポインタ)

そして、expansion()の最後でx0にxを代入することで、仮引き数x0(ポインタ)はx(配列)の先頭アドレスを指しています。
しかし、C言語は常に値渡しです。x0が呼び出し元のposへ返却されることはありません。

更に、posは配列であって配列へのポインタではありません。なので、その先頭アドレスを書き換えることはできません。
posは配列としてメモリが割り当てられています。そのメモリを別のアドレスへ移動する手順は遥かに複雑です。移動先アドレスのメモリへデータをコピーして元のメモリを解放するような手順となります。C言語はこのような操作をサポートしていません。

投稿2017/01/26 04:03

Chironian

総合スコア23272

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

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

sakas1231

2017/01/26 04:34

なるほど、あくまでx0は仮引数なのでいくらx0を変更しようとも、実引数であるところのposにはなんら影響を及ぼさない、という認識でよろしいでしょうか?
Chironian

2017/01/26 04:44

その通りです。 そして、qt6hyさんが言われるように普通はポインタのポインタで渡せばポインタを返せますが、posは配列であってポインタではないので、ポインタのポインタにしてもダメです。コピーするしかありません。
sakas1231

2017/01/26 09:19

ポインタのポインタを渡せば、ポインタを直接書き換えられるけれど、今回は配列を渡すからその手は使えない。そこで仮引数のアドレスにある値を直接書き換える。 ということでしょうか?
qt6hy

2017/01/27 08:09

その理解でよいです。
Chironian

2017/01/27 09:23

qt6hyさん、フォローありがとうございます。 sakas1231さん、その理解で合ってます。
sakas1231

2017/01/29 14:57

ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問