Warum geben Sie die Größe an, wenn Sie malloc in C verwenden?

Lesezeit: 9 Minuten

Benutzer-Avatar
Andreas Gretsch

Nehmen Sie den folgenden Code:

int *p = malloc(2 * sizeof *p);

p[0] = 10;  //Using the two spaces I
p[1] = 20;  //allocated with malloc before.

p[2] = 30;  //Using another space that I didn't allocate for. 

printf("%d", *(p+1)); //Correctly prints 20
printf("%d", *(p+2)); //Also, correctly prints 30
                      //although I didn't allocate space for it

Mit der Linie malloc(2 * sizeof *p) Ich weise Platz für zwei ganze Zahlen zu, richtig? Aber wenn ich ein hinzufüge int bis zur dritten Position werde ich noch richtig zugeordnet und abrufbar.

Also meine Frage ist, Warum geben Sie eine Größe an, wenn Sie verwenden malloc ?

  • Sie scheinen sich für p entschieden zu haben[3] weil es größer als 2 und damit “out of range” ist. Sie haben Recht, aber denken Sie daran, dass Sie 0-indiziert denken müssen, also sogar p[2] selbst ist außerhalb der Reichweite. Wenn Sie Platz für zwei Ints zugewiesen haben, können Sie die Ints mit *p (oder p[0]) und *(p+1) (oder p[1]), Nicht p[1] und P[2].

    – Tyler

    6. August 2009 um 20:07 Uhr

  • Zusätzlich zu allen Antworten, die auf das Problem hinweisen, haben Sie einen garantierten Segfault in Ihren Händen, wenn malloc NULL zurückgegeben hat, was zulässig ist. Überprüfen Sie immer den Rückgabewert von malloc, bevor Sie es verwenden. Wenn es NULL ist, weigert sich der Speichermanager, Ihnen weiteren Speicher zuzuweisen (im Allgemeinen, weil Sie zu viel angefordert haben oder alles aufgebraucht ist, was er Ihnen zu geben bereit ist).

    – Bob Somers

    6. August 2009 um 20:39 Uhr

  • Mach dir keine Sorgen. Es ist keine dumme Frage, es ist eine “Ich bin neu in Low-Level-Programmierkonzepten”-Frage. Stepancheg muss lernen, die Neulinge nicht zu beißen.

    – Tyler McHenry

    6. August 2009 um 21:56 Uhr

  • Es scheint, als hätte sich niemand die Zeit genommen zu erklären, warum malloc diesen zusätzlichen Speicherplatz für Sie zu verstecken scheint. Malloc muss den angeforderten Speicherplatz zuweisen + ein bisschen mehr, um seine eigenen Metadaten über den zugewiesenen Speicher zu speichern. Darüber hinaus kann malloc je nach Implementierung einfach einen großen Teil des Speichers vom Betriebssystem anfordern, damit es das Betriebssystem nicht erneut fragen muss, wenn Sie ein anderes malloc aufrufen (dies ist zu stark vereinfacht, aber ich hoffe, es erklärt es).

    – Falaina

    6. August 2009 um 22:09 Uhr

  • @Falaina, das ist nicht ganz richtig. Malloc weist nicht unbedingt den fraglichen zusätzlichen Platz zu. Ja, malloc funktioniert so, aber es kann Metadaten ablegen Vor den Zeiger, den es Ihnen gibt, oder ganz woanders. Nur weil p[3] scheint zu funktionieren, bedeutet nicht, dass Sie die Metadaten von malloc gefunden haben. Es kann sich um den Speicher einer anderen Variablen oder um einen vollständig ungenutzten Teil des virtuellen Speicherplatzes handeln.

    – Tyler McHenry

    6. August 2009 um 23:44 Uhr

Benutzer-Avatar
Sinan Ünür

Einfache Logik: Wenn Sie nicht auf einem legalen Parkplatz parken, passiert möglicherweise nichts, aber gelegentlich wird Ihr Auto abgeschleppt und Sie können mit einer hohen Geldstrafe stecken bleiben. Und manchmal, wenn Sie versuchen, den Weg zu der Abschleppstelle zu finden, wo Ihr Auto abgeschleppt wurde, werden Sie vielleicht von einem Lastwagen überfahren.

malloc gibt Ihnen so viele legale Parkplätze, wie Sie gefragt haben. Sie können versuchen, woanders zu parken, es scheint zu funktionieren, aber manchmal funktioniert es nicht.

Bei Fragen wie dieser ist die Speicherzuweisungsabschnitt der C-FAQ ist ein nützliches Nachschlagewerk. Sehen 7.3b.

