MALLOC voor struct en aanwijzer in C

Stel dat ik een structuur wil definiëren die de lengte van de vector en de waarden vertegenwoordigt als:

struct Vector{
    double* x;
    int n;
};

Stel nu, ik denk dat ik een vector y wil definiëren en er geheugen voor toewijst.

struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector));

Mijn zoektocht via internet laat zien dat ik het geheugen voor x afzonderlijk moet toewijzen.

y->x = (double*)malloc(10*sizeof(double));

Maar, maar, het lijkt erop dat ik het geheugen voor Y- & GT; X twee keer toewijst, één tijdens het toewijzen van het geheugen voor Y en het andere tijdens het toewijzen van geheugen voor Y- & GT; X, en het lijkt een geheugenverspilling.
Het wordt zeer op prijs gesteld als ik weet welke compiler echt doet en wat zou de juiste weg zijn
initialiseer zowel y als y- & gt; x.

Dank bij voorbaat.


Antwoord 1, Autoriteit 100%

Nee, u bent niet toewijzen van geheugen voor y->xtweemaal.

In plaats daarvan wijst u het geheugen toe voor de structuur (inclusief een aanwijzer) plus iets voor die aanwijzer om naar te wijzen.

Denk er op deze manier aan:

        1          2
        +-----+    +------+
y------>|  x------>|  *x  |
        |  n  |    +------+
        +-----+

Dus je hebt eigenlijk de twee toewijzingen nodig (1en 2) om alles op te slaan.

Bovendien moet uw type struct Vector *yzijn, aangezien het een aanwijzer is en u nooit de retourwaarde van mallocIN C moet uitgeven, omdat het bepaalde problemen kan verbergen U wilt niet dat verborgen – C is perfect in staat om de void*retourwaarde naar een andere aanwijzer impliciet te converteren.

En, natuurlijk wil je waarschijnlijk het maken van de oproep van deze vectoren om het beheer van hen gemakkelijker te maken, zoals met:

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);
    }
}

Door het inkapseren van dergelijke schepping, zorg ervoor dat vectoren volledig zijn gebouwd of helemaal niet gebouwd – er is geen kans dat ze halfgebouwd zijn. Het stelt u ook in staat om de onderliggende datastructuren in de toekomst volledig te wijzigen zonder de klanten te beïnvloeden (bijvoorbeeld, als u ze dun arrays wilt maken om ruimte voor snelheid af te wisselen).


Antwoord 2, Autoriteit 3%

De eerste keer in de buurt, toewijst u geheugen voor Vector, wat de variabelen betekent x, n.

Maar xverwijst nog niet naar iets nuttigs.

Dus daarom is tweede toewijzing ook nodig.


Antwoord 3, autoriteit 2%

In principe doe je het al goed. Voor wat je wilt heb je wel twee malloc()en nodig.

Een paar opmerkingen:

struct Vector y = (struct Vector*)malloc(sizeof(struct Vector));
y->x = (double*)malloc(10*sizeof(double));

zou moeten zijn

struct Vector *y = malloc(sizeof *y); /* Note the pointer */
y->x = calloc(10, sizeof *y->x);

In de eerste regel wijst u geheugen toe aan een Vector-object. malloc()retourneert een aanwijzer naar het toegewezen geheugen, dus y moet een vectoraanwijzer zijn. In de tweede regel wijst u geheugen toe voor een array van 10 doubles.

In C heb je de expliciete casts niet nodig, en het schrijven van sizeof *yin plaats van sizeof(struct Vector)is beter voor de typeveiligheid, en bovendien is het bespaart typen.

Je kunt je structuur herschikken en een enkele malloc()doen, zoals:

struct Vector{    
    int n;
    double x[];
};
struct Vector *y = malloc(sizeof *y + 10 * sizeof(double));

Antwoord 4, autoriteit 2%

Enkele punten

struct Vector y = (struct Vector*)malloc(sizeof(struct Vector));is fout

het moet struct Vector *y = (struct Vector*)malloc(sizeof(struct Vector));zijn aangezien yde aanwijzer naar struct Vector.

1e malloc()wijst alleen voldoende geheugen toe om de vectorstructuur vast te houden (wat een pointer is naar double + int)

2e malloc()wijst feitelijk geheugen toe aan 10 dubbele.


Antwoord 5

Je zou dit in een enkele malloc kunnen doen door de vector en de array tegelijkertijd toe te wijzen. Bijv.:

struct Vector y = (struct Vector*)malloc(sizeof(struct Vector) + 10*sizeof(double));
y->x = (double*)((char*)y + sizeof(struct Vector));
y->n = 10;

Hiermee wordt Vector ‘y’ toegewezen, waarna y->x wijst naar de extra toegewezen gegevens direct na de Vector-struct (maar in hetzelfde geheugenblok).

Als het formaat van de vector moet worden gewijzigd, moet u dit doen met de twee toewijzingen zoals aanbevolen. De interne y->x-array zou dan kunnen worden vergroot of verkleind terwijl de vectorstructuur ‘y’ intact blijft.


Antwoord 6

Als u geheugen toewijst voor struct Vector, wijst u alleen geheugen toe voor pointer x, d.w.z. voor spatie, waar de waarde, die het adres bevat, zal worden geplaatst. Op die manier wijst u dus geen geheugen toe aan het blok, waarnaar y.xzal verwijzen.


Antwoord 7

Eerste malloc wijst geheugen toe voor struct, inclusief geheugen voor x (pointer naar dubbel). Tweede malloc wijst geheugen toe voor dubbele waarde waar x naar wijst.


Antwoord 8

Wanneer u malloc(sizeof(struct_name))het automatisch geheugen toewijst voor de volledige grootte van de struct, hoeft u niet elk element erin te mallocen.

Gebruik de vlag -fsanitize=addressom te controleren hoe u uw programmageheugen hebt gebruikt.

Other episodes