Jeder weiss das:
realloc
ändert die Größe eines vorhandenen Speicherblocks oder kopiert ihn in einen größeren Block.
calloc
stellt sicher, dass der Speicher auf Null gesetzt wird und schützt vor arithmetischen Überläufen und ist im Allgemeinen auf große Arrays ausgerichtet.
Warum bietet der C-Standard keine Funktion wie die folgende, die beides kombiniert?
void *recalloc(void *ptr, size_t num, size_t size);
Wäre es nicht nützlich, um die Größe riesiger Hash-Tabellen oder benutzerdefinierter Speicherpools zu ändern?
Generell ist in C der Punkt der Standardbibliothek nicht um eine Vielzahl cooler Funktionen bereitzustellen. Es ist eine bereitzustellen essentiell Satz von Bausteinen, aus denen Sie Ihre eigenen coolen Funktionen bauen können.
Ihr Vorschlag für recalloc
wäre trivial zu schreiben und sollte daher nicht von der Standardbibliothek bereitgestellt werden.
Andere Sprachen verfolgen einen anderen Ansatz: C# und Java haben superreiche Bibliotheken, die selbst komplizierte Aufgaben trivial machen. Aber sie sind mit einem enormen Overhead verbunden. C hat einen minimalen Overhead, und das hilft dabei, es auf alle Arten von eingebetteten Geräten portierbar zu machen.
Ich nehme an, Sie sind daran interessiert, nur den neuen Teil des Arrays auf Null zu setzen:
Nicht jeder Speicherzuordner weiß, wie viel Speicher Sie in einem Array verwenden. zum Beispiel, wenn ich mache:
char* foo = malloc(1);
foo
weist jetzt darauf hin mindestens ein Stück Speicher 1 Byte groß. Die meisten Allokatoren weisen jedoch viel mehr als 1 Byte zu (z. B. 8, um die Ausrichtung beizubehalten).
Dies kann auch bei anderen Zuweisungen passieren. Der Speicherzuordner wird zuordnen mindestens so viel Speicher, wie Sie wünschen, wenn auch oft nur ein bisschen mehr.
Und es ist dieser “nur ein bisschen mehr” Teil, der die Dinge vermasselt (zusätzlich zu anderen Faktoren, die dies schwierig machen). Weil wir nicht wissen, ob es nützliches Gedächtnis ist oder nicht. Wenn es nur Polsterung ist, und du recalloc
es, und der Allocator setzt es nicht auf Null, dann haben Sie jetzt “neuen” Speicher, der einige Nicht-Null-Werte enthält.
Was wäre zum Beispiel wenn ich recalloc
foo
damit es auf einen neuen Puffer zeigt, der mindestens 2 Bytes groß ist. Wird dieses zusätzliche Byte auf Null gesetzt? Oder nicht? Das sollte es sein, aber beachten Sie, dass die ursprüngliche Zuweisung uns 8 Bytes gegeben hat, sodass durch die Neuzuweisung kein neuer Speicher zugewiesen wird. Soweit der Zuordner sehen kann, muss er keinen Speicher auf Null setzen (weil es keinen “neuen” Speicher auf Null gibt). Was zu einem schwerwiegenden Fehler in unserem Code führen könnte.
Wenn Sie einfach alles auf Null setzen, macht es keinen Sinn, die Größe zu ändern – geben Sie einfach den alten Block frei und rufen Sie dann einen neuen Block auf.
– PaulR
12. Februar 2015 um 20:52 Uhr
@PaulR: Vermutlich würde es nur den neuen Speicher auf Null setzen (oder besser gesagt sicherstellen, dass es so ist auf Null gesetzt).
– Matt
12. Februar 2015 um 20:53 Uhr
Der Zweck der Standardbibliothek besteht nicht darin, einen reichhaltigen Satz cooler Funktionen bereitzustellen. Es soll einen wesentlichen Satz von Bausteinen bereitstellen, aus denen Sie Ihre eigenen coolen Funktionen bauen können. Ihr Vorschlag für Recalloc wäre trivial zu schreiben und sollte daher nicht von der Standardbibliothek bereitgestellt werden.
– abelenky
12. Februar 2015 um 20:57 Uhr
Scheint mir alles in allem ein fairer Vorschlag zu sein
– MM
12. Februar 2015 um 21:09 Uhr
calloc()
hat eine andere Funktion, diemalloc()
funktioniert nicht: in obskuren Systemen wie DOS: die Möglichkeit, ein Array größer als zuzuweisenSIZE_MAX
. So könnte Codecalloc(60000u, sizeof (double))
sogar wennsize_t
war 16-Bit. Ich habe mich über die C-Konformität gewundert – aber es scheint richtig zu sein.– chux – Wiedereinsetzung von Monica
12. Februar 2015 um 21:42 Uhr