Problem mit "schreiben" in Struct
-
Das Problem ist aber, dass C-Strings nur eine Vereinbarung sind und anders Funktionieren als in den meisten anderen Programmiersprachen.
Arrays verhalten sich in C auch anderes als normale Variablen.Und gerade das Verständnis vom Zusammenspiel von Zeigern und Arrays ist für die Stringverarbeitung in C enorm wichtig.
Das Verständnis hast du z.Zt nicht. Darum auch deine Fehler.
Und da nützen dir auch keine aus dem Internet zusammen gesuchte Funktionen.
Die haben auch ihre Macken (die du aber nicht erkennen kannst)Wenn du schon Programmieren kannst, dann besorg dir den K&R (Kernighan Ritchie)
-
Danke Dirk, ich werde mir die Kapitel mit zeiger und Arrays mal genauer reinziehen und den KR besorgen.
Wie schon gesagt... "Strings" sind nicht so mein Ding, da ich das sehr sehr selten brauche, darum habe ich mich auch in anderen Sprachen nicht sooo damit beschäftigt.
Noch ein "ursprüngliche" frage:
Bei meinem Code
struct db{char*s1; char *s2;}test1;
wenn ich jetzt *s1 mit malloc speicher zuweise, z.B.: 20, könnte ich dann mit fgets oder dergleichen "einlesen" in &test1.s1 ? Oder bin ich da vom Grundsatz her total falsch?
Ansonsten, wenn ich total falsch liege... was kann oder wofür wird dann solch eine Struktur mit char Pointern benutzt?
Ps.: @ Sepp... ich wollte hier niemanden auf die Füße treten
-
Django2012 schrieb:
Bei meinem Code
struct db{char*s1; char *s2;}test1;
wenn ich jetzt *s1 mit malloc speicher zuweise, z.B.: 20, könnte ich dann mit fgets oder dergleichen "einlesen" in &test1.s1 ? Oder bin ich da vom Grundsatz her total falsch?
Noch nicht ganz richtig. Denn &test1.s1 ist die Adresse des Pointers selbst (der selber eine Variable ist und einen Wert hat, den man ändern kann). Du möchtest dahin schreiben, wo der Zeiger hinzeigt. Also schlicht und einfach test1.s1. Das wird dir klarer werden, wenn du dich mit Zeigern und Zeichenketten beschäftigst.
Wie "kenner der streambuffer" aber schon sagt, ist dies eine etwas komische Vorgehensweise. Wenn du mit malloc fest 20 Zeichen holst, kannst du auch gleich viel einfacher ein Array von 20 Zeichen nehmen. Das ist die für Anfänger empfehlenswerte Methode. Der eigentliche Sinn von malloc, die Zahl der Zeichen flexibel festzulegen, wäre in der Umsetzung wesentlich aufwändiger und wäre bei deinem Lernfortschritt jetzt noch zu früh. Es wäre wahrscheinlich auch gar nicht nötig.
-
Django2012 schrieb:
wenn ich jetzt *s1 mit malloc speicher zuweise, z.B.: 20, könnte ich dann mit fgets oder dergleichen "einlesen" in &test1.s1 ? Oder bin ich da vom Grundsatz her total falsch?
wenn du mit malloc 20 bytes speicher reservierst und die startadresse
(das ist der rückgabewert von malloc im falle einer erfolgreichen reservierung)
in s1 speicherst, dann könntest dutest1.s1 = s1; // test1.s1 nicht &test1.s1 !
schreiben.
erst dann hätte die membervariable s1 deiner struktur diese startadresse gespeichert und erst dann hättest du durch die membervariable s1 zugriff auf die reservierten 20 bytes. diese adresse könntest du an fgets oder an andere funktionen übergeben, das ist richtig.Django2012 schrieb:
was kann oder wofür wird dann solch eine Struktur mit char Pointern benutzt?
zeiger kann man dafür benutzen, speicher während der laufzeit zu reservieren und die größe dieses speichers während der laufzeit zu ändern(vergrößern, verkleinern).
ob sich ein zeiger in einer struktur befindet oder nicht, ist für die reservierung nicht ausschlaggebend.
man packt gern mehrere variable in eine struktur, wenn man dem programm eine gewisse ordnung geben möchte. das hat oft vorteile wie bessere übersichtlichkeit, bessere wartbarkeit des codes, usw.
z.b. lassen sich alle member einer struktur mit nur einer strukturvariable per zeiger als parameter an eine funktion übergeben.
-
hmmm... und ich dachte schon die S7AWL Pointer sind ein Buch mit 7 Siegeln, das kann ja mit C noch interessant werden.
Evtl. wird mir das ja auch noch klarer, wenn mir jmd. folgendes auf C übersetzen könnte? :
Also in etwa so :
//S7 AWL Pseudo L P#0.0 // Einen Pointer auf die Adresse 0.0 laden LAR1 // S7 Pointer werden im Adressregister gespeichert. AUF DB[index] //Datenbaustein mit nummer "index" öffnen init: schleifenindex // schleifenzähler z.b. 10 L 45.5 //lädt den Wert 45.5 T W[AR1, P#8.0] // in das Word 8.0 des Datenbausteins "index" L #typ // Typvarialbe z.B. int 2 da mit Word gearbeitet wird +ar1 // Pointer erhöhen L schleifenindex // schleifenindex wird quasi dekrementiert loop init // schleife wird solange ausgeführt bis zähler auf 0
das wäre ne Array initialisierung wobei das Array aus 10 INT werten besteht.
Ich dachte nun, in C würde ich ja mitint *p1 //pointer definiert p1 = &Erstes Arrayelement // zeigt jetzt auf das erste Element ??
aber hier auf das erste Elemnt zugreifen können.
Das zweite Element wäre dann den Pointer um "1" erhöhen also irgendwie mit dem ++ Operator.Wenn jetzt wie in meinem ursprünglichem Beispiel
struct DB{char *s1; char *s2;}test1;
s1 auf ein(?) char zeigt, dann könnte ich dies mit "&test.S1" adressieren?
Aber die Malloc funktion würde ja wie folgt aussehen: (?)s1 = (char*) malloc (20)
...also brauch ich bei dem char Pointer aus meiner Struktur eigentlich keinen Adressoperator?
für fgets(&test1.s1.....) brauche ich den Adressoperator, da fgets nen Zeiger will, richtig?
-
@Kenner : hab deinen Beitrag erst jetzt gelesen, da ich mit dem Verfassen des meinigens beschäftigt war
wenn du mit malloc 20 bytes speicher reservierst und die startadresse
(das ist der rückgabewert von malloc im falle einer erfolgreichen reservierung)
in s1 speicherst, dann könntest duWäre das dann so :
&s1 = (char*) malloc (20)
?
...sieht mich komisch an....
-
Nein, deine Syntax stimmt überhaupt nicht. Bitte nicht planlos rumraten.
c.rackwitz schrieb:
Wenn du selber Code schreibst, musst du ihn auch verstehen. Code ist kein Haufen von wahllos zusammengeschmissenen Buchstaben und Zeichen, Code ist Logik pur. Du musst genau wissen, warum du wo und welches Zeichen setzt.
Hier ist ein minimales Beispiel:
#include <stdio.h> #include <stdlib.h> int main() { char *string; unsigned num_chars; puts("Wie viele Zeichen?"); scanf("%u ", &num_chars); if (string = malloc(num_chars + 1)) // +1 für Nullterminierung { puts("Gib Zeichen ein:"); fgets(string, num_chars + 1, stdin); printf("Folgendes wurde eingegeben (erste %u Zeichen): %s\n", num_chars, string); } free(string); return 0; }
Bitte versuch jetzt nicht, das Beispiel nach und nach zu modifizieren, bis es zu dem passt, was du hast. Ich verweise nochmals auf obiges, treffendes Zitat von einem früheren Forenmitglied. Lern vernünftig Zeiger und Zeichenketten!
Zeiger und Zeichenketten sind in C nun einmal etwas kompliziert, aber du kommst nicht drumherum. Die lernst du aber nicht aus Internettutorials und auch nicht aus Büchern, deren Autoren das Thema selber nicht verstanden haben. (Das ist kein unnötiger Seitenhieb auf das Buch. J. Wolf hat Zeiger nicht verstanden. Das geht aus den fehlerhaften Beispielen in dem Buch eindeutig hervor.)
-
Django2012 schrieb:
@Kenner : hab deinen Beitrag erst jetzt gelesen, da ich mit dem Verfassen des meinigens beschäftigt war
wenn du mit malloc 20 bytes speicher reservierst und die startadresse
(das ist der rückgabewert von malloc im falle einer erfolgreichen reservierung)
in s1 speicherst, dann könntest duWäre das dann so :
&s1 = (char*) malloc (20)
?
...sieht mich komisch an....struct TestStruct { char* s1; }; int main(void) { struct TestStruct test_struct; char* s1 = malloc(20); if(s1 == NULL) return 0; test_struct.s1 = s1; puts("eingabe:"); fgets(test_struct.s1, 20, stdin); printf("deine eingabe: %s\n", test_struct.s1); free(s1); return 0; }
hier würde man weder malloc, noch zeiger noch strukturen brauchen.
das soll lediglich die syntax zeigen.
-
Danke für beide Beispiele.... Es wird ein bisschen klarer.
Abschließend zu malloc noch eine Frage :
aus der C-Referenz :
void* malloc (size_t size)
in dem Beispiel der C-REfernz dann so ausgeführt :
char * buffer; buffer = (char*) malloc (20);
Bei Euren Beispielen :
[/code]char* s1 = malloc(20)[/code]
undstring = malloc(num_chars + 1)
...wie ist die Referenz zu verstehen,? Ich les die Dinger glaub ich doch öfter falsch...
ist mein :
[/code]s1 = (char*) malloc (20) [/code]
total daneben=?
-
Dann ist deine C-Referenz eine C++-Referenz (wo es das malloc auch gibt, auch wenn man es dort nie benutzt) oder will aus anderen Gründen zu C++ kompatibel sein*. In C braucht man diesen Cast nicht (wegen der anderen Regeln für Konvertierungen zwischen Pointertypen). Das einzige Argument für den Cast ist, dass man dann den C-Code auch mit einem C++-Compiler übersetzen kann. Was man ohnehin nicht tun sollte. Er ist zwar nicht direkt falsch, kann aber ein paar Probleme verursachen und zu sehr schwer zu findenden Fehlern führen. Meine Empfehlung: Weglassen.
*: Da die ersten Treffer bei Google allesamt zu C++-Referenzen führen, nehme ich mal an, dass ersteres der Fall ist. Das ist auch ok, diese Referenzen zu benutzen. Die versuchen in der Regel im Teil der C-Bibliothek auch kompatibel zu C zu bleiben und dort keine C++-Sprachmittel zu verwenden. Aber natürlich sind die Beispiele immer noch in erster Linie für C++ gedacht, was dann eben manchmal zu subtilen Unterschieden wie diesem hier führt. Es sind eben doch verschiedene Sprachen, auch wenn sie wegen des Namens und der Geschichte oft zusammen geworfen werden.
-
Guten morgen Ihr zwei
Also, ich hab mir jetzt von K&R C the Programming Languga 2nd Edition und von einem Herrn Schellong "Moderne C Programmierung - Kompendium & Referenz " besorgt.
Ich denke mal das diese beiden Bücher mir doch weiterhelfen sollten.Nochmals habe ich jedoch eine Frage zu den "Referenzen".
Wie Sepp schon festgestellt hat, war das gestern aus der C++Refernce . My fault.Also gehen wirs mal an :
wenn ich eine selbsterstellte Funktion habe, z.B.:
void set_axis(struct E6Pos *pt, int *status, int *turn)
so muss, ich beim Aufruf wie folgt übergeben : (habs probiert, anders gehts auch nicht)
bla bla set_axis(&Home_Pos, &act_status, &act_trun)
wobei Home_Pos ne Struct vom Typ E6Pos ist.
Also da check ich das mit dem Adressoperator.
So, jetzt aus der Referenz: (fgets)
char *fgets(char *s, int n, FILE *stream)
Hier funktioniert das ganze , z.B. so:
char Data[80] fgets(Data, sizeof(Data), stdin);
Hier brauch ich keine Adressoperator...why? Weil Data festgelegt ist?
hingegen bei folgender Funktion (fwrite)
size_t fwrite(const void *buffer, size_t groesse, size_t anzahl, FILE *stream)
habe ich folgendes Beispiel angesehen :
int main(void) { FILE *stream; long list[NUM]; /*NUM ist als 100 definiert int numwritten; stream = fopen("myfile.dat", "w+b"); /* assign values to list[] */ numwritten = fwrite(list, sizeof(long), NUM, stream); printf("Number of items successfully written : %d\n", numwritten); return 0;
Ok... list ist klar, size of ist klar, NUM?? Naja dazu komme ich noch, stream ist auch klar.
Jetzt ein Beispiel aus dem (mittlerweile auch von mir) verhassten Buch : (Galileo...)
struct { char name[20]; char vornam[20]; char wohnort[30]; int alter; int plz; char Strasse[30]; } adressen; FILE *quelle; strcpy(adressen.name, "Barack"); strcpy(adressen.vornam, "Obama"); strcpy(adressen.wohnort, "Washington D.C"); adressen.alter = 55; adressen.plz = 23223; ... if((quelle=fopen("adres.dat", "w+b")) == NULL) ... fwrite(&adressen, sizeof(struct adressen), 1, quelle);
??? Wieso braucht er jetzt den Adressoperator? bei dem sizeof das "struct" nimmt er im nachfolgenden Beispiel nicht mehr her. Aber warum die 1? Bei dem andren Beispiel wurde NUM angegeben (da war das ganze ein Array, mit 100 longs) ... Also vermute ich 1.) Beispiel hat 100 Long einträge mit der größe von long geschrieben, und das Galileo Beispiel will nur einmal die Struct schreiben. OK
Aber wie zum Teufel ist jetzt so ne Referenz zu lesen?
Bei einer selbsterstellen funktion die nen Pointer in der Parameterliste enthält brauch ich zum zu weisen den "&".
Wenn ich mir jetzt die Referenz so ansehe... und dann die Beispiele.... Ich habs auf probiert, für die Struct gings mit dem "&". Wahh...
-
Deine Lernweise ist (untertrieben gesagt) unkoordiniert.
Du hangelst dich von einer grundlegenden Fragestellung zur nächsten, z.Z. scheint fwrite dein Problem.
Außerdem zitierst du falschen, uncompilierbaren Code, nämlichstruct { ... } adressen;
ist eine Definition einer Variablen,
dann ist aber
sizeof( struct adressen )
unmöglich.
Der Adressoperator & ist ein Synonym für "Adresse auf", und ist nur für Variablen (mit Name, Typ, Speicherbereich und Wert) gültig, also nicht für Typen.
Der operator sizeof ist auch für Typen erlaubt.
-
Lies im K&R das Kapitel Pointers and Arrays (5.3 bei mir).
Da wird die "Ähnlichkeit" von Zeigern und Arrays erklärt, die
char *fgets(char*, int, FILE*); void f(void){ char Data[80] fgets(Data, sizeof(Data), stdin); }
zugrundeliegt.
-
Dieser Code stammt nicht von mir sondern ist 1 zu 1 aus dem GalileoBuch!!
Das da was nicht stimmt dachte ich mir schon.
Hier der Link :
http://openbook.galileocomputing.de/c_von_a_bis_z/016_c_ein_ausgabe_funktionen_017.htm#mj72d8bcd5c9fd159c248b24caf558e345Unter Bockweise schreiben mit fwrite Abb 16.7
Nein, ich hangle mich auch nicht, ich habe schon erfolgreich mit fwrite geschrieben und seit ich die Diskussion gestern angestossen habe, bzw. meine Frageorgie , ist mir rückwirkend doch etwas unklar.
fwrite war nur ein Beispiel für das Lesen der C Refernzen, das mir Kopfzerbrechen bereitet.
-
DirkB schrieb:
Arrays verhalten sich in C auch anderes als normale Variablen.
Und gerade das Verständnis vom Zusammenspiel von Zeigern und Arrays ist für die Stringverarbeitung in C enorm wichtig.
Das Verständnis hast du z.Zt nicht. Darum auch deine Fehler.
Im K&R gibt es extra ein Kapitel über
Zeiger und Vektoren
(Arrays)Der Name eines Array (also ohne die []) steht schon für die Adresse des ersten Elements vom Array. Das ist gleichbedeutend mit
&Data[0]
Bei fwrite steht der erste Parameter für die Adresse, von wo aus die Daten geschrieben werdeb sollen.
Der zweite gibt die Größe eines Elements an,
der dritte die Anzahl der Elemente und
der vierte den Stream, über den die Ausgabe erfolgen soll.Beim ersten Beispiel schreibst du 100 long Werte (darum sizeof(long), 100)
Beim zweiten Beispiel schreibst du eine ganze Struct
-
Falls du dich fragst, warum bei
fwrite
zwei Paramter für die Anzahl angegeben werden, man kann ja schließlich auchsize*count
rechnen (wie bei malloc).Dann schau dir mal den Rückgabewert von
fwrite
an. Der gibt die Anzahl der erfolgreich gelesenen Elemente an (und nicht Byte).
-
DirkB schrieb:
Der Name eines Array (also ohne die []) steht schon für die Adresse des ersten Elements vom Array. Das ist gleichbedeutend mit
&Data[0]
.
.
Beim ersten Beispiel schreibst du 100 long Werte (darum sizeof(long), 100)
Beim zweiten Beispiel schreibst du eine ganze StructDarum für die Struct das "&" oder? Weil der Structname allein nicht wie bei dem Array die Adresse des ersten Members enthält?
-
structs sind keine Arrays!
Du kannst structs einander zuweisen und auch als Rückgabewert einer Funktion nutzen.
struct foo barbar(void); ... struct foo bar1, bar2; bar1 = barbar(); bar2 = bar1;
Das geht mit Arrays nicht!
-
schon klar das eine struct kein array ist .
Darum für die Struct das "&" oder? Weil der Structname allein nicht wie bei dem Array die Adresse des ersten Members enthält
Es ging nur um das & .
Kennt jmd. noch ein gutes Refernz buch in Druckversion?
-
Django2012 schrieb:
Kennt jmd. noch ein gutes Refernz buch in Druckversion?
"C in a nutshell" - O'Reilly
ist, glaube ich, die umfassendste C-Referenz (auch C99).
http://www.amazon.de/C-Nutshell-In-OReilly/dp/0596006977
Gibt's auch als PDF im Internet, mir ist aber die gedruckte Version lieber.