In einer verwandten (humorvollen) Anmerkung siehe auch eine Liste von Pannen durch KUNST.

  • Perfekte Metapher. Sie können Tag für Tag falsch parken und vielleicht passiert nichts Schlimmes. Aber es besteht immer noch die Möglichkeit, abgeschleppt oder mit einem Strafzettel belegt zu werden, also sollten Sie es nicht tun.

    – Tyler

    6. August 2009 um 20:09 Uhr

  • Sie geben eine gute Erklärung ab, Sie erhalten Upvotes. Danke für die Erklärung.

    – David Thornley

    6. August 2009 um 21:37 Uhr

  • Die Analogie ist gut, aber Sie erklären nicht, was los ist. Es scheint offensichtlich für Leute, die das Problem verstehen … aber wenn er das Problem verstanden hätte, hätte er die Frage nicht gestellt. Dass das Programm abstürzen oder der verwendete Speicher überschrieben werden könnte, ist nicht offensichtlich. Erklären Sie, was sich hinter dieser Analogie verbirgt, und es ist ein einfaches +1.

    – Beška

    6. August 2009 um 21:38 Uhr

  • +1. Ausgezeichnete Analogie. Und die verschwendete Zeit^H^H^H^H^H, die damit verbracht wird, die Gedächtnisverfälschungen aufzuspüren, ist die Strafe für das Vergehen.

    – Andreas Y

    6. August 2009 um 21:57 Uhr

  • @AndrewY: Wenn du Glück hast. “Back to School, Mr. Bean” bietet eine realistischere Ansicht. Als Mr. Bean ein Auto aus einem abgesperrten Parkplatz schiebt und selbst benutzt, bekommt er keinen Strafzettel. Stattdessen wird die geplante Demonstration der „über alles fahren“-Fähigkeiten eines Panzers mit dem Fahrzeug in diesem Raum wie geplant fortgesetzt, wobei Mr. Beans Fahrzeug verwendet wird und nicht das, das er verdrängt hat.

    – Superkatze

    20. April 2012 um 16:43 Uhr

Benutzer-Avatar
Igal Serban

C ließ dich freundlicherweise in den Kopf schießen. Sie haben gerade zufälligen Speicher auf dem Heap verwendet. Mit unabsehbaren Folgen.

Haftungsausschluss: Meine letzte echte C-Programmierung habe ich vor etwa 15 Jahren gemacht.

  • Kein Haftungsausschluss erforderlich, diese Antwort ist absolut richtig. Normalerweise ist die nächste Variable, die Sie zuweisen, diejenige, die überschrieben wird, aber wenn Sie wirklich Pech haben, könnten Sie den Variablenspeicherplatz eines anderen Programms treffen und etwas Zufälliges vermasseln.

    – Rachitis

    6. August 2009 um 20:22 Uhr

  • Damit meinte ich, wenn Sie nach der Deklaration von p auch int* q = malloc(sizeof(int)); (ein Array mit einem Element), ist es wahrscheinlich (aber nicht garantiert), dass p[2] == f[0]. Dies führt auch Fälle ein, in denen Ihr Programm möglicherweise weiterläuft und keine Verwüstung anrichtet, und dann tritt plötzlich ein Fall auf, in dem p[2] != q[0] und ein Fehler passiert einmal… Diese unvorhersehbaren Fehler, die kommen und gehen, sind extrem schwer zu debuggen.

    – Rachitis

    6. August 2009 um 20:24 Uhr

Benutzer-Avatar
Lasse V. Karlsen

Lassen Sie mich Ihnen eine Analogie geben, warum dies “funktioniert”.

Nehmen wir an, Sie müssen eine Zeichnung zeichnen, also nehmen Sie ein Blatt Papier, legen es flach auf Ihren Tisch und beginnen mit dem Zeichnen.

Leider ist das Papier nicht groß genug, aber Sie kümmern sich nicht darum oder bemerken es nicht und zeichnen einfach weiter.

Wenn Sie fertig sind, treten Sie einen Schritt zurück und sehen sich Ihre Zeichnung an, und sie sieht gut aus, genau so, wie Sie es sich vorgestellt haben und genau so, wie Sie es gezeichnet haben.

Bis jemand vorbeikommt und sein Stück Papier aufhebt, das er auf dem Tisch liegen gelassen hat, bevor Sie es erreicht haben.

Jetzt fehlt ein Stück der Zeichnung. Das Stück, das Sie auf das Papier dieser anderen Person gezeichnet haben.

Außerdem hat diese Person jetzt Teile Ihrer Zeichnung auf ihrem Papier und macht sich wahrscheinlich mit allem, was sie stattdessen auf dem Papier haben wollte, herum.

Während Ihre Speicherauslastung also zu funktionieren scheint, tut sie dies nur, weil Ihr Programm beendet wird. Lassen Sie einen solchen Fehler in einem Programm, das eine Weile läuft, und ich kann Ihnen garantieren, dass Sie seltsame Ergebnisse, Abstürze und so weiter erhalten.

