2017-01-26 7 views
3

Я написал эту программу во-первых, она рекурсивно вычисляет pi и останавливается, когда значение ошибки достаточно мало.Почему эти две программы 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); 
} 

Это один работает как надо, но тогда я попытался сделать функцию quad вернуть void pointer вместо того, чтобы double это выглядело так.

#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; 
} 

Эта программа, хотя она компилируется, дает мне совершенно другой результат, 0.042298, а не 3.14159. Я довольно новичок в C и использую указатель, поэтому я уверен, что что-то перепутал с конверсиями, но не могу, чтобы жизнь меня определяла где.

Любая помощь в выяснении того, почему эти две программы дают разные результаты, будет оценена по достоинству. Благодарю.

+4

Ни одна из программ не действительна. C langauge требует, чтобы вы объявляли функции перед их вызовом. Вы вызываете необъявленную функцию «quad» в своем коде. Даже в старых C89/90, где объявления функций были необязательными, поведение было бы неопределенным. В современном C это даже не компилируется. В любом случае ваша вторая версия пытается вернуть указатель на локальную переменную, что не имеет смысла. – AnT

ответ

5

Вы возвращаете указатель на ret. Переменная, которая является локальной для quad(). К тому времени, когда вы посмотрите на него, он был заменен.

Также разыменование недопустимого указателя является неопределенным поведением. Это означает, что ваш компилятор может делать все, что угодно, например, форматировать жесткий диск или запускать WW3.

+0

Да, это имеет смысл. Это исправление? Выделение указателя на кучу или что-то работает? –

+0

@JohnSlaine, что было не так с первым подходом - возврат значения «double»? Я предлагаю вам отказаться от второй версии, 'void *' указатели и все, и двигаться дальше. Хороший эксперимент. –

+0

@JohnSlaine Да, указатель на кучу будет работать. Конечно, это означало бы, что вы должны malloc() и free(). Я предполагаю, что вы изучаете укромные уголки и подшучивания языка, потому что то, что вы делаете, на самом деле не лижет меня смысла. – kamikaze

2

Ваша неработающая функция возвращает указатель на локальную переменную, которая выходит из сферы действия и срока службы, когда функция заканчивается.

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

В то время как рабочая версия возвращает фактическое double значение.

Почему бы не изменить функцию, чтобы вернуть указатель void*?

+0

Я хотел попытаться сделать это многопоточным, и я понимаю, что 'pthread' хочет функции, которые возвращают' void * ' –

+0

Если это так, вы можете попробовать отличить значение' double' к указателю 'void *'. Таким образом, значение указателя * является двойным: если ваши указатели имеют 64 бита;). 'return (void *) ret;' Удачи вам в этом. –

+1

@JohnSlaine Чтобы вернуть значение из потока, добавьте элемент (например, 'double result;') в 'struct args' и поместите туда возвращаемое значение. – user3386109

 Смежные вопросы

  • Нет связанных вопросов^_^