Clanintern Clanintern Clanintern

Forum

Öffentliche Foren
FORUM: Spiele & Computer THEMA: dynamische arrays in ANSI-C?
AUTOR BEITRAG
Huri-Kane

RANG Deckschrubber

#1 - 27.03 09:52

/edit: das problem hat sich erledigt: braucht sich keiner mehr durch den text hier wühlen ;) lösung steht unten drunter...

Tach ihr,

komme momentan an einem "kleinen" c-problem nicht weiter. dazu eine kurze vorgeschichte: ich habe einen struct-typ namens "monitor_t" (dessen inhalt ist erstmal irrelevant, aber er enthält u.a. einen int namens "id"). von diesen structs muss ich eine bestimmte menge bereits allokiert vorhalten. ebenfalls müssen sie über eine ID ansprechbar sein (welche maximal 23 bit groß sein darf - also entfällt ein einfacher pointer schonmal). des weiteren soll möglichst effizient mit den structs hantiert werden, was es nahelegt lediglich die pointer darauf "umherzuschieben".

der offensichtlich funktionierende weg war für mich, anfangs lediglich ein array mit pointern auf die structs anzulegen ("monitor_t *liste[100]"), wodurch ich dann über deren IDs, die ich an einigen stellen im programm nur vorliegen habe, wieder zu den strukturen komme, indem ich sie einfach als index in das array nehme. problem ist nun folgendes: es kann vorkommen, dass die vorgehaltene menge der structs nicht ausreicht und neue angelegt werden müssen. das array müsste quasi dynamisch vergrößert werden. da ich nicht so der c-insider bin hab ich mich erstmal damit abgefunden, dass das wohl in der form so einfach nicht machbar ist (zumindest hat gcc keiner meiner syntax-versuche durchgehen lassen :D)

so kommt es zum nächsten ansatz: ich habe einen pointer "monitor_t *liste", den ich aber mit dem n-fachen der größe von "monitor_t" mittles "malloc" initialisiere (also "liste = (monitor_t*) malloc(n * sizeof(monitor_t))"). somit kann ich dann mittels addition auf den basiszeiger auf die weiteren elemente zugreifen ((monitor_t*) (liste + X)). das funktionierte auch soweit - jedoch komme ich da nun an der stelle nicht weiter, wo es heißt, bei bedarf weitere structs zu allozieren. soweit ich mich reingelesen hab, kann die funktion "realloc()" den belegten speicherbereich eines objekts verändern und wenn erforderlich (bspw. wenn andere daten "im weg" sind) einen komplett neuen bereich reservieren und die daten aus dem alten bereich in den neuen kopieren. klar soweit? :D nun und da klemmts bei mir - u.a. was die "stern-syntax" von c angeht (auch wenn ich meine es im prinzip verstanden zu haben). denn wenn ich mir die daten zum schluss angucke, steht da völliger müll drin. prinzipiell sollen die monitor_t structs an ort und stelle bleiben, egal was ich mit meiner lsite anstelle - schließlich weden beim eventuellen kopieren nur die zeiger darauf kopiert *confused*

vielleicht hilft folgender code zum verständnis. zur info: es wird parallel eine verkettete liste geführt (ex_monitorPoolNextFree), deren beginn immer auf die nächste noch unbenutze struktur zeigt.

code:

#include <stdlib.h>

typedef struct monitor {
  /* ... */
  int id;
} monitor_t;

typedef struct monitorPoolElement {
  monitor_t *monitor;
  struct monitorPoolElement *next;
} monitorPoolElement_t;

/** The complete list of allocated monitor structures. */
monitor_t *ex_monitorPoolList;

/** A pointer to the next free monitor structure */
monitorPoolElement_t *ex_monitorPoolNextFree;

/** Counter indicating the current number of monitor structures allocated */
int ex_monitorCurrentPoolSize;

/**
* @brief Retrieves a previously allocated monitor structure from the free
*        monitor list.
*
* @return A monitor structure from the free monitor list.
*
* This method retrieves a free monitor structure (actually the
* "ex_monitorNextFree" structure) and points "ex_monitorNextFree" to it's
* successor. In the case there's no monitor left it automatically doubles
* the pool size and reallocates the it.
*/
monitor_t *ex_monitorGet() {
    monitorPoolElement_t *elem = ex_monitorPoolNextFree;

    if (ex_monitorPoolNextFree == NULL) {
        /* there's no allocated monitor structure left */

        /* double the pool size by allocating a new pool twice the size of the old */
        ex_monitorPoolList = (monitor_t*) realloc(ex_monitorPoolList, ex_monitorCurrentPoolSize * 2 * sizeof(monitor_t));

        int i;
        /* initialize the remaining monitor structures */
        /* downward for parralel initialization of the linked list with its element's successors
        for (i = ex_monitorCurrentPoolSize*2 - 1; i >= ex_monitorCurrentPoolSize; i--) {
            /* ... */
            ex_monitorPoolList[i].id = i;

            /* expand the free monitor linked list */
            elem = (monitorPoolElement_t *) malloc(sizeof(monitorPoolElement_t));
            elem->next = ex_monitorPoolNextFree; /* ex_monitorPoolNextFree is NULL at the beginning */
            elem->monitor = (ex_monitorPoolList + i);

            ex_monitorPoolNextFree = elem;
        }

        ex_monitorCurrentPoolSize *= 2;
    }

    ex_monitorPoolNextFree = elem->next;
    elem->next = NULL;

    return elem->monitor;
}


