Warum ist "int *ptr = new int[0])!=NULL" ??
-
Hallo zusammen,
untiges Test-Programm hat mich verwundert !! Wenn ich ein dynamisch erzeugtes Array mit 0 Elementen allokiere, bekomme ich einen Pointer auf eine gültige Adresse zurück... ich dachte immer, daß ich darauf einen Nullpointer erhalte. Das ganze geht sogar soweit, daß wenn ich den Code unter dem Gcc/G++ kompiliere, ich sogar einen Wert ins Array schreiben kann. Unter MS Visual Studio geht das nicht.
Ist das inkonsequent oder verstehe ich die Logik dahinter noch nicht ?
Winn

#include <stdio.h> #include <stdlib.h> int main() { int *Array = NULL; fprintf(stderr,"Pointer:: %p\n",Array); Array = new int[0]; if (Array==NULL) fprintf(stderr,"Nullpointer !!\n"); else fprintf(stderr,"Pointer:: %p\n",Array); Array[0]=12; fprintf(stderr,"Inhalt:: %d\n",Array[0]); delete[] Array; //Array=(int *)calloc(0,sizeof(int)); //if (Array==NULL) fprintf(stderr,"Nullpointer !!\n"); //else fprintf(stderr,"Pointer:: %p\n",Array); //Array[0]=12; //fprintf(stderr,"Inhalt:: %d\n",Array[0]); //free(Array); return 0; }
-
Arrays sind in C/C++ leider nicht so richtig sauber implementiert. Die Grenzen eines Arrays können problemlos überschritten werden. Du schreibst dann halt in irgendwelche Speicherbereiche.
Array[0]=12;Diese Zeile füllt das erste Element deines Arrays. Da die tatsächliche größe des Arrays aber 0 ist, schreibst du schon außerhalb des Array-Speichers. Du könntest auch
Array[1]=8; fprintf(stderr,"Inhalt:: %d\n",Array[1]);in dein Programm einfügen, ohne dass der GCC motzt. Ich hoffe das Programm wird dann allerdings nicht zur Steuerung von Atomkraftwerken genutzt... ;o)
-
ich glaub es geht mehr um die frage warum man eine adresse zurückbekommt wenn man 0 byte allokiert
würd ich auch gern wissen
was sagt der standard?
-
Also meines Wissens wird bei einem Fehler in new nicht NULL zurück gegeben, sondern eine Exception geworfen. Allerdings kann man compilerspezifisch das mit dem NULL-Verhalten einstellen.
Bei dem 0 Byte allokieren wird allerdings auch keine Exception geworden ... .
Mehr fällt mir da jetzt auch nicht ein
-
Winn schrieb:
Wenn ich ein dynamisch erzeugtes Array mit 0 Elementen allokiere, bekomme ich einen Pointer auf eine gültige Adresse zurück
Das ist richtig und genau so ist es ja auch gedacht. Das heisst, solche
if (!p) // Fehler -> blaFehlerabfanggeschichten wie in C sind überflüssig und vereinfachen den Code.
new gibt NIEMALS einen Nullzeiger zurück. Sollte etwas schief gehen, dann wird eine Exception geworfen. Die Exception freie Variante ist new(std::nothrow).Winn schrieb:
Das ganze geht sogar soweit, daß wenn ich den Code unter dem Gcc/G++ kompiliere, ich sogar einen Wert ins Array schreiben kann. Unter MS Visual Studio geht das nicht.
Ja, sowas fällt unter die Rubrik undefiniertes Verhalten. Dh, es kann ALLES passieren.
-
Im VS 6.0 hast du sicher im Debug-Modus gearbeitet. Da werden einige zusätzliche Daten automatisch mit generiert zur Fehlersuche und dynamische Felder noch besonders kontrolliert. Daher kommen dann die Speicherzugrifffehler. Kannst ja mal im Release-Modus kompilieren und starten, da kann es dann sein das du keinen Fehler bekommst.
-
was wurde denn für platformen definiert die keine exceptions unterstützen?
-
Pellaeon schrieb:
Kannst ja mal im Release-Modus kompilieren und starten, da kann es dann sein das du keinen Fehler bekommst.
Tatsächlich... im Release-Mode bekomme ich keinen Fehler !!
groovemaster schrieb:
new gibt NIEMALS einen Nullzeiger zurück. Sollte etwas schief gehen, dann wird eine Exception geworfen. Die Exception freie Variante ist new(std::nothrow).
Sag niemals nie... siehe unten
MSDN::C++ Language Reference schrieb:
If the request is for zero bytes of storage, operator new returns a pointer to a distinct object (that is, repeated calls to operator new return different pointers). If there is insufficient memory for the allocation request, operator new returns NULL or throws an exception (see The new and delete Operators for more information).
Dennoch verstehe ich nicht, wie man eine gültige Adresse bekommt... irgendwie ist das so wie, ich geh zum Bäcker und sage: Ich möchte bitte 0 Brötchen - und er gibt mir 1 !!
-
Winn schrieb:
Dennoch verstehe ich nicht, wie man eine gültige Adresse bekommt... irgendwie ist das so wie, ich geh zum Bäcker und sage: Ich möchte bitte 0 Brötchen - und er gibt mir 1 !!
Nö. Du bestellst ja nicht den Inhalt sondern den Container. Du sagst: "Ich möchte bitte eine Tüte in die 0 Brötchen reinpassen", nicht "ich möchte 0 Brötchen". Eine Tüte in die 0 Brötchen reinpassen kann jetzt entweder eine sehr sehr kleine Tüte oder aber auch gar keine Tüte sein. Der Standard hat sich für die erste Variante entschieden, da diese Variante weniger Randfälle produziert. So kannst du dynamische Arrays einfach für beliebige n spezifizieren ohne das du für n == 0 noch eine extra Ausnahme hast.
Demnach ist ein Array mit Platz für 0 Objekte ein Objekt (hat also eine Adresse und damit eine Größe != 0), jeder Zugriff auf den Inhalt des Arrays ( Derefernzierung des Pointers) ist allerdings illegal.
-
Winn schrieb:
Sag niemals nie... siehe unten
Dir ist hoffentlich klar, dass wir hier über Standard C++ reden und nicht über "MS C++". Die Referenz ist demnach ISO/IEC 14882:1998(E), respektive ISO/IEC 14882:2003(E), und nicht MSDN.
Und dort steht zB folgendesISO/IEC 14882:2003(E) schrieb:
When the value of the expression in a direct-new-declarator is zero, the allocation function is called to allocate an array with no elements.
ISO/IEC 14882:2003(E) schrieb:
unless an allocation function is declared with an empty exception-specification (15.4), throw(), it indicates failure to allocate storage by throwing a bad_alloc exception (clause 15, 18.4.2.1); it returns a non-null pointer otherwise. If the allocation function is declared with an empty exception-specification, throw(), it returns null to indicate failure to allocate storage and a non-null pointer otherwise.
Und daraus folgt, dass new NIEMALS null zurückgibt. Lediglich bei new(std::nothrow) besteht die Möglichkeit. Die Definition der Operator new Funktionen kannst du dir ja selbst anschaun.
-
Winn schrieb:
MSDN::C++ Language Reference schrieb:
If the request is for zero bytes of storage, operator new returns a pointer to a distinct object (that is, repeated calls to operator new return different pointers). If there is insufficient memory for the allocation request, operator new returns NULL or throws an exception (see The new and delete Operators for more information).
Das ist doch immer noch (fast) exakt das was der Standard sagt:
Wenn new speicher allokieren kann tut es dass in der größe n, falls
nicht wirft es eine Exception ODER gibt NULL zurück.
Auf Systemen wo es keine Exception gibt, definiert der Standard dies sicherlich
ähnlich.phlox