ubuntuusers.de

C Programm - Funktion als Argument über das Terminal definieren

Status: Gelöst | Ubuntu-Version: Lubuntu 12.10 (Quantal Quetzal)
Antworten |

Wooodl

Avatar von Wooodl

Anmeldungsdatum:
27. August 2011

Beiträge: Zähle...

Hallo Community,

ich soll ein C-Programm schreiben, welches eine beliebige reelle Funktion auswertet. Diese soll über die Kommandozeile als argc(1) ←-"sollen eckige Klammern sein 😉" übergeben werden. Kann man das irgendwie mit Hilfe von Funktionspointern lösen? Meine einzige Lösung für das Problem ist momentan eine externe Datei aus meinem Programm heraus zu kompilieren in der die Funktion dann definiert wird. Aber das muss doch einfacher gehen: Ich habe mir sowas vorgestellt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#include<stdio.h>
#include<strings.h>
#include<stdlib.h>

double f(double x);

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

double f(double x){
double ergebnis;
ergebnis=argc[1];
return ergebnis;
}

double y;
y=f(3) // Beispiel

fprintf(stdout, "Das Ergebnis von f(3)=%lf \n",y);
return 0;
}

DAS FUNKTIONIERT NATÜRLICH NICHT!, aber ich hoffe es ist klar geworden was ich will.

Danke schon mal im Voraus. Gruß Wooodl

TraumFlug

Avatar von TraumFlug

Anmeldungsdatum:
16. Juli 2009

Beiträge: 999

Wohnort: zwischen den ohren

Du bist nicht ganz eindeutig darin zu beschreiben, was für Funktionen du ausführen willst. Gib' bitte mal ein Beispiel in der Benutzung, also was das Programm genau können soll.

Du musst auch bedenken, dass C keine "Skriptsprache" ist wie Python oder ähnliche, wo man in Laufzeit einfach mal Code ausführen kann. Jeder C Code, der laufen soll, muss vorkompiliert sein. Die Funktion in C-Notation zu übergeben und vom Programm aus zu kompilieren ist eine sehr schlichte Lösung, und wird sicher als grösstmögliche Schummelei und Schlaumeierei angesehen, wenn das eine Hausaufgabe ist! Da machst du's dir dann doch ein bisschen zu leicht...

Willst du etwa eine "reelle Funktion" auswerten im Sinne einer mathematischen Funktion, brauchst du einen Parser für diese Funktion, der die Klammern, Variablen und Operatoren auswertet, und dann die Rechenschritte in der richtigen Reihenfolge ausführt, wenn du das Ergebnis der Funktion für bestimmte Werte haben willst.

Ein recht komplexes Beispiel in C, was Rechenformeln auswertet ist übrigends das GNU-Tool "bc", aber wenn es darum geht, mathematische Formeln zu übergeben, auszuwerten und durchzurechnen, findest du bestimmt viele einfachere Beispiellösungen im Netz, da das eine beliebte Aufgabenstellung ist.

Wooodl

(Themenstarter)
Avatar von Wooodl

Anmeldungsdatum:
27. August 2011

Beiträge: Zähle...

Hallo und Danke für die schnelle Antwort!

Die Aufgabe besteht darin eine Nullstellenberechnung mit Hilfe des Bisektionsverfahrens durchzuführen. Ist an und für sich auch kein Problem, zumindest für eine vorab deklarierte Funktion, z.B. ein Polynom. Mit der Schummelei hast du sicher recht, das Problem besteht nur darin, dass wir laut unserem Vorlesungsskript eigentlich nur Funktionsponiter kennen und nicht viel komplexeres. Ich denke also nicht dass das Verfahren sehr schwierig sein kann. Vlt verstehe ich die Aufgabe auch einfach nur falsch. Dort steht:

"Schreiben sie eine Routine für das Bisektionsverfahren und bestimmen sie die Nullstellen der Funktion f(x)=x^2-x-2" ... "Erweitern sie nun ihre Routine so, dass das Bisektionsvefahren als Funktion aufgerufen werden kann. Die übergebenen Argumente sollen sein: Zwei Startwerte, eine reelle Funktion, maximale Iterationszahl und eine Genauigkeitsgrenze."

Ich kann so Sachen programmieren wie:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include ...

double plus(double a, double b){
double erg;
erg=a+b;
return erg;
}

double minus(double a, double b){
double erg;
erg=a-b;
return erg;
}

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

double x,y;
char rechenzeichen[5];
double (*f)(double,double);

