Hallo, ich arbeite mich gerade in c ein und bin nun noch nicht ganz Freund mit Pointern und Adressoperatoren. Nun möchte ich ein char array "Rücksetzen" sprich alle Werte 0 setzen und dies mit einer Fkt. realisieren um die Arbeit mit Pointern &Co. zu üben. Das Array soll mal 4 chars beinhalten. void array_loeschen(uchar *nr ){ uchar i; for(i=0 ; i>3 ; i++) nr[i]=0; } ///vorher: 2,3,4,5 //Aufruf: array_loeschen(&nummern); //danach: 0,0,0,0 ?? Was mache ich falsch, denn es läuft so nicht? Dank und Gruß
Hi, Du machst zwei Sachen falsch: Zum einen sollte der Aufruf der Lösch-Funktion array_loeschen(nummern); lauten, da ein Array ja nichts anderes als ein Pointer ist. Das zweite: Schau Dir mal die Abbruch-Bedingung der for-Schleife an... MfG Daniel Jelkmann
Hi dein Problem sind nicht die Pointer sondern du hast noch nicht verstanden wie eine for-Schleife funktioniert. Ich geb dir mal einen Tip: vvvvv vvv v for(i=0 ; i>3 ; i++) ^ ^^^ ^^^^^ ;-) Matthias
ups, doch, ich hab die for Schleife schon verstanden (da ist ja auch nicht viel dran), war halt nur ein >< Dreher. Danke
Hi, selbst wenn es nur ein ><-Dreher war, ist die Bedingung für 4 Zeichen immer noch falsch ;-) MfG Daniel Jelkmann
Hi, wie nö? Wenn da steht: for(i=0 ; i>3 ; i++) und es ein Dreher war, dann müsste er ja "for(i=0 ; i<3 ; i++)" gemeint haben. Damit läuft die Schleife von 0 über 1 bis zum Index i=2... Das sind drei Zeichen... Das Array besteht aber laut Posting aus 4 Zeichen... Oder bezog sich das "nö" jetzt auf einen anderen Beitrag? MfG Daniel Jelkmann
Wenn "nummern" ein Array ist (z.B. char nummern[4]), dann ist &nummern der Pointer auf den Pointer des 0.en Elements. Was du willst müsste dann entweder array_loeschen(&nummern[0]); oder einfach nur array_loeschen(nummern); lauten. Wenn Nummern eine Variable ist (char nummern) ist zwar der Aufruf richtig, aber dann würde die Schleife ins Nirvana laufen...
> Wenn "nummern" ein Array ist (z.B. char nummern[4]), dann ist > &nummern > der Pointer auf den Pointer des 0.en Elements. Nein. Zwar zeugt &nummern davon, dass man das Kapitel über Pointer&Arrays im K&R noch nicht verstanden hat, aber es ergibt denselben Code wie nummern: $ cat foo.c int nummern[4]; void * a(void) { return (void *)&nummern; } void * b(void) { return (void *)nummern; } $ avr-gcc -Os -S foo.c $ cat foo.s ... .global a .type a, @function a: ldi r24,lo8(nummern) ldi r25,hi8(nummern) ret .size a, .-a .global b .type b, @function b: ldi r24,lo8(nummern) ldi r25,hi8(nummern) ret .size b, .-b ... (Mal alle Kommentare rausgeworfen wegen der Übersichtlichkeit.)
Das ist interessant. Soweit ich mich erinnere dürfte das laut ANSI-C nicht die selbe Wirkung haben. Vielleicht unterstützt der AVR-GCC gar keine Pointer auf Pointer. Sieht auf alle Fälle so aus. Oder er optimiert das weg (-Os)
> Das ist interessant. Soweit ich mich erinnere dürfte das laut ANSI-C > nicht die selbe Wirkung haben. Deine Erinnerung ist falsch. > Vielleicht unterstützt der AVR-GCC gar keine Pointer auf Pointer. Mach's mal halblang. Der GCC ist ein C-Compiler und keine Krücke. > Sieht auf alle Fälle so aus. Oder er optimiert das weg (-Os) Nein, mit -O0 hat man lediglich ein bisschen Stackframe-Gewurschtel zusätzlich. Glaub's mal, die Adresse eine Arrays ist einfach mal kein Zeiger auf einen Zeiger. Auch wenn man ein Array meistenteils wie einen Zeiger benutzen kann: beides ist nicht identisch.
> Soweit ich mich erinnere dürfte das laut ANSI-C nicht die selbe > Wirkung haben. Doch, muß es sogar. "return (void *)nummern;" ergibt die Adresse des ersten Elements des Arrays. "return (void *)&nummern;" ergibt die Adresse des Arrays selbst. Das erste Element ist immer an der Startadresse des Arrays, also sind die Adressen gleich. > Vielleicht unterstützt der AVR-GCC gar keine Pointer auf Pointer. Doch, tut er. Aber in dem Programm kommen keine vor. Du hast Zeiger und Arrays auch noch nicht verstanden. Wichtig ist, daß ein Zeiger eben ganz und gar nicht dasselbe wie ein Array ist. Sie verhalten sich oft gleich, aber eben nicht immer. @mikes: Was spricht eigentlich dagegen, memset zu verwenden?
>Wichtig ist, daß ein Zeiger eben ganz >und gar nicht dasselbe wie ein Array ist. Natürlich nicht, das sind ja auch im Speicher aufeinanderfolgende Variablen. Schließlich ist ja auch eine Variable auch kein Zeiger (z.B. char Foo). C behandelt halt Arrays speziell und mit "nummern" (wenn das wieder das Array von vorhin ist) ist die Adresse vom 0. Element gemeint. Nun dachte ich (was ja falsch ist, ich seh's ja ein!), das &nummern gleichzusetzen ist, wie z.B. int Addr; //Hält dann den Wert der Adresse char *Zeichen //Pointer ... Addr=&Zeichen //das wäre dann Pointer auf Pointer ...
Hi > int Addr; //Hält dann den Wert der Adresse > char *Zeichen //Pointer > ... > Addr=&Zeichen //das wäre dann Pointer auf Pointer > ... Addr ist kein Pointer auf einen Pointer da Addr gar kein Pointer ist :-) Addr enthält nur die Adresse der Variablen Zeichen. Ob Zeichen jetzt ein char, ein int, ein foo oder ein *foo ist spielt dabei überhaupt keine Rolle. Matthias
Mal ne andere Lösung. void array_loeschen(unsigned char *buffer ) { memset(&buffer,0,sizeof(buffer)); }
Hi und was soll das auser einem Programmierfehler sein? ;-) Dein Code "nullt" die ersten n Elemente von Buffer wobei n dabei nur von der Größe des Pointers (also typischerweise 2, 4 oder 8 Byte) abhängig ist. Matthias
> Mal ne andere Lösung. > void array_loeschen(unsigned char *buffer ) > { > memset(&buffer,0,sizeof(buffer)); > } Kann nicht funktionieren. Würde nur zwei Bytes in buffer löschen, da sizeof(buffer) == 2 ist. Innerhalb einer Funktion geht das mit sizeof() so gar nicht, da der generierte Code nicht wissen kann, wie groß das Array hinter dem übergebenen Zeiger ist. Mit einem Makro würde es gehen: #define array_loeschen(ary) memset((ary), 0, sizeof(ary))
Müßte aber so funktionieren. void array_loeschen(unsigned char *buffer ) { memset(&buffer,0,strlen(buffer)); }
Hi, memset(&buffer,0,strlen(buffer)) macht wohl nur in bestimmten Fällen, das was man erwarten würde. Wenn das erste Zeichen im Array eine Null ist, bewirkt die Funktion beispielsweise garnichts, dh. die restlichen Array-Elemente bleiben unverändert. Ich glaube oben war nie die Rede davon, dass buffer einen String enthält... Daher hilft es nur, die Array-Größe zu übergeben oder eben soetwas zu basteln, wie Jörg es vorgeschlagen hat. MfG Daniel Jelkmann
@Thomas: Wie ermittelt strlen die Größe von buffer? Indem es nach einer Null im String sucht. Bei diesem Beispiel handelt es sich aber nicht um einen String, d.h. Du kannst auch nicht erwarten, dass irgendwo eine Null steht. Im schlimmsten Fall wird gelöscht, bis irgendwo in einer Variablen Null steht. Bis dahin wird alles gelöscht - und nicht nur buffer. Beim anderen Extrem steht gleich am Anfang von buffer eine Null. Dann wird garnichts gelöscht - auch wenn der Rest des Arrays ungleich Null ist. Die saubere Lösung - meiner Meinung nach: Mit typedef sich einen Buffertyp definieren. Den Funktionen als Übergabeparameter keinen Ptr auf *uchar o.ä. mitgeben sondern einen Ptr auf den Buffertyp. Dann funktioniert auch sizeof überall - auch innerhalb von Funktionen. Gruß, Stefan
@Thomas > void array_loeschen(unsigned char *buffer ) > { > memset(&buffer,0,strlen(buffer)); > } Das kannst Du auch einfacher haben void array_loeschen(unsigned char *buffer ) { buffer[0] = '\0'; } Es war nie die Rede von einem Buffer fuer einen String.
@Stefan Du musst aber vorsichtig sein. Der sizeof muss auf *Ptr losgelassen werden. Sonst hast Du wieder nur einen sizeof von einem Pointer typedef unsigned char buffer_t[64]; void array_loeschen( buffer_t * buffer ) { memset( &buffer, 0, sizeof( *buffer ) ); } Hat halt einen Nachteil: geht nur mit buffer_t Arrays. Wenns allgemein sein soll, hilft alles nichts: Die Groesse des Arrays muss Parameter sein. Alles andere ist eine Einladung zu Fehlern. Genau dieses ist auch das Problem mit der Standard-Funktion gets(). Da sie die Array-Groesse nicht mitbekommt, hat sie keine Chance sich gegen misbrauch zu wehren. Daher gets() ist fuer Programmierer eine no-no Funktion. Immer fgets() verwenden. Bei der wurde dieser Kardinalfehler in der Argumentliste nicht gemacht.
Hallo Karl Heinz, > Du musst aber vorsichtig sein. Der sizeof muss > auf *Ptr losgelassen werden. Sonst hast Du wieder > nur einen sizeof von einem Pointer Klar ;-) Ehrlich gesagt war ich zu faul, die Lösung gleich komplett auszuformulieren. > Hat halt einen Nachteil: geht nur mit buffer_t Arrays. Das kann auch ein Vorteil sein ... es gibt einen Fehler, wenn man Schrott übergibt ... Viele Grüße, Stefan
In C++ könnte man sich auch ein Template basteln: template<typename T, size_t Size> static inline void array_loeschen(T (&buffer)[Size]) { memset(buffer, 0, sizeof(T) * Size); }
>> Hat halt einen Nachteil: geht nur mit buffer_t Arrays. > > Das kann auch ein Vorteil sein ... es gibt einen Fehler, wenn man > Schrott übergibt ... Auch hier wieder: Extreme Vorsicht. Es ist absolut wichtig hier einen Pointer zu uebergeben. zb. Kompiliert dieses: #include <memory.h> typedef unsigned char buffer_t[64]; void array_loeschen( buffer_t buffer ) { memset( &buffer, 0, sizeof( buffer ) ); } int main() { unsigned char Test[32]; array_loeschen( Test ); } ohne Probleme. typedef, im Gegensatz zu seiner Bezeichnung, definiert eben keinen neuen Typ, sondern erzeugt nur einen Alias dafuer. Im obigen Gegen-Beispiel ist es fuer den Compiler immer noch so, dass er jeden beliebigen Pointer auf unsigned char fuer buffer_t akzeptiert. Denn buffer_t ist nur ein anderer Name fuer ein unsigned char Array, und wie wir alle wissen werden Arrays immer per Pointer uebergeben. d.h. ob Du void array_loeschen( buffer_t buffer ) schreibst, oder void array_loeschen( unsigned char* buffer ) oder void array_loeschen( unsigned char buffer[] ) macht fuer den Compiler keinen Unterschied.
Tschuldigung. Die fehlerhafte Version muss natuerlich void array_loeschen( buffer_t buffer ) { memset( buffer, 0, sizeof( *buffer ) ); } lauten. Ist zwar in der Argumentliste immer noch problematisch, jedoch ist der memset jetzt korrekt.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.