Woher wissen Sie, wie viel Platz mit malloc () zuzuordnen ist?

8

Ich bin ein C-Neuling, ich komme aus C #. Ich habe etwas über Speicherverwaltung und die Funktion malloc() gelernt. Ich bin auch auf diesen Code gestoßen:

%Vor%

Was ich nicht verstehe ist, wie viel Speicherplatz für a_persons_name reserviert wird. Gibt es 2 Zeichen (zB AB) oder etwas anderes?

Ich weiß auch, dass Sie manchmal mit malloc "glücklich" werden und nicht zugeordneten Speicherplatz verwenden können (was zu Datenkorruption und Seg-Fehlern führen kann). Woher weiß ich also, wie viel Platz ich zur Verfügung stelle und wie viel ich brauche?

    
Kredns 08.08.2009, 04:22
quelle

6 Antworten

14

Dieses Snippet belegt genug Platz für einen 2-stelligen Namen.

Im Allgemeinen wird der Zeichenfolgenpuffer von irgendwo, d. h. I / O, gefüllt. Wenn die Größe der Zeichenfolge nicht vorher bekannt ist (z. B. Lesen von Datei oder Tastatur), wird im Allgemeinen einer von drei Ansätzen verwendet:

  • Definieren Sie eine maximale Größe für eine beliebige Zeichenfolge, weisen Sie diese Größe + 1 zu (für den Nullabschluss), lesen Sie höchstens so viele Zeichen und den Fehler, oder schneiden Sie blind ab, wenn zu viele Zeichen angegeben wurden. Nicht besonders benutzerfreundlich.

  • Weisen Sie sie schrittweise zu (vorzugsweise unter Verwendung geometrischer Reihen, z. B. Verdoppeln, um ein quadratisches Verhalten zu vermeiden) und lesen Sie weiter, bis das Ende erreicht ist. Nicht so einfach zu programmieren.

  • Ordne eine feste Größe zu und hoffe, dass sie nicht überschritten wird, und crash (oder im Besitz) schrecklich sein, wenn diese Annahme fehlschlägt. Einfach zu programmieren, leicht zu knacken. Siehe beispielsweise gets in der Standard-C-Bibliothek. ( Verwenden Sie diese Funktion niemals. )

Barry Kelly 08.08.2009, 04:28
quelle
5

Nun, für den Anfang ist sizeof(char) immer 1, also könntest du nur malloc(3) .

Was Sie dort zuweisen, ist genug Platz für drei Zeichen. Aber denken Sie daran, Sie brauchen einen für einen Nullterminator für C-Strings.

Was Sie normalerweise finden, sind Dinge wie:

%Vor%

, um genügend Speicherplatz für einen Namen und ein Abschlusszeichen zu erhalten (wobei zu beachten ist, dass die Zeichenfolge "xyzzy" im Speicher wie folgt gespeichert wird:

) %Vor%

Manchmal sehen Sie bei nicht char-basierten Arrays:

%Vor%

, die genug Platz für 22 ganze Zahlen zuweisen wird.

    
paxdiablo 08.08.2009 04:28
quelle
3

malloc() weist einen Speicherblock zu und gibt bei Erfolg einen Zeiger auf diesen Speicher zurück, und NULL, falls nicht erfolgreich. Die Größe des Speicherblocks wird durch das Argument malloc in Bytes angegeben.

Der Operator sizeof gibt die Größe seines Arguments in Bytes an.

%Vor%