x=atof(argc[1]);
strcpy(rz,argc[2]);
y=atof(argc[3]);

if(strcmp(rz,"+")==0)
f=plus;
if(strcmp(rz,"-")==0)
f=minus;

fprintf(stdout,"%g %s %g = %g\n", x, rz, y, f(x,y));

return 0;
}

Aber ich hab keine Ahnung wie ich damit die obige Aufgabe lösen soll. Ich hoffe das waren genug Infos 😉

Danke!

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Für mich klingt das so, als sei die Aufgabe schlecht formuliert worden! Das Beispiel behandelt den einfachsten Fall, ein Polynom. Für dieses ist es kein so großes Problem, da man - anstelle den Ausdruck als String zu parsen - einfach die entsprechenden Parameter fest definiert übergenen kann, also etwa so:

1
2
3
f(x)=x^2-x-2
// wird zu folgenden Parametern
1 -1 -2

Du übergibst einfach nur jeden Koeffizienten für jeden Term. Dies kannst Du recht einfach in Dein Programm hineinbekommen und entsprechend an die Bisektionsfunktion übergeben.

Allerdings würde ich tatsächlich mit dieser anfangen, eben basierend auf dieser Annahme. Wenn das so weit klappt, kümmerst Du Dich dann um das Parsen der CLI-Argumente.

Wäre wirklich *jede* denkbarte reelle Funktion gefordert, so müsstest Du Dich exzellent in Sache Parsing auskennen und darüber hinaus fast ein eigenes kleines CAS entwickeln! Das kann so nicht gefordert sein...

TraumFlug

Avatar von TraumFlug

Anmeldungsdatum:
16. Juli 2009

Beiträge: 999

Wohnort: zwischen den ohren

Du brauchst "einfach" eine Funktion, die aus einem String mit der Gleichung ein Ergebnis erzeugt. Sowas nennt man "parser", in deinem Fall "formula/expression/equation - parser". Jedenfalls wenn die Formel als Textparameter mitgegeben werden soll. Je nachdem welche Rechenoperationen, Formelarten, und ob man Klammern und dergleichen nutzen darf, wird sie mehr oder weniger komplex. Hattet ihr schon Sachen wie rekursion und komplexere Schleifen, und Datenstrukturen wie verlinkte Listen und Stacks oder so? Funktionspointer braucht man dafür eigentlich nicht wirklich, können aber für eine "Maschine" die die Formel nach einem vorparsen (und die die Rechenschritte in einer Datenstruktur komprimiert für die Ausführung abgelegt vorfindet) "ausführen" soll nützlich in Punkto Optimierung sein. Dein Minibeispiel deutet schon darauf hin, dass es darum gehen soll, eine Funktion in Textform mit sowas ausrechnen zu können. Musst halt nur das Ganze in "grösser" durchdenken - ist schon ein ganzschöner Sprung von so einem kleinen Ding zu einem ganzen Formelparser. Ich hoffe mal, sie haben euch genug Zeit dafür gegeben...

Mehr sag' ich nicht, ich mache ja nicht deine Hausaufgaben für dich 😛

TraumFlug

Avatar von TraumFlug

Anmeldungsdatum:
16. Juli 2009

Beiträge: 999

Wohnort: zwischen den ohren

Ja, Lysander hat recht, es wird wohl kaum eine völlig beliebige Funktion gefordert sein, sondern nur ein Polynom mit einer Variable - alles andere wären wohl dann Taschenträgerpunkte für korrekt gescheitelte, vor allem wenn ihr sowieso noch nicht so weit seid. Wenn's ohne Klammern und Sonderfunktionen ist, also ein String mit soundsoviel x hoch y plus/minus nächstes Teil... brauchst du ja nur in einer Schleife den String entlang gehen, jeden Faktor einzeln berechnen und auf einen Akkumulator addieren/substrahieren, bis der String durch ist und der Akkum. dann das Ergebnis enthält. Pass nur mit den Parametern auf, leerzeichen machen aus einem argv[] gleich mal 2 oder mehr, wenn sie nicht gequoted/escaped wurden (ich weiss nicht, wie das unter windows wäre...). Wozu man da Funktionspointer braucht...? ...aber gut, wenn der prof das will benutz' die halt...

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Mir fällt gerade auf, dass in der Aufganenstellung mit keinem Wort irgend etwas von CLI steht! Das kann doch alles *intern* gelöst werden. DU hast uns ja erst auf den Trcihter von wegen "Parameter Übergabe" gelenkt...