nun wird beim start des programms eine bestimmte menge jener structs angelegt und auch alles fein säuberlich initialisiert. danach rufe ich ein paar mal die ex_monitorGet()-funktion auf und speichere die rückgabewerte (also die zeiger auf die structs). danach rufe ich die funktion noch ein paar mal auf, ohne mir die rückgabewerte zu speichern. gebe ich zum schluss meine anfangs gespeicherten structs aus, steht lediglich müll drin :-/
die main-methode sieht wie folgt aus:
code:

int main(int argc, char *argv[]) {
    ex_monitorCurrentPoolSize = MONITOR_POOL_SIZE;
    ex_monitorPoolList = (monitor_t*) malloc(ex_monitorCurrentPoolSize * sizeof(monitor_t));
/* init pool */
    int i;
    monitorPoolElement_t *elem;
    ex_monitorPoolNextFree = NULL;
    for (i = ex_monitorCurrentPoolSize-1; i >= 0; i--) {
        ex_monitorPoolList[i].id = i;

        elem = (monitorPoolElement_t *) malloc(sizeof(monitorPoolElement_t));
        elem->next = ex_monitorPoolNextFree;
        elem->monitor = (ex_monitorPoolList + i);
        ex_monitorPoolNextFree = elem;
    }

    monitor_t *monitors[10];

    for (i = 0; i < 10; i++) {
     monitors[i] = ex_monitorGet();
     printf("Monitor retrieved: %d, (0x%x)\n", monitors[i]->id, monitors[i]);
    }

    monitor_t *mon;
    for (i = 0; i < 10; i++) {
        mon = ex_monitorGet();
        printf("Another monitor retrieved: %d, (0x%x)\n", mon->id, mon);
    }
    for (i = 0; i < 10; i++) {
        printf("Saved monitor %d: %d (0x%x)\n", i, monitors[i]->id, monitors[i]);
    }
}


die ausgabe davon sieht dann in etwa so aus:
code:

Monitor retrieved: 0, (0x804a008)
Monitor retrieved: 1, (0x804a020)
Monitor retrieved: 2, (0x804a090)
Monitor retrieved: 3, (0x804a0a8)
Monitor retrieved: 4, (0x804a148)
Monitor retrieved: 5, (0x804a160)
Monitor retrieved: 6, (0x804a178)
Monitor retrieved: 7, (0x804a190)
Monitor retrieved: 8, (0x804a1a8)
Monitor retrieved: 9, (0x804a1c0)
Another monitor retrieved: 10, (0x804a1d8)
Another monitor retrieved: 11, (0x804a1f0)
Another monitor retrieved: 12, (0x804a208)
Another monitor retrieved: 13, (0x804a220)
Another monitor retrieved: 14, (0x804a238)
Another monitor retrieved: 15, (0x804a250)
Another monitor retrieved: 16, (0x804a450)
Another monitor retrieved: 17, (0x804a468)
Another monitor retrieved: 18, (0x804a480)
Another monitor retrieved: 19, (0x804a498)
Saved monitor 0: 134520840 (0x804a008)
Saved monitor 1: 1 (0x804a020)
Saved monitor 2: 0 (0x804a090)
Saved monitor 3: 3 (0x804a0a8)
Saved monitor 4: 134521160 (0x804a148)
Saved monitor 5: 17 (0x804a160)
Saved monitor 6: 0 (0x804a178)
Saved monitor 7: 17 (0x804a190)
Saved monitor 8: -1208209040 (0x804a1a8)
Saved monitor 9: 9 (0x804a1c0)


so... das war nun mehr als viel text, aber ich hoffe einer von euch kann mir da irgend nen kleinen tipp geben (an mehr wird es wahrscheinlich nicht hapern) - voraussetzung wäre nur, dass es hardcore ANSI-C is ;). vielleicht hab ich auch irgendwo nur nen stern falsch gesetzt o.ä....

viele dank für die mühe,
André

/edit mit lösung: papier und stift hilft doch manchmal. des rätsels lösung war, dass die "liste" als pointer of pointer deklariert werden musste (also monitor_t **ex_monitorPoolList), da die elemente der liste wiederum pointer auf die monitor_t-strukturen sind. die liste selbst wird ebenfalls durch einen pointer referenziert - und so kommt es zum pointer of pointer *erleuchtung*... naja, falls sich das hier trotzdem wer angetan hat viele dank fürs lesen ;)

-> kann zu