Meine Suche im Internet zeigt, dass ich den Speicher für x separat zuweisen sollte.
y->x = (double*)malloc(10*sizeof(double));
Aber es scheint, dass ich den Speicher für y-> x zweimal zuweise, einen, während ich Speicher für y und den anderen, während ich Speicher für y-> x zuweise, und es scheint eine Verschwendung von Speicher zu sein. Es wird sehr geschätzt, wenn Sie mich wissen lassen, was Compiler wirklich tun und wie der richtige Weg wäre, um sowohl y als auch y->x zu initialisieren.
Danke im Voraus.
Wie von Paxdiablo ausdrücklich betont, geben Sie bitte nicht den Rückgabewert von ein malloc() in C. Ich werde nie verstehen, warum jeder das Bedürfnis verspürt. 🙁
– abschalten
8. Februar 2013 um 8:37 Uhr
@unwind, vielleicht sind es alte C++-Programmierer, die auf C upgraden 🙂
– paxdiablo
8. Februar 2013 um 8:55 Uhr
@unwind Wenn ich den nvcc-Compiler von Nvidia für C-Code verwende und das Ergebnis von malloc nicht umwandle, wird ein Fehler ausgegeben.
– Nubkuchen
12. Juli 2017 um 19:44 Uhr
@ Nubcake Laut dieser Link Das könnte daran liegen, dass nvcc den zugrunde liegenden Compiler im C++-Modus ausführt, da ihre CUDA-Schnittstelle C++ ist. In C erhalten Sie dafür keine Fehler. In C++ void * konvertiert nicht automatisch in andere Zeiger, und die Umwandlung wird benötigt (oder verwenden Sie einfach nicht malloc() in C++ natürlich).
– abschalten
15. Juli 2017 um 12:10 Uhr
@unwind Ja, das habe ich später herausgefunden 🙂 Ich wollte nur eine Situation angeben, in der es einen Fehler geben würde, wenn Sie das Ergebnis nicht übertragen würden.
– Nubkuchen
15. Juli 2017 um 14:36 Uhr
paxdiablo
Nein, du bist nicht Speicher zuweisen für y->x zweimal.
Stattdessen weisen Sie Speicher für die Struktur zu (die einen Zeiger enthält). Plus etwas, auf das dieser Zeiger zeigen soll.
Die braucht man eigentlich zwei Zuweisungen (1 und 2), um alles zu speichern, was Sie brauchen.
Außerdem sollte Ihr Typ sein struct Vector *y da es sich um einen Zeiger handelt und Sie den Rückgabewert niemals umwandeln sollten malloc in C.
Es kann bestimmte Probleme verbergen, die Sie nicht verbergen möchten, und C ist perfekt in der Lage, die implizit zu konvertieren void* Rückgabewert an jeden anderen Zeiger.
Und natürlich möchten Sie wahrscheinlich die Erstellung dieser Vektoren kapseln, um ihre Verwaltung zu vereinfachen, z. B. indem Sie Folgendes in einer Header-Datei haben vector.h:
Dann in vector.chaben Sie die eigentlichen Funktionen zur Verwaltung der Vektoren:
#include "vector.h"
// Atomically allocate a two-layer object. Either both layers
// are allocated or neither is, simplifying memory checking.
struct Vector *newVector(size_t sz) {
// First, the vector layer.
struct Vector *vector = malloc(sizeof (struct Vector));
if (vector == NULL)
return NULL;
// Then data layer, freeing vector layer if fail.
vector->data = malloc(sz * sizeof (double));
if (vector->data == NULL) {
free(vector);
return NULL;
}
// Here, both layers worked. Set size and return.
vector->size = sz;
return vector;
}
void delVector(struct Vector *vector) {
// Can safely assume vector is NULL or fully built.
if (vector != NULL) {
free(vector->data);
free(vector);
}
}
Indem Sie die Vektorverwaltung so kapseln, stellen Sie sicher, dass Vektoren entweder vollständig oder gar nicht erstellt werden – ja nein Wahrscheinlichkeit, dass sie halb gebaut sind.
Es ermöglicht Ihnen auch, die zugrunde liegenden Datenstrukturen in Zukunft vollständig zu ändern, ohne Clients zu beeinträchtigen. Zum Beispiel:
wenn Sie sie zu spärlichen Arrays machen wollten, um Speicherplatz gegen Geschwindigkeit einzutauschen.
wenn Sie möchten, dass die Daten bei jeder Änderung im dauerhaften Speicher gespeichert werden.
wenn Sie sicherstellen möchten, dass alle Vektorelemente auf Null initialisiert wurden.
wenn Sie die Vektorgröße aus Effizienzgründen von der Vektorkapazität trennen wollten(1).
Sie können bei Bedarf auch weitere Funktionen hinzufügen, z. B. das sichere Festlegen oder Abrufen von Vektorwerten (siehe kommentierten Code in der Kopfzeile).
Beispielsweise könnten Sie (als eine Option) Einstellungswerte außerhalb des gültigen Bereichs stillschweigend ignorieren und Null zurückgeben, wenn Sie diese Werte erhalten. Oder Sie könnten einen Fehler irgendeiner Art melden oder versuchen, den Vektor unter der Decke automatisch zu erweitern(1).
In Bezug auf die Verwendung der Vektoren ist ein einfaches Beispiel wie folgt (sehr einfach) main.c
(1) Dieses Potenzial für einen erweiterbaren Vektor bedarf weiterer Erklärung.
Viele Vektorimplementierungen trennen die Kapazität von der Größe. Ersteres gibt an, wie viele Elemente Sie verwenden können, bevor eine Neuzuweisung erforderlich ist, letzteres ist die tatsächliche Vektorgröße (immer <= die Kapazität).
Beim Erweitern möchten Sie im Allgemeinen so erweitern, dass Sie es nicht viel tun, da dies eine teure Operation sein kann. Sie könnten beispielsweise 5 % mehr hinzufügen, als unbedingt erforderlich ist, damit in einer Schleife, die kontinuierlich ein Element hinzufügt, es nicht für jedes einzelne Element neu zuweisen muss.
Zittere vor meiner ASCII-Kunstfertigkeit 🙂
– paxdiablo
8. Februar 2013 um 8:32 Uhr
Vielen Dank. Wirklich hilfreich.
– Poya
8. Februar 2013 um 8:47 Uhr
In if(retval == NULL) sollte retval gleich retVal sein
– Legion Daeth
17. April 2018 um 19:36 Uhr
@paxdiablo Vielen Dank für die klare Erklärung und die wunderbare Idee, eine Funktion zu erstellen. Können Sie den Code bitte um a ergänzen main zeigen, wie man anruft newVector()?
– MA Bisk
31. August um 16:08 Uhr
@MABisk: fertig. Ich habe auch etwas mehr Erläuterungen zu einigen anderen Aspekten hinzugefügt.
– paxdiablo
31. August um 21:39 Uhr
Beim ersten Mal weisen Sie Speicher zu Vectorwas die Variablen bedeutet x,n.
Jedoch xdeutet noch nichts brauchbares an.
Deshalb also eine zweite Zuordnung ist ebenfalls erforderlich.
Wernsee
Im Prinzip machst du es schon richtig. Für das, was Sie wollen, brauchen Sie zwei malloc()s.
Nur einige Kommentare:
struct Vector y = (struct Vector*)malloc(sizeof(struct Vector));
y->x = (double*)malloc(10*sizeof(double));
In der ersten Zeile weisen Sie Speicher für ein Vector-Objekt zu. malloc() gibt einen Zeiger auf den zugewiesenen Speicher zurück, also muss y ein Vektorzeiger sein. In der zweiten Zeile weisen Sie Speicher für ein Array von 10 Doubles zu.
In C brauchen Sie die expliziten Umwandlungen und das Schreiben nicht sizeof *y Anstatt von sizeof(struct Vector) ist besser für die Typsicherheit und spart außerdem Tipparbeit.
Sie können Ihre Struktur neu anordnen und eine einzelne ausführen malloc() so:
“tippen sparen” ist nie ein stichhaltiges Argument für Programmierentscheidungen. Der eigentliche Grund, warum Sie *y nehmen würden, sind Sicherheitsgründe, um sicherzustellen, dass Sie der entsprechenden Variablen so viel Platz wie nötig zuweisen.
– Ludin
8. Februar 2013 um 9:19 Uhr
@Lundin Ich habe meine Antwort aktualisiert, aber für mich ist das Argument “Typsicherheit”. fast in der gleichen Liga wie das Schreiben if(NULL == foo)
– Wernsee
8. Februar 2013 um 9:38 Uhr
@Lundin Schreiben sizeof *y hilft Ihnen, Fehler wie das Schreiben zu bekämpfen sizeof(Vector) wenn du meinst sizeof(Matrix). Wie oft machst du solche Fehler? Wie schnell finden und beheben Sie sie, wenn Sie dies tun? Ich stimme zu, dass es die Typsicherheit erhöht, und ich schreibe sizeof *y in meinem eigenen Code, aber es ist fast so paranoid wie das Schreiben if(NULL == foo) um Tippfehler zu vermeiden ==.
– Wernsee
8. Februar 2013 um 12:57 Uhr
@Wernsey, warum ist struct Vector *y = malloc(sizeof *y); das Gleiche wie struct Vector *y = malloc(sizeof(struct Vector)); Tut *y Dereferenzierung auf den Typ Vector irgendwie?
– Schmuel Kamensky
12. Oktober 2020 um 8:55 Uhr
@ShmuelKamensky Sie sind funktional gleichwertig. y ist ein Hinweis auf struct Vector Also sizeof *y sagt “Größe dessen, worauf y zeigt”, also sizeof struct Vector.
– Wernsee
13. Oktober 2020 um 9:23 Uhr
rajneesh
Wenige Punkte
struct Vector y = (struct Vector*)malloc(sizeof(struct Vector)); ist falsch
es sollte sein struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector)); seit y hält Zeiger auf struct Vector.
1 malloc() weist nur genügend Speicher zu, um die Vektorstruktur zu halten (die ein Zeiger auf double + int ist)
2 malloc() Weisen Sie tatsächlich Speicher zu, um 10 doppelt zu halten.
Wenn Sie Speicher zuweisen für struct Vector Sie weisen nur Speicher für den Zeiger zu x, dh für Leerzeichen, wo sein Wert, der Adresse enthält, platziert wird. Auf diese Weise weisen Sie dem Block also keinen Speicher zu, auf dem y.x wird verweisen.
oleg_g
Zuerst weist malloc Speicher für struct zu, einschließlich Speicher für x (Zeiger auf double). Der zweite malloc weist Speicher für den doppelten Wert zu, auf den x zeigt.
PQuinn
Sie könnten dies tatsächlich in einem einzigen Malloc tun, indem Sie den Vektor und das Array gleichzeitig zuweisen. Z.B:
Dies weist den Vektor ‘y’ zu und lässt dann y->x auf die extra zugewiesenen Daten unmittelbar nach der Vektorstruktur zeigen (jedoch im selben Speicherblock).
Wenn eine Größenänderung des Vektors erforderlich ist, sollten Sie dies wie empfohlen mit den beiden Zuordnungen tun. Das interne y->x-Array könnte dann in der Größe geändert werden, während die Vektorstruktur ‘y’ intakt bleibt.
Warum haben Sie speziell cast y in char eingegeben? Warum nicht (double*)y + sizeof(struct Vector)?
– Vishnu Prasath
24. Februar 2014 um 13:15 Uhr
sizeof gibt die Strukturgröße in Bytes zurück, und der arithmetische ‘+’-Operator des Zeigers fügt dem ‘y’-Zeiger ein Vielfaches von sizeof(y). Wenn wir wie oben vorgehen würden, würde y um sizeof(double)*sizeof(struct) erhöht werden, was zu viel ist. Casting von y zu char Lassen Sie uns y um sizeof(char)*sizeof(struct) = 1*sizeof(struct) erhöhen
– PQuinn
25. Februar 2014 um 8:16 Uhr
Tu das nicht. Das gewährleistet es nicht y->x richtig ausgerichtet ist, um a zu halten double. Wenn dies nicht der Fall ist, haben Sie ein undefiniertes Verhalten.
– real oder zufällig
9. November 2021 um 15:27 Uhr
14213300cookie-checkmalloc für Struktur und Zeiger in Cyes
Wie von Paxdiablo ausdrücklich betont, geben Sie bitte nicht den Rückgabewert von ein
malloc()
in C. Ich werde nie verstehen, warum jeder das Bedürfnis verspürt. 🙁– abschalten
8. Februar 2013 um 8:37 Uhr
@unwind, vielleicht sind es alte C++-Programmierer, die auf C upgraden 🙂
– paxdiablo
8. Februar 2013 um 8:55 Uhr
@unwind Wenn ich den nvcc-Compiler von Nvidia für C-Code verwende und das Ergebnis von malloc nicht umwandle, wird ein Fehler ausgegeben.
– Nubkuchen
12. Juli 2017 um 19:44 Uhr
@ Nubcake Laut dieser Link Das könnte daran liegen, dass nvcc den zugrunde liegenden Compiler im C++-Modus ausführt, da ihre CUDA-Schnittstelle C++ ist. In C erhalten Sie dafür keine Fehler. In C++
void *
konvertiert nicht automatisch in andere Zeiger, und die Umwandlung wird benötigt (oder verwenden Sie einfach nichtmalloc()
in C++ natürlich).– abschalten
15. Juli 2017 um 12:10 Uhr
@unwind Ja, das habe ich später herausgefunden 🙂 Ich wollte nur eine Situation angeben, in der es einen Fehler geben würde, wenn Sie das Ergebnis nicht übertragen würden.
– Nubkuchen
15. Juli 2017 um 14:36 Uhr