C ist wie eine Kettensäge auf Steroiden aufgebaut. Es gibt fast nichts, was Sie nicht können. Das bedeutet auch, dass Sie wissen müssen, was Sie tun, sonst sägen Sie durch den Baum und in Ihren Fuß, bevor Sie es wissen.

  • Dies ist eine großartige Analogie, da sie auch etwas auf die Frage „Warum trifft das nicht zu?“ beantwortet; Man könnte einen Rahmen um sein Blatt Papier bauen, damit der Stift nicht darüber hinauskommt, aber das wäre sicherlich mehr Arbeit, als nur ein Blatt Papier zu nehmen und zu zeichnen. In einigen Umgebungen werden die zusätzlichen Kosten des Rahmens als lohnend angesehen. In anderen Umgebungen gelten Menschen mit Anhängern als ausreichend vertrauenswürdig, sodass sie sich nicht um Rahmen kümmern müssen.

    – Superkatze

    21. November 2011 um 1:06 Uhr

Du hast (Pech) Glück. Zugriff auf p[3] ist undefiniert, da Sie diesen Speicher nicht für sich selbst zugewiesen haben. Das Lesen/Schreiben des Endes eines Arrays ist eine der Möglichkeiten, wie C-Programme auf mysteriöse Weise abstürzen können.

Dies könnte beispielsweise einen Wert in einer anderen Variablen ändern, die über malloc zugewiesen wurde. Das bedeutet, dass es später abstürzen kann und es sehr schwierig sein wird, den (nicht verwandten) Code zu finden, der Ihre Daten überschrieben hat.

Schlimmer noch, Sie könnten einige andere Daten überschreiben und es vielleicht nicht bemerken. Stellen Sie sich vor, dies überschreibt versehentlich den Geldbetrag, den Sie jemandem schulden 😉

In der Tat, malloc weist Ihrer dritten Ganzzahl nicht genügend Platz zu, aber Sie hatten “Glück” und Ihr Programm ist nicht abgestürzt. Sie können nur sicher sein, dass malloc genau das zugeteilt hat, wonach Sie gefragt haben, nicht mehr. Mit anderen Worten, Ihr Programm hat in einen Speicherbereich geschrieben, der ihm nicht zugewiesen wurde.

Malloc muss also die Größe des Speichers kennen, den Sie benötigen, da es nicht weiß, was Sie am Ende mit dem Speicher machen werden, wie viele Objekte Sie in den Speicher schreiben möchten usw.

  • Ich würde behaupten, dass dies eigentlich Pech ist 🙂

    – bdonlan

    6. August 2009 um 19:53 Uhr

  • Sie sehen, wie unglücklich es ist, wenn der Code auf einem System ausgeführt wird, auf dem sich der Heap anders verhält (aber natürlich innerhalb des Standards). „Es lief auf meinem Rechner“ ist nicht der Satz, den Kunden hören wollen.

    – scharfer Zahn

    12. August 2009 um 11:19 Uhr

Benutzer-Avatar
Matt Kellogg

Das alles geht auf C zurück, mit dem Sie sich selbst in den Fuß schießen können. Nur weil Sie dies tun können, heißt das nicht, dass Sie es tun sollten. Es ist definitiv nicht garantiert, dass der Wert bei p+3 dem entspricht, was Sie dort eingegeben haben, es sei denn, Sie haben ihn ausdrücklich mit malloc zugewiesen.

  • Ich würde behaupten, dass dies eigentlich Pech ist 🙂

    – bdonlan

    6. August 2009 um 19:53 Uhr

  • Sie sehen, wie unglücklich es ist, wenn der Code auf einem System ausgeführt wird, auf dem sich der Heap anders verhält (aber natürlich innerhalb des Standards). „Es lief auf meinem Rechner“ ist nicht der Satz, den Kunden hören wollen.

    – scharfer Zahn

    12. August 2009 um 11:19 Uhr

Benutzer-Avatar
Benutzer47559

Versuche dies:

int main ( int argc, char *argv[] ) {
  int *p = malloc(2 * sizeof *p);
  int *q = malloc(sizeof *q);
  *q = 100;

  p[0] = 10;    p[1] = 20;    p[2] = 30;    p[3] = 40;
  p[4] = 50;    p[5] = 60;    p[6] = 70;


  printf("%d\n", *q);

  return 0;
}

Auf meiner Maschine druckt es:

50

Dies liegt daran, dass Sie den für p zugewiesenen Speicher überschrieben und auf q getrampelt sind.

Beachten Sie, dass malloc aufgrund von Ausrichtungsbeschränkungen p und q möglicherweise nicht in zusammenhängenden Speicher stellt.

1345260cookie-checkWarum geben Sie die Größe an, wenn Sie malloc in C verwenden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy