2017-01-26 15 views
3

私はこのプログラムを最初に書きました。再帰的にpiを計算し、エラー値が十分に小さいときに停止します。これらの2つのCプログラムで同じ結果が得られないのはなぜですか?

#include <stdio.h>` 
#include <stdlib.h> 
#include <math.h> 

int threads=1; 
double error=0.000001; 
double func(double); 


struct args{ 
     double l; 
     double r; 
     double fl; 
     double fr; 
     double area;}; 

double quad(struct args*); 

int main(int argc, char *argv[]) { 

    struct args* res = (struct args*)malloc(sizeof(struct args)); 
    res->l=0; 
    res->r=1; 
    res->fl=1; 
    res->fr=0; 
    res->area=0; 

    double ans=quad(res); 
    free(res); 

    ans=ans*4; 

    printf("pi=%f\n",ans); 


} 


double func(double x){ 
     x=(1-(x*x)); 
     x=sqrt(x); 
     return x; 
    } 


double quad(struct args* arg){ 
    double m=(arg->l+arg->r)/2; 
    double fm=func(m); 
    double larea=(arg->fl+fm)*(m-arg->l)/2; 
    double rarea = (fm+arg->fr)*(arg->r-m)/2; 

    struct args* arg1 = (struct args*)malloc(sizeof(struct args)); 
    arg1->l=arg->l; 
    arg1->r=m; 
    arg1->fl=arg->fl; 
    arg1->fr=fm; 
    arg1->area=larea; 

    struct args* arg2 = (struct args*)malloc(sizeof(struct args)); 
    arg2->l=m; 
    arg2->r=arg->r; 
    arg2->fl=fm; 
    arg2->fr=arg->fl; 
    arg2->area=rarea; 
    if(fabs((larea+rarea)-arg->area)>error){ 
     if(threads<=1){ 
      larea=quad(arg1); 
      rarea=quad(arg2); 

      free(arg1); 
      free(arg2); 
     } 

    } 

    return(larea+rarea); 
} 

この1つは、それが必要として動作しますが、私はquad機能ではなく、それはこのように見えたdoublevoid pointerを返す作ってみました。

#include <stdio.h>` 
#include <stdlib.h> 
#include <math.h> 

int threads=1; 
double error=0.000001; 
double func(double); 
struct args{ 
     double l; 
     double r; 
     double fl; 
     double fr; 
     double area;}; 

void* quad(struct args*); 

int main(int argc, char *argv[]) { 

     struct args* res = (struct args*)malloc(sizeof(struct args)); 
     res->l=0; 
     res->r=1; 
     res->fl=1; 
     res->fr=0; 
     res->area=0; 
     void* ans=quad(res); 

     double val=*(double*)ans; 
     val=val*4; 

     free(res); 


     printf("pi=%f\n",val); 
    } 

double func(double x){ 
    x=(1-(x*x)); 
    x=sqrt(x); 
    return x; 
    } 

void* quad(struct args* arg){ 
    double m=(arg->l+arg->r)/2; 
    double fm=func(m); 
    double larea=(arg->fl+fm)*(m-arg->l)/2; 
    double rarea = (fm+arg->fr)*(arg->r-m)/2; 

    struct args* arg1 = (struct args*)malloc(sizeof(struct args)); 
    arg1->l=arg->l; 
    arg1->r=m; 
    arg1->fl=arg->fl; 
    arg1->fr=fm; 
    arg1->area=larea; 

    struct args* arg2 = (struct args*)malloc(sizeof(struct args)); 
    arg2->l=m; 
    arg2->r=arg->r; 
    arg2->fl=fm; 
    arg2->fr=arg->fl; 
    arg2->area=rarea; 
    if(fabs((larea+rarea)-arg->area)>error){ 
     if(threads<=1){ 
      void* p1=quad(arg1); 
      void* p2=quad(arg2); 
      larea=*((double*)p1); 
      rarea=*((double*)p2); 

      free(arg1); 
      free(arg2); 
     } 
    } 


    double ret= (larea+rarea); 
    void*poin=&ret; 

    return poin; 
} 

このプログラムをコンパイルすると、私はまったく異なる結果になります。つまり、3.14159ではなく0.042298です。私はかなり新しいCとポインタを使用しているので、私は変換で何かを混乱させると確信していますが、私は人生のためにどこにあるのか理解できません。

これらの2つのプログラムが異なる結果をもたらす理由を理解する助けがあれば幸いです。ありがとう。

+4

いずれのプログラムも有効ではありません。 C言語では、関数を呼び出す前に宣言する必要があります。あなたのコードで宣言されていない関数 'quad'を呼び出しています。関数の宣言がオプションの古いC89/90でさえ、動作は未定義です。現代Cでは、これはコンパイルできません。どちらの場合でも、2つ目のバージョンはローカル変数へのポインタを返そうとしますが、意味がありません。 – AnT

答えて

5

retへのポインタを返しています。変数はquad()にローカルです。あなたがそれを見るときに、それは置き換えられました。

また、無効なポインタの逆参照は未定義の動作です。つまり、あなたのコンパイラは、あなたのハードドライブをフォーマットするか、WW3を始めるような何でも自由であることを意味します。

+0

ええ、それは理にかなっています。それは修正可能ですか?ヒープや何かの上でポインタを割り当てるか? –

+0

@JohnSlaine最初のアプローチで何が間違っていたか - 'double'値を返すのですか? 2番目のバージョンの 'void *'ポインタとすべてを取り除き、次に進むことをお勧めします。しかし、良い実験。 –

+0

@JohnSlaineはい、ヒープへのポインタが機能します。もちろん、それはあなたがmalloc()とfree()をしなければならないことを意味します。 私は言語の隅々を探っていると仮定しています。あなたがやっていることは、実際に私には意味がありません。 – kamikaze

2

あなたの機能していない関数は、関数が終了するときにスコープと寿命から外れるローカル変数へのポインタを返します。

​​

実際のバージョンでは、実際のdoubleの値が返されます。

なぜ、void*ポインタを返すように関数を変更しましたか?

+0

私はそれをマルチスレッドにしようと思っていました。 'pthread'が' void * 'を返す関数を望んでいることを理解しています。 –

+0

その場合、 'double'値を' void * 'ポインタにキャストしてみてください。だから、ポインタ*値*は二重線そのものです:あなたのポインタには64ビットがあると仮定します;)。 'return(void *)ret;'それで幸運です。 –

+1

@JohnSlaineスレッドから値を返すには、 'struct args'にメンバ(例えば' double result; ')を追加し、そこに戻り値を入れます。 – user3386109

関連する問題