[C] Eliminazione elemento da array e riallocazione

oleg.fresi
Buonasera. Sto avendo un problema col c. Devo scrivere una funzione a cui viene passato un array allocato dinamicamente nel main e un intero che indica la posizione di un elemento che va cancellato. Inoltre l'array deve ridimensionarsi, rilasciando una locazione di memoria non più occupata. Il codice che ho scritto però non funziona.
Sapreste aiutarmi a capire il problema, o un modo migliore di risolvere? Grazie in anticipo!

#include <stdlib.h>
void eliminaElemento(int lista[], int posizione, int size)
{
    int*listaProvvisoria = (int*) malloc((size - 1) * sizeof(int));
    for(int i = 0; i < posizione; i++)
        listaProvvisoria[i] = lista[i];
    for(int i = posizione + 1; i < size; i++)
        listaProvvisoria[i] = lista[i];

    *lista= (int*) realloc(lista, (size- 1) * sizeof(int) );
    for(int i = 0; i < size - 1; i++)
        lista[i] = listaProvvisoria[i];
}

void stampaLista(int lista[], int size)
{
    for(int i = 0; i < size; i++)
        printf("\n %d", lista[i]);
}

int main(void)
{
    int size = 10;
    int posizione = 3;
    int *lista = (int *) malloc(size * sizeof(int));
    stampaLista(lista, size);
    eliminaElemento(lista, posizione, size);
    stampaLista(lista, size - 1);
}

Risposte
vict85
La riallocazione è esplicitamente richiesta dal professore? Insomma, in genere non si rialloca quando si cancellano pochi dati. In genere, ci si limita a dichiarare che la dimensione è cambiata.

Inoltre la definizione della funzione è strana: passi come array qualcosa che vuoi modificare e non fornisci la nuova dimensione a chi usa la funzione.

vict85
Comunque il tuo codice non assegnava alcun valore a lista.

Comunque, io mi sarai limitato a qualcosa come:
#include <stdlib.h>
#include <stdio.h>

int
eliminaElemento( int lista[], int posizione, int size )
{
    if ( posizione >= size )
        return size;

    for ( int i = posizione + 1; i < size; i++ )
        lista[ i - 1 ] = lista[ i ];

    return size - 1;
}

void
stampaLista( int lista[], int size )
{
    for ( int i = 0; i < size; i++ )
        printf( "%d ", lista[ i ] );

    printf( "\n" );
}

void
inserisciValori( int lista[], int size )
{
    for ( int i = 0; i < size; i++ )
        lista[ i ] = i;
}

int
main( void )
{
    int size = 10;
    int posizione = 3;
    int* lista = (int*)malloc( size * sizeof( int ) );
    inserisciValori( lista, size );
    stampaLista( lista, size );
    size = eliminaElemento( lista, posizione, size );
    stampaLista( lista, size );
}


Mentre se devi proprio riallocare, allora devi passare un puntatore all'array (devi modificare il valore del puntatore). Ci ho provato senza, ma il mio address sanitaser non apprezzava.
#include <stdlib.h>
#include <stdio.h>

int
eliminaElemento( int** lista, int posizione, int size )
{
    if ( posizione >= size )
        return size;

    for ( int i = posizione + 1; i < size; i++ )
        ( *lista )[ i - 1 ] = ( *lista )[ i ];

    *lista = (int*)realloc( *lista, ( size - 1 ) * sizeof( int ) );
    return size - 1;
}

void
stampaLista( int lista[], int size )
{
    for ( int i = 0; i < size; i++ )
        printf( "%d ", lista[ i ] );

    printf( "\n" );
}

void
inserisciValori( int lista[], int size )
{
    for ( int i = 0; i < size; i++ )
        lista[ i ] = i;
}

int
main( void )
{
    int size = 10;
    int posizione = 3;
    int* lista = (int*)malloc( size * sizeof( int ) );
    inserisciValori( lista, size );
    stampaLista( lista, size );
    size = eliminaElemento( &lista, posizione, size );
    stampaLista( lista, size );
}

Super Squirrel
Alcune osservazioni:

- il problema non è che non funziona, ma che non compila, in quanto stai cercando di assegnare un puntatore ad una variabile intera:
*lista = (int*) realloc(lista, (size - 1) * sizeof(int));

- il secondo for nella funzione eliminaElemento() è sbagliato e andrebbe corretto, per esempio, nel seguente modo:
for(int i = posizione + 1; i < size; i++)
    listaProvvisoria[i - 1] = lista[i];

- inoltre, dal momento che dalla documentazione della realloc() si legge
The function may move the memory block to a new location (whose address is returned by the function).

è sbagliato passare il parametro lista per copia;
- la funzione eliminaElemento() dovrebbe occuparsi anche di aggiornare il valore di size;
- sarebbe buona norma liberare la memoria allocata in precedenza;
- listaProvvisoria è superfluo, basta spostare gli elementi a partire da posizione;
- chiamare un array dinamico lista mi sembra un po' ambiguo.

Sulla base di quanto appena detto il codice diventa:
#include <stdlib.h>
#include <stdio.h>

void elimina_elemento(int **v, int *size, int posizione)
{
    for(int i = posizione + 1; i < *size; ++i)
    {
        (*v)[i - 1] = (*v)[i];
    }
    *v = (int*)realloc(*v, --(*size) * sizeof(int));
}

void stampa_array(int *v, int size)
{
    for(int i = 0; i < size; ++i)
    {
        printf("%d ", v[i]);
    }
    printf("\n");
}

int main()
{
    int size = 5;
    int *v = (int *)malloc(size * sizeof(int));
    stampa_array(v, size);
    elimina_elemento(&v, &size, 2);
    stampa_array(v, size);
    free(v);
}


Inoltre, a meno che tu non sia obbligato a farlo per esigenze particolari, non ha molto senso riallocare la memoria ogni volta, basta associare all'array dinamico una dimensione massima e una dimensione utilizzata.


EDIT:
Preceduto

oleg.fresi
Grazie mille a tutti per l'aiuto. La soluzione che ha fornito super squirrel è quella che si adatta meglio al mio caso.
Grazie ancora a tutti!

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.