Budada_Bubladend
Anmeldungsdatum: 13. Dezember 2009
Beiträge: 812
|
Hallo Leute, ich bin gerade trotz langer Internetsuche am verzweifeln.
Ich stehe vor folgendem Problem: Ich habe mit einer Structur einen Datentyp erstellt:
struct bruch {
int zaehler;
int nenner;
}; Nun möchte ich in einer Funktion Namens eingabe b1 füllen.
Ich habe nur keine Ahnung wie ich b1 übergebe!
Beispiel:
//b1 soll sein
struct bruch b1={zaehler nenner};
//muss ich jetzt b1 anlegen, und das dann in die Funktion eingabe übergeben oder wie?
void eingabe (b1){
int zaehler;
printf ( "Zaehler:" );
scanf ( "%d" , zaehler);
struct bruch b1 ={zaehler}; //funktioniert so leider nicht Im Internet bin ich auf folgendes gestoßen: //Funktionsaufruf:
eingabe( bruch);
//Funktionskopf:
void eingabe (struct bruch);
doch das geht auch nicht! Kann mir bitte jemand helfen? Danke schon mal im voraus Lg
BB
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17622
Wohnort: Berlin
|
Hiermit sind zaehler und nenner nur lokal im struct bekannt.
| struct bruch {
int zaehler;
int nenner;
};
|
| //b1 soll sein
struct bruch b1={zaehler nenner};
void eingabe (b1){
int zaehler;
printf ( "Zaehler:" );
scanf ( "%d" , zaehler);
struct bruch b1 ={zaehler}; //funktioniert so leider nicht
|
Weder sind zaehler und nenner deklariert und initialisiert (lediglich bruch.nenner ist deklariert), noch deklarierst Du eine Funktion derart, dass Du sie mit einer konkreten Referenz aufrufst. | int a = 7;
void foo (a) { // ...
void foo (7) { // ...
|
würde man beides nicht machen, denn es ist sinnlos. Eine Funktion erwartet Parameter, die erst zur Laufzeit gebunden werden. Wenn Du sowas wirklich bräuchtest würdest Du schreiben | void foo (void) {
int a = 7;
|
Was Du meinst ist wohl:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | #include <stdio.h>
struct bruch {
int zaehler;
int nenner;
};
struct bruch eingabe () {
int n, z;
printf ( "Zähler:" );
scanf ( "%d" , &z);
printf ( "Nenner:" );
scanf ( "%d" , &n);
struct bruch b1;
b1.zaehler = z;
b1.nenner = n;
return b1;
}
|
Mein C ist sehr angestaubt - da sind bestimmt Fehler drin - jedenfalls compiliert es.
|
Vain
Anmeldungsdatum: 12. April 2008
Beiträge: 2510
|
Entweder das oder du übergibst einen Zeiger an deine Funktion:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 | #include <stdio.h>
struct bruch
{
int zaehler;
int nenner;
};
void eingabe(struct bruch *b)
{
b->zaehler = 2;
b->nenner = 3;
}
int main(int argc, char *argv[])
{
struct bruch a;
eingabe(&a);
printf("%d, %d\n", a.zaehler, a.nenner);
return 0;
}
|
Der Unterschied ist meines Wissens nach auch, dass bei user unknown in der Funktion „eingabe() “ ein struct erzeugt wird und dann nach Ende dieser Funktion in der aufrufenden Funktion das „zurückgegebene“ struct auf den lokalen Stack kopiert wird. Musst du wissen, ob sowas bei dir sinnvoll ist. Wenn du es mit einem Pointer machst, dann hast du nur in der aufrufenden Funktion ein struct und „eingabe() “ arbeitet direkt darauf. Damit wir alle Varianten durch haben: Obiges Beispiel ohne Pointer erzeugt dir in „eingabe() “ eine Kopie des structs, die auf die aufrufende Funktion keine Auswirkung hat:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | #include <stdio.h>
struct bruch
{
int zaehler;
int nenner;
};
void eingabe(struct bruch b)
{
b.zaehler = 2;
b.nenner = 3;
}
int main(int argc, char *argv[])
{
struct bruch a;
a.zaehler = 123;
a.nenner = 456;
eingabe(a);
printf("%d, %d\n", a.zaehler, a.nenner);
return 0;
}
|
|
Darkstar999
Anmeldungsdatum: 21. September 2008
Beiträge: 324
|
Vain schrieb: Hallo nur so Interesse halber, der Unterschied kommt doch
erst Signifikant zur Geltung im Ansi C bei großen Strukturen wo es
um Speicher spezifische bzw. Zeitliche Begrenzungen geht
oder z.B auf einem 8-Bit Systeme etc. Oder liege ich da
falsch. Zumal das Direkt auf der Struktur rum rutschen wenn man weiß was man tut ideal ist da man dann
im Programmverlauf keine Kopie der Struktur an die Funktion übergibst! Wie du oben schon erwähnt hast. mfg darkstar999
|
Budada_Bubladend
(Themenstarter)
Anmeldungsdatum: 13. Dezember 2009
Beiträge: 812
|
Hey Vain, danke dir!
Genau das habe ich eigentlich gesucht!
Ich hatte es mit einem Pointer versucht, doch das hatte nicht ganz funktioniert.. ich weiß jetzt auch warum. Ich hatte da
void eingabe(*b)
(an dein Beispiel angepasst).
Nun funktioniert es!
Vielen Dank.. natürlich auch an user unknown. Gruß
BB
|
Vain
Anmeldungsdatum: 12. April 2008
Beiträge: 2510
|
Darkstar999 schrieb: Hallo nur so Interesse halber, der Unterschied kommt doch
erst Signifikant zur Geltung im Ansi C bei großen Strukturen wo es
um Speicher spezifische bzw. Zeitliche Begrenzungen geht
oder z.B auf einem 8-Bit Systeme etc. Oder liege ich da
falsch.
Ist anzunehmen, dass das nur relevant ist, wenn’s wirklich auf die
letzte Millisekunde und das letzte Bit ankommt. Kannst dir aber
vielleicht auch mal anschauen, welchen Code der Compiler so generiert,
wenn du ihn optimieren lässt. So schlau, wie die Dinger mittlerweile
sind, könnte ich mir vorstellen, dass sie eine unnötige Kopie dann eh
wegoptimieren.
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17622
Wohnort: Berlin
|
Ich kann nur raten die Frage aus einem anderen Blickwinkel zu stellen: Wie will man die Funktion nutzen? Will ich mir ein Bruch-Objekt geben lassen, oder will ich dafür immer extra Code schreiben? Als Programmierer will ich eine Funktion, die mir soviel Arbeit wie möglich abnimmt. Will ich einen einmal erzeugten Bruch nochmal neu verwenden - das sieht eher ungewöhnlich und wie ein Codesmell aus, kann aber in speziellen Situationen doch sinnvoll sein. Benötige ich eine extra Funktion, die Brüche erzeugt, die aber nicht von der Tastatur liest? Das ist ziemlich gut möglich, z.B. wenn man Funktionen hat, die da lauten | struct Bruch add (Bruch a, Bruch b);
struct Bruch mul (Bruch a, Bruch b);
struct Bruch sub (Bruch a, Bruch b);
struct Bruch div (Bruch a, Bruch b);
struct Bruch invers (Bruch a);
struct Bruch kuerzen (Bruch a);
|
Dann könnte sich eine eigene Funktion zum Erzeugen von Brüchen dennoch anbieten, weil man das nicht immer an Ort und Stelle machen will (DRY-Prinzip).
|
Darkstar999
Anmeldungsdatum: 21. September 2008
Beiträge: 324
|
user unknown schrieb: Dann könnte sich eine eigene Funktion zum Erzeugen von Brüchen dennoch anbieten, weil man das nicht immer an Ort und Stelle machen will (DRY-Prinzip).
Naja dan würde ich Persönlich auf Zeiger und eine Dynamische Datenstruktur wählen!!!
Plus Funktionszeiger wegen mal plus durch etc.. Besten Dank für die Antworten mfg darkstar999
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17622
Wohnort: Berlin
|
Darkstar999 schrieb: user unknown schrieb: Dann könnte sich eine eigene Funktion zum Erzeugen von Brüchen dennoch anbieten, weil man das nicht immer an Ort und Stelle machen will (DRY-Prinzip).
Naja dan würde ich Persönlich auf Zeiger und eine Dynamische Datenstruktur wählen!!!
Was ist eine dynamische Datenstruktur? Wie implementiert man das? Wieso?
Plus Funktionszeiger wegen mal plus durch etc..
Verstehe ich auch nicht.
| Bruch a = eingabe ();
Bruch b = eingabe ();
Bruch c = add (mul (a, a), div (a, b));
|
Nötig ist das ja nicht. Oder wozu?
|
Darkstar999
Anmeldungsdatum: 21. September 2008
Beiträge: 324
|
So ich habe hier mal ein kleines Beispiel zum Thema Funktionszeiger zusammengebastelt. 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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 | /*
============================================================================
Name : Bruch.c
Author : darkstar999
Version :
Copyright : Your copyright notice
Description : Bruch C, Ansi-style
============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
struct Bruch {
int zaehler;
int nenner;
struct Bruch *next;
};
struct Bruch plus(struct Bruch *a,struct Bruch *b){
struct Bruch *rueck =malloc(sizeof(struct Bruch));
rueck->zaehler = (a->zaehler) + (b->zaehler);
rueck->nenner = (a->nenner) + (b->nenner);
return *rueck;
}
struct Bruch mal(struct Bruch *a,struct Bruch *b){
struct Bruch *rueck = malloc(sizeof(struct Bruch));
rueck->zaehler = (a->zaehler) * (b->nenner);
rueck->nenner = (b->zaehler) * (a->nenner);
return *rueck;
}
struct Bruch berechnen(struct Bruch (*modus)(struct Bruch *c, struct Bruch *d),struct Bruch *a, struct Bruch *b)
{
struct Bruch *erg = malloc(sizeof(struct Bruch));
*erg = (*modus)(a,b);
return *erg;
}
int main(void) {
struct Bruch *a = malloc(sizeof(struct Bruch));
struct Bruch *b = (struct Bruch *)malloc(sizeof(struct Bruch));
struct Bruch *c = (struct Bruch *)malloc(sizeof(struct Bruch));
struct Bruch *d = (struct Bruch *)malloc(sizeof(struct Bruch));
a->zaehler = 2;
a->nenner = 2;
b->zaehler = 2;
b->nenner = 2;
*c = berechnen(mal,a,b);
*d = berechnen(plus,a,b);
printf("Z%d N%d\n",c->zaehler,c->nenner);
printf("Z%d N%d\n",d->zaehler,d->nenner);
free(a);
free(b);
free(c);
free(d);
return 0;
}
|
Das mit der Dynamischen Datenstruktur oben im Beispiel schon durch den next Zeiger angedeutet macht z.b Sinn wenn du die Brüche aus einer Datei ausliest um die einzelnen Brüche zwischen zu speichern. Eine Liste (Dynamische Datenstruktur) zu verwende ist Sinnvoll da in der einzulesenden Datei ja unterschiedlich viele Brüche stehen können und du nicht immer von vornherein sagen kannst wie viele Brüche du brauchst.Ich habe das jetzt nicht mit implementiert weil ich nicht weiß ob jedem gleich klar wird was ich in dem Beispiel oben mache. mfg darkstar999
|
TraumFlug
Anmeldungsdatum: 16. Juli 2009
Beiträge: 999
Wohnort: zwischen den ohren
|
Darkstar999 schrieb: So ich habe hier mal ein kleines Beispiel zum Thema Funktionszeiger zusammengebastelt.
...
<...> weil ich nicht weiß ob jedem gleich klar wird was ich in dem Beispiel oben mache.
Du machst Mist mit malloc. Unter Anderem. Dein Code "leakt" wie sau: Bei jedem Aufruf einer deiner Unterfunktionen: struct Bruch *rueck = malloc(sizeof(struct Bruch));
...
return *rueck; ...Du alloziierst eine Struct mit malloc, und gibtst nicht den Pointer Zurück, sondern die reine Struct (auf dem Stack für die aufrufende Funktion). Die Daten werden nich in deinem Programm freigegeben. Wenn du schon, im Sinne wirklich "dynamischer" Datenstrukturen (dein Beispiel hat so gut wie nichts damit zu tun!), eine Funktion willst, die einen Pointer auf eine "neue" Struktur zurückgibt, dann musst du im Programm Sorge tragen, dass keine Leaks entstehen. Z.B. indem du einen Pointer auf das alloziierte zurückgibst, diesen nur auf einen "leeren" Pointer überträgst, und sicherstellst, dass er nach Nutzung wieder freigegeben wird. Gut, du wolltest nur ein kleines "Beispiel" geben, aber insgesammt ist in diesem jegliche Nutzung von malloc "überflüssig". Das man mit Pointer-Parameter-Funktionen arbeitet, heisst nicht, dass man malloc nutzen muss, malloc hat den Sinn, bei Programmierung unbekannte Quantitäten an Speicher zur Verfügung zu stellen, der auch Ausserhalb von den alloziierenden Funktionen noch Bestand hat. Und nicht, dass man jeglichen Speicher, den man so braucht damit anfordert! Ausserdem ist es eher unüblich, einen Basisdatentyp, mit dem man alles Mögliche machen kann ("struct Bruch") direkt mit einem Pointer für eine verlinkte Liste zu versehen, eher baut man eine spezialisierte Listenstruktur, und versieht diese mit einer "struct Bruch", oder wenn's ganz generisch sein soll, mit einem void* der dann auf einen extra angeforderten Bruch zeigt. Und noch lesenswert, eine gute Konvention in der C Programmierung, die viel praktiziert wird, wenn Pointer auf irgendwas an eine Funktion übergeben werden: http://en.wikipedia.org/wiki/Const_correctness.
|
Darkstar999
Anmeldungsdatum: 21. September 2008
Beiträge: 324
|
Darkstar999 schrieb:
Das mit der Dynamischen Datenstruktur oben im Beispiel schon durch den next Zeiger angedeutet macht z.b Sinn wenn du die Brüche aus einer Datei ausliest um die einzelnen Brüche zwischen zu >speichern.Ich habe das jetzt nicht mit implementiert weil ich nicht weiß ob jedem gleich klar wird was ich in dem Beispiel oben mache.
Richtig ich habe die Dynamische Datenstruktur nicht genutzt wie ich auch geschrieben habe in diesem Beispiel!!!!! Zum Thema jegliche Nutzung von malloc ist überflüssig nein da sonst z.b *d adresse 0x00 hat und somit das Programm abbricht und keine Ausgabe zu Stande kommt von d! Soweit zum mindestens mein Stand der Dinge! Sorry ich kann dir gerade nicht ganz folgen wo das leak entsteht. mfg darkstar999
|
user_unknown
Anmeldungsdatum: 10. August 2005
Beiträge: 17622
Wohnort: Berlin
|
Darkstar999 schrieb: So ich habe hier mal ein kleines Beispiel zum Thema Funktionszeiger zusammengebastelt. | struct Bruch {
int zaehler;
int nenner;
struct Bruch *next;
};
|
Und wenn Du Brüche in Arrays speichern willst, dann schreibst Du die Struktur neu, ohne *next? Und wenn Du eine doppelt verkettete Liste willst, dann schreibst Du es wieder neu? Und wenn Du eine Liste von Fluechen haben willst schreibst Du effektiv wieder den gleichen Listencode - nur mit Flüchen statt Brüchen - neu? Das sieht aber nicht empfehlenswert aus. Ein next-Zeiger hat in einem Bruch meiner Meinung nach nichts verloren (SOC: separation of concerns), und eine Liste sollte agnostisch sein gegenüber ihren Inhalten.
| struct Bruch plus(struct Bruch *a,struct Bruch *b){
struct Bruch *rueck =malloc(sizeof(struct Bruch));
rueck->zaehler = (a->zaehler) + (b->zaehler);
rueck->nenner = (a->nenner) + (b->nenner);
return *rueck;
}
|
Sei froh dass das Dein Mathelehrer nicht sieht! ☺
struct Bruch berechnen (struct Bruch (*modus)(struct Bruch *c, struct Bruch *d), struct Bruch *a, struct Bruch *b)
{
struct Bruch *erg = malloc(sizeof(struct Bruch));
return *erg;
} int main(void) {
struct Bruch *a = malloc(sizeof(struct Bruch));
struct Bruch *b = (struct Bruch *) malloc (sizeof (struct Bruch));
struct Bruch *c = (struct Bruch *) malloc (sizeof (struct Bruch));
struct Bruch *d = (struct Bruch *) malloc (sizeof (struct Bruch)); a-> zaehler = 2;
a-> nenner = 2;
b-> zaehler = 2;
b-> nenner = 2;
printf ("Z%d N%d\n", c-> zaehler, c-> nenner);
printf ("Z%d N%d\n", d-> zaehler, d-> nenner); free (a);
free (b);
free (c);
free (d); return 0;
} }}}
Wenn Du zeigen wolltest, welches Problem jetzt Dein Typ löst, welches meiner nicht löst, sehe ich nichts. Nur 4 Aufrufe von 'free', die ich spare.
Das mit der Dynamischen Datenstruktur oben im Beispiel
... überrascht mich, weil ich eine dynamische Collection nicht so bezeichnet hätte, und nicht mit dem Code des Objekts vermengen würde. Aber wenn man es tut, wie Du, ist das Bruchobjekt selbst keine dynamische Struktur: Es ist ja jeder Bruch neben seiner Bruchhaftigkeit noch ein Knoten, und weder kann er unterschiedlich viele Zeiger auf weitere Elemente haben - etwa in einem Baum könnte das praktisch sein, oder in einer Dequeue - (außer einer notdürftigen Unterscheidung zwischen 0 und 1 next-Element, implementiert als NullPointer) - noch kann das nächste Element etwas anderes als wieder ein Bruch sein. Also sehr dynamisch ist die Struktur so nicht.
ist ja auch nur komplizierter als
Ein Vorteil wurde nicht deutlich gemacht.
|
Darkstar999
Anmeldungsdatum: 21. September 2008
Beiträge: 324
|
user unknown schrieb:
Sei froh dass das Dein Mathelehrer nicht sieht! ☺
Ups inne Ecke stell +dumdidum+ Flüchtigkeitsfehler! mfg darkstar999
|
TraumFlug
Anmeldungsdatum: 16. Juli 2009
Beiträge: 999
Wohnort: zwischen den ohren
|
Darkstar999 schrieb: Zum Thema jegliche Nutzung von malloc ist überflüssig nein da sonst z.b *d adresse 0x00 hat und somit das Programm abbricht und keine Ausgabe zu Stande kommt von d!
Ich meinte ja auch nicht, dass nur das malloc überflüssig ist, sondern dass du unnötig dynamischen Speicher anforderst, wo ein Arbeiten mit lokalen Variablen sehr viel sauberer und effizienter wäre.
Soweit zum mindestens mein Stand der Dinge! Sorry ich kann dir gerade nicht ganz folgen wo das leak entsteht.
return *rueck; Das kopiert die Struct, auf die "rueck" zeigt als return-value auf den Stack und danach wird der "struct Bruch* rueck" quasi "vergessen" und der alloziierte Speicher, auf den er zeigte nie wieder freigegeben. Im Ernst, aus verschiedenen Gründen ist das einer der verkifftesten c-codes seit langem, den ich gesehen habe - wenn man bedenkt, dass du das in einem Thread, der von einem Anfänger gestartet wurde, der grundsätzliche Fragen hatte, quasi als gute Lösung präsentierst, ...kann man nicht mehr schweigen... 😈
|