dies wird genug Platz für eine 49-stellige Zeichenfolge reservieren (eine C-style-Zeichenfolge muss mit einem NULL ( 'someString' ) -Zeichen ohne NULL-Zeichen und Punkt malloc(sizeof(char) * 2); in diesem Speicher abgeschlossen werden.

Es sieht so aus, als sollte der Code in Ihrer Frage sizeof(char) + 2 sein, da sizeof(char) keinen Sinn ergibt.

Beachten Sie, dass %code% garantiert immer 1 (Byte) ist - aber die Speicherrepräsentation anderer Typen (z. B. long) kann zwischen Compilern variieren.

Die Art und Weise, wie Sie mit dynamisch zugewiesenem Speicher (un) glücklich werden, ist, wenn Sie versuchen, außerhalb des von Ihnen zugewiesenen Speichers zu lesen / schreiben.

Zum Beispiel

%Vor%

Die erste Zeile bietet genug Platz für 9 Zeichen und ein NULL-Zeichen.
Die zweite Zeile versucht, 20 Zeichen (19 + NULL) in diesen Speicherplatz zu kopieren. Dies überschreibt den Puffer und kann etwas unglaublich witziges verursachen, wie zum Beispiel das Überschreiben von benachbartem Speicher oder das Auftreten eines Segmentfehlers.

Die dritte Zeile könnte funktionieren, zum Beispiel, wenn Speicher direkt neben someString zugewiesen wurde, und "Hello there, world!" Wenn Sie in diesen Speicherbereich hineingelaufen sind, könnte er Ihre Zeichenfolge plus den Inhalt des nächsten Speicherplatzes ausgeben. Wenn dieser zweite Raum NULL-terminiert wäre, würde er aufhören - außer es war nicht, in welchem ​​Fall er wandern würde und schließlich segfault.

Dieses Beispiel ist eine ziemlich einfache Operation, aber es ist so einfach, einen Fehler zu machen. C ist knifflig - sei vorsichtig.

    
Carson Myers 08.08.2009 04:48
quelle
1

Ihr Aufruf an malloc weist 3 Bytes Speicher zu. sizeof(char) ist 1 Byte und 2 Bytes sind explizit angegeben. Dies gibt Ihnen genug Platz für eine Zeichenfolge der Größe 2 (zusammen mit dem Abschlusszeichen)

    
Brandon E Taylor 08.08.2009 04:28
quelle
1

Dies wird drei Bytes zuweisen; 1 für sizeof (char), plus zwei. Wenn ich diese Zeile außerhalb des Kontexts sehe, kann ich nicht wissen, warum sie auf diese Weise zugewiesen wird oder ob sie korrekt ist (sie sieht für mich fischartig aus).

Sie müssen genügend Speicher reservieren, um alles zu speichern, was Sie brauchen, um es einzufügen. Wenn Sie beispielsweise Speicher reservieren, um eine Zeichenfolge zu speichern, müssen Sie genügend Speicher reservieren, um die längste erwartete Zeichenfolge plus ein Byte für die abschließende Null zu speichern. Wenn Sie mit ASCII-Strings arbeiten, ist das einfach: ein Byte pro Zeichen plus eins. Wenn Sie Unicode-Strings verwenden, werden die Dinge komplizierter.

    
Fred Larson 08.08.2009 04:31
quelle
1

Erster Punkt - es ist eine gute Angewohnheit, niemals absolute Zahlen in das Argument von malloc zu setzen, benutzen Sie immer sizeof und multiple. Wie oben gesagt, variiert der Speicher, der für einige Typen reserviert ist, mit dem Compiler und der Plattform. Um sicherzustellen, dass genügend Platz für ein Array vom Typ "Blob" zur Verfügung steht, ist es am besten, etwas wie folgt zu verwenden:

%Vor%

Auf diese Weise erhalten Sie genau die richtige Menge, egal wie der Typ ist, aber wie er aussieht.

Zweitens, segfaults usw. C, als eine Low-Level-Sprache, hat keine Grenzen zu überprüfen. Das bedeutet, dass Sie nicht überprüfen können, ob Sie einen Index betrachten, der nicht wirklich im Array enthalten ist. Tatsächlich hindert es Sie nicht daran, überall auf Speicher zuzugreifen, auch wenn es nicht zu Ihrem Programm gehört (obwohl Ihr Betriebssystem dies möglicherweise ist, was ein Segfault ist). Wenn Sie also ein Array in C übergeben, müssen Sie auch dessen Länge übergeben, damit die Funktion, die das Array empfängt, weiß, wie groß es ist. Vergiss nicht, dass ein "Array" wirklich nur ein Zeiger auf das erste Element ist. Dies ist sehr hilfreich, wenn Strings übergeben werden - jedes String-Argument würde zu zwei Argumenten werden, also wird ein Cheat verwendet. Jede Standard-C-Zeichenfolge ist NULL-terminiert. Das letzte Zeichen in der Zeichenfolge sollte der ASCII-Wert 0 sein. Alle Zeichenfolgenfunktionen arbeiten so lange im Array, bis sie das sehen und dann anhalten. Auf diese Weise überholen sie das Array nicht, aber wenn es aus irgendeinem Grund nicht da ist, werden sie es tun. Das wird verstanden

%Vor%

ist 5, aber um es zu speichern, benötigen Sie ein weiteres Zeichen. Zum Beispiel:

%Vor%

Und ja, sizeof (char) ist unnötig, weil es als 1 definiert ist, aber ich finde es klarer und es ist auf jeden Fall eine gute Gewohnheit.

    
WillW 08.08.2009 12:41
quelle