Elemente aus einem Array in C entfernen

Lesezeit: 7 Minuten

Benutzer-Avatar
Rini Posny

Ich habe nur eine einfache Frage zu Arrays in C:

Was ist der beste Weg, um Elemente aus einem Array zu entfernen und dabei das Array kleiner zu machen?

dh: das Array ist n Größe, dann entferne ich Elemente aus dem Array und dann wird das Array um den Betrag kleiner, aus dem ich es entfernt habe.

Im Grunde behandle ich das Array wie ein Kartenspiel, und sobald ich eine Karte von der Oberseite des Decks nehme, sollte sie nicht mehr da sein.

EDIT: Ich werde mich vor Ende des Tages verrückt machen, danke für all die Hilfe, ich versuche das Value-Swap-Ding, aber es funktioniert nicht richtig.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

enum faces { Ace = 0, Jack = 10, Queen, King };
char *facecheck(int d); 
int draw(int deck, int i); 

int main() { 
    int deck[52], i, n;
    char suits[4][9] = {
        "Hearts",
        "Diamonds",
        "Clubs",
        "Spades"
    };

    n = 0;

    for (i = 0; i < 52; i++) {
        deck[i] = n;
        n++;
    };

    for (i = 0; i < 52; i++) {       
        if (i % 13 == 0 || i % 13 == 10 || i % 13 == 11 || i % 13 == 12)
            printf("%s ", facecheck(i % 13));
        else
            printf("%d ", i % 13 + 1);
        printf("of %s \n", suits[i / 13]);
    }

    draw(deck, i);

    return 0; 
}  

char *facecheck(int d) {
    static char *face[] = {
        "Ace",
        "Jack",
        "Queen",
        "King"
    };

    if (d == Ace)
        return face[0];
    else {
        if (d == Jack) 
            return face[1];
        else {
            if (d == Queen)
                return face[2];
            else { 
                if (d == King)
                    return face[3];
            }
        }
    } 
}

int draw(int deck, int i) { 
    int hand[5], j, temp[j];

    for (i = 0; i < 52; i++) {
        j = i
    }; 

    for (i = 0; i < 5; i++) {
        deck[i] = hand[]; 
        printf("A card has been drawn \n");
        deck[i] = temp[j - 1];
        temp[j] = deck[i];
    };
      
    return deck;
}

Es gibt wirklich zwei verschiedene Probleme. Die erste besteht darin, die Elemente des Arrays in der richtigen Reihenfolge zu halten, damit es nach dem Entfernen eines Elements keine “Löcher” gibt. Die zweite ist tatsächlich die Größenänderung des Arrays selbst.

Arrays in C werden als eine feste Anzahl zusammenhängender Elemente zugewiesen. Es gibt keine Möglichkeit, den von einem einzelnen Element im Array verwendeten Speicher tatsächlich zu entfernen, aber die Elemente können verschoben werden, um das Loch zu füllen, das durch das Entfernen eines Elements entstanden ist. Zum Beispiel:

void remove_element(array_type *array, int index, int array_length)
{
   int i;
   for(i = index; i < array_length - 1; i++) array[i] = array[i + 1];
}

Statisch zugewiesene Arrays können nicht in der Größe geändert werden. Dynamisch zugewiesene Arrays können mit realloc() in der Größe verändert werden. Dadurch wird möglicherweise das gesamte Array an eine andere Stelle im Speicher verschoben, sodass alle Zeiger auf das Array oder seine Elemente aktualisiert werden müssen. Zum Beispiel:

remove_element(array, index, array_length);  /* First shift the elements, then reallocate */
array_type *tmp = realloc(array, (array_length - 1) * sizeof(array_type) );
if (tmp == NULL && array_length > 1) {
   /* No memory available */
   exit(EXIT_FAILURE);
}
array_length = array_length - 1;
array = tmp;

realloc gibt einen NULL-Zeiger zurück, wenn die angeforderte Größe 0 ist oder wenn ein Fehler auftritt. Andernfalls gibt es einen Zeiger auf das neu zugewiesene Array zurück. Der temporäre Zeiger wird verwendet, um Fehler beim Aufruf von realloc zu erkennen, da es statt des Beendens auch möglich ist, das ursprüngliche Array einfach so zu belassen, wie es war. Wenn realloc ein Array nicht neu zuordnen kann, ändert es das ursprüngliche Array nicht.

Beachten Sie, dass diese beiden Operationen ziemlich langsam sind, wenn das Array groß ist oder wenn viele Elemente entfernt werden. Es gibt andere Datenstrukturen wie verknüpfte Listen und Hashes, die verwendet werden können, wenn effizientes Einfügen und Löschen Priorität hat.

Benutzer-Avatar
Chris Farmiloe

Sie möchten nicht jedes Mal Speicher neu zuweisen, wenn Sie etwas entfernen. Wenn Sie die ungefähre Größe Ihrer kennen Deck Wählen Sie dann eine geeignete Größe für Ihr Array und halten Sie einen Zeiger auf den Strom Ende der Liste. Das ist ein Stapel.

Wenn Sie die Größe Ihres Decks nicht kennen und glauben, dass es sehr groß werden könnte und sich ständig in der Größe ändert, müssen Sie etwas Komplexeres tun und a implementieren verknüpfte Liste.