Die Funktion für die Bisketion soll einfach eine beliebige, *im* C-Code definierte, Funktion übergeben bekommen. Die Funktionen an sich kannst Du dann programmieren wie Du willst. Wichtig ist nur, dass die Signatur immer passt. Das ist aber ja kein Problem, da die Funktion ja f(x) definiert sind. Somit kannst Du dann auch Sinus, Cosinus, usw. übergeben.

Als ersten Schritt sollst Du ja nur die gegebene Funktion nutzbar machen. Diese verpackst Du bereits in eine separate Funktion und rufst halt diese *direkt* im Bisektions-Algo auf. Im zweiten Schritt ersetzt Du einfach den direkten Aufruf gegen einen über einen übergebenen Funktionspointer.

Manchmal ist das Leben einfacher als man denkt... 😉

Wooodl

(Themenstarter)
Avatar von Wooodl

Anmeldungsdatum:
27. August 2011

Beiträge: 28

Lysander schrieb:

Mir fällt gerade auf, dass in der Aufganenstellung mit keinem Wort irgend etwas von CLI steht! Das kann doch alles *intern* gelöst werden. DU hast uns ja erst auf den Trcihter von wegen "Parameter Übergabe" gelenkt...

Die Funktion für die Bisketion soll einfach eine beliebige, *im* C-Code definierte, Funktion übergeben bekommen. Die Funktionen an sich kannst Du dann programmieren wie Du willst. Wichtig ist nur, dass die Signatur immer passt. Das ist aber ja kein Problem, da die Funktion ja f(x) definiert sind. Somit kannst Du dann auch Sinus, Cosinus, usw. übergeben.

Als ersten Schritt sollst Du ja nur die gegebene Funktion nutzbar machen. Diese verpackst Du bereits in eine separate Funktion und rufst halt diese *direkt* im Bisektions-Algo auf. Im zweiten Schritt ersetzt Du einfach den direkten Aufruf gegen einen über einen übergebenen Funktionspointer.

Manchmal ist das Leben einfacher als man denkt... 😉

Aaaach soooo ist das gemeint :DD Ich war nur verwirrt weil ich mir dachte ein Programm in dem die Funktion intern definiert ist macht wenig Sinn für jemanden der es nur "benutzen" will. Aber nachdem der Kurs "Numerische Methoden der Physik" heißt, denk ich mal dass sie von uns erwarten kurz die definierte Funktion im Code ändern zu können 😀

Naja großes Dankeschön, das hat mir viel Arbeit erspart ;D

Wooodl

(Themenstarter)
Avatar von Wooodl

Anmeldungsdatum:
27. August 2011

Beiträge: 28

TraumFlug schrieb:

Du brauchst "einfach" eine Funktion, die aus einem String mit der Gleichung ein Ergebnis erzeugt. Sowas nennt man "parser", in deinem Fall "formula/expression/equation - parser". Jedenfalls wenn die Formel als Textparameter mitgegeben werden soll. Je nachdem welche Rechenoperationen, Formelarten, und ob man Klammern und dergleichen nutzen darf, wird sie mehr oder weniger komplex. Hattet ihr schon Sachen wie rekursion und komplexere Schleifen, und Datenstrukturen wie verlinkte Listen und Stacks oder so? Funktionspointer braucht man dafür eigentlich nicht wirklich, können aber für eine "Maschine" die die Formel nach einem vorparsen (und die die Rechenschritte in einer Datenstruktur komprimiert für die Ausführung abgelegt vorfindet) "ausführen" soll nützlich in Punkto Optimierung sein. Dein Minibeispiel deutet schon darauf hin, dass es darum gehen soll, eine Funktion in Textform mit sowas ausrechnen zu können. Musst halt nur das Ganze in "grösser" durchdenken - ist schon ein ganzschöner Sprung von so einem kleinen Ding zu einem ganzen Formelparser. Ich hoffe mal, sie haben euch genug Zeit dafür gegeben...

Mehr sag' ich nicht, ich mache ja nicht deine Hausaufgaben für dich 😛

So weit sind wir noch nicht 😉 im Kurs gehts eher um die Algorithmen an sich als um die elegante Programmierung. Aber ich werde mir das mit den Parsern trotzdem mal anschauen, kann ja nicht schaden. Danke!

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

@Wooodl Bitte unterlasse doch Full-Quotes ☺

Antworten |