Angenommen, ich möchte eine Struktur definieren, die die Länge des Vektors und seine Werte wie folgt darstellt:
struct Vector{
double* x;
int n;
};
Angenommen, ich möchte einen Vektor y definieren und Speicher dafür zuweisen.
struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector));
Meine Suche über das 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 zuordne, einen beim Zuweisen des Speichers für y und den anderen beim Zuweisen des Speichers für y-> x, und es scheint eine Verschwendung von Speicher zu sein. Es wird sehr geschätzt, wenn Sie mich wissen lassen, was der Compiler wirklich tut und wie Sie sowohl y als auch y-> x richtig initialisieren können.
Danke im Voraus.
c
memory-management
Pouya
quelle
quelle
malloc()
in C ein. Ich werde nie verstehen, warum jeder das für nötig hält. :(void *
wird nicht automatisch in andere Zeiger konvertiert, und die Umwandlung wird benötigt (odermalloc()
natürlich nicht in C ++ verwendet).Antworten:
Nein, Sie weisen nicht
y->x
zweimal Speicher zu .Stattdessen weisen Sie Speicher für die Struktur zu (die einen Zeiger enthält) sowie etwas, auf das dieser Zeiger zeigen soll.
Denk darüber so:
1 2 +-----+ +------+ y------>| x------>| *x | | n | +------+ +-----+
Sie benötigen also tatsächlich die beiden Zuordnungen (
1
und2
), um alles zu speichern.Außerdem sollte Ihr Typ sein,
struct Vector *y
da es sich um einen Zeiger handelt, und Sie sollten den Rückgabewert niemalsmalloc
in C umwandeln, da er bestimmte Probleme verbergen kann, die nicht ausgeblendet werden sollen. C ist perfekt in der Lage, denvoid*
Rückgabewert implizit in einen anderen Zeiger zu konvertieren .Und natürlich möchten Sie wahrscheinlich die Erstellung dieser Vektoren kapseln, um die Verwaltung zu vereinfachen, z. B.:
struct Vector { double *data; // no place for x and n in readable code :-) size_t size; }; struct Vector *newVector (size_t sz) { // Try to allocate vector structure. struct Vector *retVal = malloc (sizeof (struct Vector)); if (retVal == NULL) return NULL; // Try to allocate vector data, free structure if fail. retVal->data = malloc (sz * sizeof (double)); if (retVal->data == NULL) { free (retVal); return NULL; } // Set size and return. retVal->size = sz; return retVal; } 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 Erstellung so kapseln, stellen Sie sicher, dass Vektoren entweder vollständig oder gar nicht erstellt werden - es besteht keine Chance, dass sie zur Hälfte erstellt werden. Außerdem können Sie die zugrunde liegenden Datenstrukturen in Zukunft vollständig ändern, ohne die Clients zu beeinträchtigen (z. B. wenn Sie sie zu spärlichen Arrays machen möchten, um Speicherplatz gegen Geschwindigkeit auszutauschen).
quelle
Das erste Mal, weisen Sie Speicher für
Vector
, die die Variablen bedeutetx
,n
.Zeigt
x
jedoch noch nichts Nützliches an .Deshalb ist auch eine zweite Zuweisung erforderlich .
quelle
Einige Punkte
struct Vector y = (struct Vector*)malloc(sizeof(struct Vector));
ist falsches sollte
struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector));
day
Zeiger auf haltenstruct Vector
.1.
malloc()
reserviert nur genügend Speicher, um die Vektorstruktur aufzunehmen (was ein Zeiger auf double + int ist)2.
malloc()
tatsächlich Speicher zuweisen, um 10 doppelt zu halten.quelle
Sie können dies tatsächlich in einem einzigen Malloc tun, indem Sie gleichzeitig den Vektor und das Array zuweisen. Z.B:
struct Vector y = (struct Vector*)malloc(sizeof(struct Vector) + 10*sizeof(double)); y->x = (double*)((char*)y + sizeof(struct Vector)); y->n = 10;
Dadurch wird der Vektor 'y' zugewiesen, und y-> x zeigt unmittelbar nach der Vektorstruktur (jedoch im selben Speicherblock) auf die zusätzlich zugewiesenen Daten.
Wenn die Größe des Vektors geändert werden muss, sollten Sie die beiden empfohlenen Zuordnungen verwenden. Die Größe des internen y-> x-Arrays könnte dann geändert werden, während die Vektorstruktur 'y' intakt bleibt.
quelle
Im Prinzip machst du es schon richtig. Für das, was Sie wollen, brauchen Sie zwei
malloc()
s.Nur ein paar Kommentare:
struct Vector y = (struct Vector*)malloc(sizeof(struct Vector)); y->x = (double*)malloc(10*sizeof(double));
sollte sein
struct Vector *y = malloc(sizeof *y); /* Note the pointer */ y->x = calloc(10, sizeof *y->x);
In der ersten Zeile weisen Sie einem Vektorobjekt Speicher zu.
malloc()
Gibt einen Zeiger auf den zugewiesenen Speicher zurück, daher muss y ein Vektorzeiger sein. In der zweiten Zeile weisen Sie Speicher für ein Array von 10 Doubles zu.In C benötigen Sie keine expliziten Casts, und das Schreiben
sizeof *y
anstelle vonsizeof(struct Vector)
ist besser für die Typensicherheit und spart außerdem Tipparbeit.Sie können Ihre Struktur neu anordnen und eine Single
malloc()
wie folgt ausführen :struct Vector{ int n; double x[]; }; struct Vector *y = malloc(sizeof *y + 10 * sizeof(double));
quelle
if(NULL == foo)
sizeof *y
. Wenn Sie dies nur tun, um 5 Buchstaben weniger (sizeof * y versus sizeof (Vector)) ohne ein anderes Argument einzugeben, muss dies daran liegen, dass Sie die Aufgabe, 5 Buchstaben auf Ihrer Tastatur einzugeben, als großes Hindernis empfinden. Und wenn ja, dann ziehen Sie vielleicht eine andere Berufswahl in Betracht, da das Programmieren eine Menge Tastatureingaben erfordert ...sizeof *y
hilft Ihnen dabei, Fehler wie das Schreiben zu bekämpfen,sizeof(Vector)
wenn Sie es gemeint habensizeof(Matrix)
. Wie oft machst du solche Fehler? Wie schnell finden und beheben Sie sie, wenn Sie dies tun? Ich bin damit einverstanden, dass es die Typensicherheit erhöht, und ich schreibesizeof *y
in meinen eigenen Code, aber es ist fast so paranoid wie das Schreibenif(NULL == foo)
, um Tippfehler auf dem zu verhindern==
.y
ist ein Zeiger aufstruct Vector
sosizeof *y
heißt "Größe dessen, worauf y zeigt", alsosizeof struct Vector
.Wenn Sie Speicher für
struct Vector
Sie zuweisen, weisen Sie nur Speicher für Zeiger zux
, dh für Leerzeichen, wo sein Wert, der die Adresse enthält, platziert wird. Auf diese Weise weisen Sie dem Block, auf deny.x
verwiesen wird, keinen Speicher zu .quelle
Das erste malloc weist Speicher für struct zu, einschließlich Speicher für x (Zeiger auf double). Das zweite Malloc weist Speicher für einen doppelten Wert zu, auf den x zeigt.
quelle