Wskaźnik do struktury

0

Witam. W programie który piszę korzystam z biblioteki numerycznej cminpack, służącej m.in. do obliczania pierwiastków równań nieliniowych. Problem polega na tym, że nie wiem jak podać do funkcji zmienną zewnętrzną (z main'a), w dokumentacji jest jedynie napisane że można to zrobić poprzez podanie wskaźnika do struktury, jednak nie ma żadnego przykładu. Niestety moje próby nie przyniosły rezultatu. Oto program który mi działa:

#include <iostream>
#include <cmath>
#include <cminpack.h>

int fcn(void *p, int n, const double *x, double *fvec, int iflag);

int main()
{
  int n = 1, lwa = 8;				//n - liczba równań
  double tol = sqrt(dpmpar(1));		//tol - dokladnosc obliczen
  double x[1], fvec[1], wa[8];		//wa - tablica operacyjna o dlugosci lwa

  x[0] = - 2;						//wartosc poczatkowa x[0]

  hybrd1(fcn, 0, n, x, fvec, tol, wa, lwa);

  std::cout << x[0] << std::endl;

  system("pause");
  return 0;
}

int fcn(void *p, int n, const double *x, double *fvec, int iflag) {

	double a = 3, b = 5, c = 13, d = 7;

	fvec[0] = a*pow(x[0],3) + b*pow(x[0],2) + c*x[0] + d;

	return 0;
}

Przypuśćmy że chciałbym wywołać funkcję zawierającą zmienną zewnętrzną, jednak nie globalną, np:

int fcn(void *p, int n, const double *x, double *fvec, int iflag) {

	double a = 3, b = 5, c = 13, d = 7;

	fvec[0] = a*pow(x[0],3) + b*pow(x[0],2) + c*x[0] + d + e;

	return 0;
}

Z dokumentacji: "The argument 'p' can be used to store extra function parameters, thus avoiding the use of global variables. You can also think of it as a 'this' pointer a la C++."; "...void* argument can be used to pass any pointer-to-struct, and you can put all you extra parameters and data in that struct. Just cast this pointer to the appropriate pointer type in your function"
Z góry dzięki za pomoc.

0

Oj to jest dość proste. Załóżmy że przekazałeś tam pointer na na jakąś zmienną typu int którą chcesz dodać do tego swojego fvec[0]

int fcn(void *p, int n, const double *x, double *fvec, int iflag) 
{
        int* pointerdonaszejzmiennej = (int*)p;
        double a = 3, b = 5, c = 13, d = 7;
        fvec[0] = a*pow(x[0],3) + b*pow(x[0],2) + c*x[0] + d + e + *pointerdonaszejzmiennej;
        return 0;
}

Załóżmy że przekazałeś tam tablicę i chcesz dodać 3 elementy tej tablicy:

int fcn(void *p, int n, const double *x, double *fvec, int iflag) 
{
        int* tab = (int*)p;
        double a = 3, b = 5, c = 13, d = 7;
        fvec[0] = a*pow(x[0],3) + b*pow(x[0],2) + c*x[0] + d + e + tab[0]+tas[1]+tab[2];
        return 0;
}

Oczywiście w main to będzie wyglądało tak:

int main()
{
  int n = 1, lwa = 8;                                //n - liczba równań
  double tol = sqrt(dpmpar(1));                //tol - dokladnosc obliczen
  double x[1], fvec[1], wa[8];                //wa - tablica operacyjna o dlugosci lwa
  x[0] = - 2;                                                //wartosc poczatkowa x[0]
  int zmienna = 10; 
  int tablica[3] = {1,2,3};
  //w pierwszym przypadku:
  hybrd1(fcn, (void*)&zmienna, n, x, fvec, tol, wa, lwa);
  //w drugim przypadku:
  hybrd1(fcn, (void*)tablica, n, x, fvec, tol, wa, lwa);
  std::cout << x[0] << std::endl;
  return 0;
}
0

Kurde stary działa wyśmienicie :-) Ogromne dzięki [browar] . Przy okazji, wiesz może jak by to wyglądało gdybym chciał użyć struktury ? Kombinowałem z czymś takim:

struct moje_parametry { double par; };
moje_parametry parametry = { zmienna };
moje_parametry *wsk = &parametry;
wsk -> par;

Nie wiem także czy to podpiąć w main czy w definicji funkcji.

0

W przypadku struktury robisz identycznie.

struct Ala
{
  int ola;
  double ela;
  Ala(int o, double e):ola(o),ela(e){}
};
// w main masz np.:
Ala obiekt(1,2.0);
hybrd1(fcn, (void*)&obiekt, n, x, fvec, tol, wa, lwa);
//w funkcji masz np.:
int fcn(void *p, int n, const double *x, double *fvec, int iflag) 
{
        Ala* obiekt = (Ala*)p;
        double a = 3, b = 5, c = 13, d = 7;
        fvec[0] = a*pow(x[0],3) + b*pow(x[0],2) + c*x[0] + d + e + obiekt->ola + obiekt->ela;
        return 0;
}
0

Stworzyłem trochę prostszą (wg. mnie) wersję i wygląda to następująco:

#include <iostream>
#include <cmath>
#include <cminpack.h>

int fcn(void *p, int n, const double *x, double *fvec, int iflag);

int main()
{
  int n = 1;						//n - liczba równań
  const int lwa = 8;
  double tol = sqrt(dpmpar(1));		//tol - dokladnosc obliczen
  double x[1], fvec[1], wa[lwa];	//wa - tablica operacyjna o dlugosci lwa

  x[0] = - 2;						//wartosc poczatkowa x[0]

  parametry p1 = { 2.33, 4.5, 54.6, 5.0, -3.1, -9.776 };

  hybrd1(fcn, (void*)&p1, n, x, fvec, tol, wa, lwa);

  std::cout << x[0] << std::endl;

  system("pause");
  return 0;
}

int fcn(void *p, int n, const double *x, double *fvec, int iflag) {

	parametry* p1 = (parametry*)p;
	double a = 3, b = 5, c = 13;

	fvec[0] = a*pow(x[0],3) + b*pow(x[0],2) + c*x[0] + p1->q;

	return 0;
}

struct parametry { double q, w, e, r, t, y; };

Na chwilę przed wykonaniem kompilator na pasku informacyjnym sygnalizuje "Build faild" (ułamek sekundy) i następnie wyświetla się wynik, poprawny zresztą. Zastanawiam się czy w kodzie jest jakiś błąd, czy to po prostu jakiś "grymas" kompilatora. A tak w ogóle to będę korzystał z tablic, wydaje mi się to wygodniejsze.

0

Na oko wygląda ok, ale
(void*)&p1
zamieniłbym na
(void*)p1
;)

0

Dziwna sprawa. Po zamianie (void*)&p1 na (void*)p1 progs się wykonuje, jak poprzednio przez chwilę widać "Build failed", a do tego kompilator podkreśla p1 na czerwono. Jeszcze raz dzięki za pomoc Shalom.

0

Aaa źle źle. Mea culpa. Ma być tak jak było, z tym &
Bo rzuciłem tylko na to okiem i wydawało mi się że to tablica jest, a to struktura. Przepraszam za wprowadzenie w błąd.

1 użytkowników online, w tym zalogowanych: 0, gości: 1