In C haben Sie zwei einfache Möglichkeiten, ein Array zu deklarieren.

  1. Auf dem Stack als statisches Array

    int myArray[16]; // Static array of 16 integers
    
  2. Auf dem Heap als dynamisch zugewiesenes Array

    // Dynamically allocated array of 16 integers
    int* myArray = calloc(16, sizeof(int));
    

Standard-C erlaubt keine Größenänderung von Arrays dieser beiden Typen. Sie können entweder ein neues Array einer bestimmten Größe erstellen und dann den Inhalt des alten Arrays in das neue kopieren, oder Sie können einem der obigen Vorschläge für einen anderen abstrakten Datentyp folgen (z. B.: verkettete Liste, Stapel, Warteschlange, etc).

Benutzer-Avatar
cmaster – monica wieder einsetzen

Welche Lösung Sie benötigen, hängt davon ab, ob Ihr Array seine Reihenfolge beibehalten soll oder nicht.

Im Allgemeinen haben Sie nie nur den Array-Zeiger, sondern auch eine Variable, die ihre aktuelle logische Größe enthält, sowie eine Variable, die ihre zugewiesene Größe enthält. Ich gehe auch davon aus, dass die removeIndex liegt innerhalb der Grenzen des Arrays. Damit ist die Entfernung einfach:

Bestellung irrelevant

array[removeIndex] = array[--logicalSize];

Das ist es. Sie kopieren einfach das letzte Array-Element über das Element, das entfernt werden soll, und dekrementieren die logicalSize des Arrays im Prozess.

Wenn removeIndex == logicalSize-1also das letzte Element entfernt werden soll, degradiert dies zu einer Selbstzuweisung dieses letzten Elements, aber das ist kein Problem.

Ordnung halten

memmove(array + removeIndex, array + removeIndex + 1, (--logicalSize - removeIndex)*sizeof(*array));

Ein bisschen komplexer, denn jetzt müssen wir anrufen memmove() um die Verschiebung von Elementen durchzuführen, aber immer noch ein Einzeiler. Auch dies aktualisiert die logicalSize des Arrays im Prozess.

Benutzer-Avatar
KRoy

Interessanterweise ist das Array durch den Index wahlfrei zugänglich. Und das zufällige Entfernen eines Elements kann sich auch auf die Indizes anderer Elemente auswirken.

    int remove_element(int*from, int total, int index) {
            if((total - index - 1) > 0) {
                      memmove(from+i, from+i+1, sizeof(int)*(total-index-1));
            }
            return total-1; // return the new array size
    }

Beachten Sie, dass memcpy funktioniert in diesem Fall wegen des überlappenden Speichers nicht.

Eine der effizientesten Methoden (besser als Memory Move), um ein zufälliges Element zu entfernen, ist das Austauschen mit dem letzten Element.

    int remove_element(int*from, int total, int index) {
            if(index != (total-1))
                    from[index] = from[total-1];
            return total; // **DO NOT DECREASE** the total here
    }

Aber die Reihenfolge wird nach dem Entfernen geändert.

Wenn das Entfernen wiederum im Schleifenbetrieb erfolgt, kann sich die Neuordnung auf die Verarbeitung auswirken. Memory Move ist eine teure Alternative, um die Reihenfolge beizubehalten, während ein Array-Element entfernt wird. Eine andere Möglichkeit, die Bestellung in einer Schleife zu halten, besteht darin, die Entfernung aufzuschieben. Dies kann durch ein Gültigkeitsarray gleicher Größe erfolgen.

    int remove_element(int*from, int total, int*is_valid, int index) {
            is_valid[index] = 0;
            return total-1; // return the number of elements
    }

Es wird ein Sparse-Array erstellt. Schließlich kann das Sparse-Array kompakt gemacht werden (das keine zwei gültigen Elemente enthält, die ein ungültiges Element zwischen sich enthalten), indem eine Neuordnung vorgenommen wird.

    int sparse_to_compact(int*arr, int total, int*is_valid) {
            int i = 0;
            int last = total - 1;
            // trim the last invalid elements
            for(; last >= 0 && !is_valid[last]; last--); // trim invalid elements from last

            // now we keep swapping the invalid with last valid element
            for(i=0; i < last; i++) {
                    if(is_valid[i])
                            continue;
                    arr[i] = arr[last]; // swap invalid with the last valid
                    last--;
                    for(; last >= 0 && !is_valid[last]; last--); // trim invalid elements
            }
            return last+1; // return the compact length of the array
    }

Benutzer-Avatar
Liaquat Hussein

Versuchen Sie diesen einfachen Code:

#include <stdio.h>
#include <conio.h>
void main(void)
{ 
    clrscr();
    int a[4], i, b;
    printf("enter nos ");
    for (i = 1; i <= 5; i++) {
        scanf("%d", &a[i]);
    }
    for(i = 1; i <= 5; i++) {
        printf("\n%d", a[i]);
    }
    printf("\nenter element you want to delete ");
    scanf("%d", &b);
    for (i = 1; i <= 5; i++) {
        if(i == b) {
            a[i] = i++;
        }
        printf("\n%d", a[i]);
    }
    getch();
}

Benutzer-Avatar
Werner Henz

Ich mache das normalerweise und funktioniert immer.


/Versuche dies/

for (i = res; i < *size-1; i++) { 

    arrb[i] = arrb[i + 1];
}

*size = *size - 1; /*in some ides size -- could give problems*/

1384730cookie-checkElemente aus einem Array in C entfernen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy