[C++] Insert/Delete di elementi di un array di interi

alessandro.de.social
A lezione abbiamo visto due algoritmi basilari per gli array, ma ho alcuni dubbi sul codice:
- Insert:
int insertVettore(vettore v, int &r, int pos, int elem)
{
	int i, exit;
	if(r+1<N && pos>=0 && pos<r)
	{
		for(i=r;i>pos;i--)
			v[i]=v[i-1];
		v[pos]=elem;
		r++;
		exit=1;
	}
	else
		exit=0;
	
	return exit;
}

che ho modificato in
int insertVettore(vettore v, int &r, int pos, int elem)
{
	int i, exit;
	if(r+1<=N && pos>=0 && pos<=r)
	{
		for(i=r;i>pos;i--)
			v[i]=v[i-1];
		v[pos]=elem;
		r++;
		exit=1;
	}
	else
		exit=0;
	
	return exit;
}

Ho modificato:
- la condizione dell'if, scrivendo r+1<=N (perché posso aggiungere un elemento anche quando r=N-1) e pos<=r (perché così posso aggiungere un elemento anche quando pos=r)

- Delete:
(Qui credo che ci sia proprio un errore)
int deleteVettore(vettore v, int &r, int pos)
{
	int i, exit;
	if(r-1>0 && pos>=0 && pos<r)
	{
		for(i=pos;i<r;i++)
			v[i]=v[i+1];
		r--;
		exit=1;
	}
	else
		exit=0;
	return exit;
}

che ho modificato in
int deleteVettore(vettore v, int &r, int pos)
{
	int i, exit;
	if(r-1>=0 && pos>=0 && pos<r)
	{
		for(i=pos;i<r-1;i++)
			v[i]=v[i+1];
		r--;
		exit=1;
	}
	else
		exit=0;
	return exit;
}

Ho modificato:
- la condizione dell'if, scrivendo r-1>=0,perché posso cancellare un elemento anche se r=1: non potrei se fosse 0. Ottengo un vettore con riempimento r=0, ma non credo sia un problema.
- la condizione di terminazione del for, scrivendo i-1, perché se i=r-1, eseguo v[r-1]=v[r]: nel caso migliore potevo risparmiare quest'ultima iterazione, ma se r=N, vado ad accedere a un'area di memoria che non è assegnata all'array, no?
Eppure non ottengo alcun errore a runtime, e in v[N-1] viene copiato 0 (sempre?)
Analogamente, se provo a scrivere su v[N] non ottengo alcun errore, né su v[N+1], ma solo per valori molto maggiori di N (circa N+150).

Le modifiche che ho fatto sono giuste?
P.S.: N è la cardinalità del vettore

Risposte
apatriarca
Direi che le correzioni sono corrette in entrambi i casi. Personalmente scriverei però alcune condizioni diversamente, per esempio \(r < N\) al posto di \(r + 1 \leq N\) e \(r \geq 1\) invece che \(r - 1 \geq 0\).

A questo punto i codici sono corretti, ma ho alcune note puramente stilistiche:

1. Non c'è alcuna ragione di dichiarare le variabili all'inizio della funzione e dichiarare tali variabili quando vengono utilizzate aumenta spesso la leggibilità del codice. Impedisce inoltre spesso di dimenticarsi di inizializzarle o di riutilizzarle (era una limitazione esistente in vecchie versioni del C e poi eliminata nello standard del 1999, ma non è mai stata presente in C++).

2. Si può avere più di un return nella tua funzione. La variabile exit è quindi del tutto inutile.

3. In C++ esiste il tipo bool per rappresentare valori che possono essere veri o falsi. Siccome il valore di ritorno della funzione può essere solo 0 e 1 avrebbe più senso usare questo tipo come valore di ritorno. Rende più chiaro il significato del valore restituito in quanto è immediatamente ovvio rappresenti il successo o meno della funzione. Un valore intero può invece avere altri significati, come la dimensione o il valore che è stato rimosso dall'array o altro.

4. Anche se il C++ permette di non mettere le parentesi credo sia sempre meglio farlo. Non è un grande sforzo da parte del programmatore ma può salvare da alcuni errori.

Avrei quindi insomma scritto i codici come segue:
bool insertInVector(int v[N], int &size, int pos, int elem)
{
    if (size < 0 || size >= N || pos < 0 || pos > size)
    {
        return false;
    }
   
    for (int i = size; i > pos; --i)
    {
        v[i] = v[i - 1];
    }
    
    v[pos] = elem;
    size += 1;
    
    return true;
}

bool removeFromVector(int v[N], int &size, int pos)
{
    if (size < 1 || pos < 0 || pos >= size)
    {
        return false;
    }

    for (int i = pos + 1; i < size; i++)
    {
        v[i - 1] = v[i];
    }

    size -= 1;

    return true;
}

alessandro.de.social
Perfetto, grazie mille! :)

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