[C] Funzione che dovrebbe restituire un vettore

Suwako27
Ciao a tutti, ho dei dubbi riguardo le funzioni che dovrebbero ritornare ""array"":
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void trovaMax(int* a, int n)
 {
	 int cont = 0;

    if(*a > *(a + 1)) {printf("%d|", *a); cont++;}
	 int* b = a + 10;
	 a++;
	 while(a < b)
	 {
		 if((*a > *(a - 1))&&(*a > *(a + 1)))
		 {
			printf("%d|", *a); cont++;
		 }
		 a++;
	 }
    if(*b > *(b - 1)) {printf("%d|", *b); cont++;}
	 printf("\n\n%d", cont);
}
int main()
{
	srand(time(0));
	int n = 11;
	int* a = malloc(sizeof(int)*n);
	for(size_t i = 0; i < n; i++)
	{
		a[i] = rand()% 300;
		printf("%d|", a[i]);
	}
	puts("\n");
	trovaMax(a, n);
}

Il testo di questo esercizio chiede di trovare in un array i "max parziali", cioè quei termini che sono più grandi di quelli adiacenti. Tuttavia è richiesto che il prototipo della funzione sia del tipo: int * TrovaMaxParziale(int * a,int N); cioè si dovrebbero inserire tutti i max parziali all'interno di questo array. E' possibile quindi fare questa modifica senza complicare inutilmente il codice?

Risposte
DeltaEpsilon
Innanzitutto, ti consiglio di dare un nome simbolico e utile alle variabili... sia per il "te" del futuro, sia per noi del presente, che dobbiamo leggere il tuo codice.

Non capisco perchè utilizzi il parametro della funzione trovaMax come un array ma ti rifiuti di usare il subscript operator: a[1] = *(a+1)

Inoltre, nel main stai allocando memoria dinamicamente, senza mai liberarla... molto male!

Tornando al tuo quesito, se l'esercizio chiede di ritornare un array non vedo il problema: lo allochi (dinamicamente) nella funzione, lo riempi e lo ritorni... ricordando però di liberarlo dalla memoria quando hai finito!

Suwako27
È inutile parlare di efficienza, memoria da liberare etc. Dato che è solo un esercizio fine a se stesso; il problema è solo capire l'algoritmo che c'è dietro quello che viene richiesto: In che modo e quando si dovrebbe allocare la memoria dell'array? Prima della chiamata della funzione trovaMax non è chiaro quanti siano gli elementi da inserire nell'array; è quello il mio problema.

Super Squirrel
Prima di parlare dell'algoritmo ti faccio una domanda: in che modo una funzione del tipo
int* TrovaMaxParziale(int *a, int N);

potrebbe darti informazioni sulla dimensione "utile" dell'array ritornato?

DeltaEpsilon
"Suwako27":
È inutile parlare di efficienza, memoria da liberare etc. Dato che è solo un esercizio fine a se stesso; il problema è solo capire l'algoritmo che c'è dietro quello che viene richiesto:

Io intanto te l'ho detto. Rimanere mediocre o no, è una tua scelta.

"Suwako27":

In che modo e quando si dovrebbe allocare la memoria dell'array?

Nello stesso modo con cui hai allocato gli altri array. E, come ti ho già detto, nella funzione trovaMax che poi lo restituirà... oppure un parametro di output, ma dubito che l'esercizio voglia quest'ultima strada, dal momento che ti chiede di cambiare proprio il tipo di ritorno della funzione. :wink:

"Suwako27":

Prima della chiamata della funzione trovaMax non è chiaro quanti siano gli elementi da inserire nell'array; è quello il mio problema.

Ed è lo stesso problema che l'allocazione dinamica risolve.

Nel peggiore dei casi, dovrai prima contare quanti elementi ti servono e poi allocare l'array.

Ma, se ho capito bene l'esercizio, qui è banale dedurre la grandezza finale del tuo array con i dati che già hai a disposizione. :wink:

Suwako27
io intanto te l'ho detto. Rimanere mediocre o no, è una tua scelta
Se ti dico così è perché so cosa andrebbe fatto in questo caso, ma dato che non è il focus principale, quello che hai detto lascia il tempo che trova.
Nel peggiore dei casi, dovrai prima contare quanti elementi ti servono e poi allocare l'array.

Ma, se ho capito bene l'esercizio, qui è banale dedurre la grandezza finale del tuo array con i dati che già hai a disposizione. :wink:
È proprio questo il punto; Anche se contassi quanti elementi dovrei inserire nell'array, dovrei effettuare nuovamente la ricerca per l'inserimento in un secondo momento, ed è quello che volevo evitare.

DeltaEpsilon
"Suwako27":

È proprio questo il punto; Anche se contassi quanti elementi dovrei inserire nell'array, dovrei effettuare nuovamente la ricerca per l'inserimento in un secondo momento, ed è quello che volevo evitare.


Non c'è bisogno di contarli, è noto a priori (conoscendo N) :wink:

Suwako27
L'unica cosa che so è il numero massimo ma non quello esatto

apatriarca
In linea di massima esistono due metodi per "restituire" un array da una funzione:

1. Restituire un puntatore. La memoria è allocata all'interno della funzione ed è quasi sempre rilasciata dal codice che fa uso della funzione. Il codice avrà una forma come la seguente:
int *funzione(..)
{
    int * array = malloc(..);
    // ...
    return array;
}

// codice che fa uso della funzione
int * array = funzione(...);
// ... uso array ...
free(array);


2. Usare un argomento della funzione per restituire l'array. Di solito questo array è allocato e deallocato al di fuori della funzione, ma può anche essere allocato all'interno della funzione. Il codice è qualcosa come il seguente:
void funzione(.., int * array_out)
{
    // ... uso array_out ...
}

// codice che fa uso della funzione
int * array = malloc(...);
// ...
funzione(..., array);
// ...
free(array);


Un'ulteriore problematica quando si ha a che fare con array è quella di sapere il numero di elementi inserito. In questo caso abbiamo le seguenti soluzioni:

1. Non fare nulla (nel caso in cui sia già conosciuta la dimensione per altre ragioni).
2. Usare un valore come terminatore dell'array (usanto spesso nelle stringhe).
3. Se l'array è numerico, puoi usare il primo elemento come dimensione dell'array.
4. Puoi usare un argomento della funzione per questo scopo. Avrai quindi un argomento, qualcosa come [tt]int *outN[/tt], che dovrai riempire con il valore richiesto.
5. Nel caso tu stia usando la soluzione 2 sopra, puoi usare il valore di ritorno della funzione per restituirne la dimensione.
6. Puoi restituire una struttura invece che un puntatore nella soluzione 1 sopra.

Super Squirrel
"DeltaEpsilon":
Non c'è bisogno di contarli, è noto a priori (conoscendo N) :wink:

Non sono sicuro di aver capito quello che intendi, ma il numero "utile" di elementi (chiamiamolo $M$) del secondo array può variare tra $0$ e $[(N+1)/2]$ (dove le parentesi quadre stanno ad indicare la divisione intera). Quindi, nonostante dipenda da $N$, non è comunque possibile definire $M$ senza aver prima valutato l'array di partenza.

@Suwako
Noto che hai ignorato la mia precedente domanda
"Super Squirrel":
Prima di parlare dell'algoritmo ti faccio una domanda: in che modo una funzione del tipo
int* TrovaMaxParziale(int *a, int N);

potrebbe darti informazioni sulla dimensione "utile" dell'array ritornato?

in ogni caso, rifacendomi al post di @apatriarca, credo che con quel prototipo l'unica strada percorribile sia la numero 3).

Suwako27
"Super Squirrel":
[quote="DeltaEpsilon"]Non c'è bisogno di contarli, è noto a priori (conoscendo N) :wink:

Non sono sicuro di aver capito quello che intendi, ma il numero "utile" di elementi (chiamiamolo $ M $) del secondo array può variare tra $ 0 $ e $ [(N+1)/2] $ (dove le parentesi quadre stanno ad indicare la divisione intera). Quindi, nonostante dipenda da $ N $, non è comunque possibile definire $ M $ senza aver prima valutato l'array di partenza.

@Suwako
Noto che hai ignorato la mia precedente domanda
"Super Squirrel":
Prima di parlare dell'algoritmo ti faccio una domanda: in che modo una funzione del tipo
int* TrovaMaxParziale(int *a, int N);

potrebbe darti informazioni sulla dimensione "utile" dell'array ritornato?

in ogni caso, rifacendomi al post di @apatriarca, credo che con quel prototipo l'unica strada percorribile sia la numero 3).[/quote] Scusami, ero dal cellulare e mi è sfuggito il messaggio. Comunque avevo detto prima che posso solo sapere il numero massimo di maxParziali conoscendo il numero di elementi dell'array di partenza, ma il problema è appunto questo: Non so come saperlo a priori quando vado ad allocare memoria per l'array della funzione ed è quello che volevo capire.

DeltaEpsilon
"Suwako27":
L'unica cosa che so è il numero massimo ma non quello esatto


Benissimo; a questo punto sta a te decidere: sacrificare lo spazio o il tempo?

"Super Squirrel":

Non sono sicuro di aver capito quello che intendi, ma il numero "utile" di elementi (chiamiamolo $M$) del secondo array può variare tra $0$ e $[(N+1)/2]$ (dove le parentesi quadre stanno ad indicare la divisione intera). Quindi, nonostante dipenda da $N$, non è comunque possibile definire $M$ senza aver prima valutato l'array di partenza.


Appunto, è proprio quello che intendevo: non c'è bisogno di contare. :-D

Almeno che l'OP non intenda sacrificare il tempo e salvare lo spazio per il numero esatto di elementi che gli interessa.

Suwako27
"DeltaEpsilon":
[quote="Suwako27"]L'unica cosa che so è il numero massimo ma non quello esatto


Benissimo; a questo punto sta a te decidere: sacrificare lo spazio o il tempo?

"Super Squirrel":

Non sono sicuro di aver capito quello che intendi, ma il numero "utile" di elementi (chiamiamolo $ M $) del secondo array può variare tra $ 0 $ e $ [(N+1)/2] $ (dove le parentesi quadre stanno ad indicare la divisione intera). Quindi, nonostante dipenda da $ N $, non è comunque possibile definire $ M $ senza aver prima valutato l'array di partenza.


Appunto, è proprio quello che intendevo: non c'è bisogno di contare. :-D

Almeno che l'OP non intenda sacrificare il tempo e salvare lo spazio per il numero esatto di elementi che gli interessa.[/quote] Ok, quindi non ha senso trovare il numero preciso, ma conviene comunque allocare memoria per il numero massimo di elementi?

DeltaEpsilon
"Suwako27":

Ok, quindi non ha senso trovare il numero preciso, ma conviene comunque allocare memoria per il numero massimo di elementi?


Nulla non ha senso. Tutto va ponderato con le proprie esigenze.

Quella di allocare l'array con il numero massimo di elementi possibili è una strada, ma non l'unica.
E certamente non l'unica sensata.

Suwako27
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int* trovaMax(int* a, int n)
{
	 int cont = 0;
	 int N2 = (n+1)/2;
    int* orsotolino = malloc(sizeof(int)*N2);
	 
 if(*a > *(a + 1)){*orsotolino = *a; printf("%d|", *orsotolino); cont++; orsotolino++;}
	 int* b = a + 10;
	 a++;
 while(a < b)
 {
	if((*a > *(a - 1))&&(*a > *(a + 1)))
	{
	  *orsotolino = *a; printf("%d|", *orsotolino); cont++; orsotolino++;
	}
		a++;
 }
 if(*b > *(b - 1)){*orsotolino = *b; printf("%d|", *orsotolino); cont++; orsotolino++;}
	 printf("\n\n%d", cont);
	 return orsotolino;
}
int main()
{
	srand(time(0));
	int n = 11;
	int* a = malloc(sizeof(int)*n);
	for(size_t i = 0; i < n; i++)
	{
		a[i] = rand()% 300;
		printf("%d|", a[i]);
	}
	puts("\n");
	
	int* orsotolino = trovaMax(a, n);

}
Questo è il codice che avevo scritto inizialmente(quello che avevo pensato più che altro), considerando appunto il numero massimo di elementi. Però così non va bene; la funzione non riesce a passare correttamente il puntatore e non possibile do conseguenza usare la free nel main. Su windows il problema non viene rilevato.

Suwako27
L'errore non è causato dal fatto che l'area di memoria allocata localmente nella funzione viene distrutta una volta che questa ritorna il valore?

Super Squirrel
- utilizzare u o v come nome di un array risulta troppo banale?!
- come già detto da @DeltaEpsilon, perché non utilizzi l'operatore di indicizzazione []?
- al fine di rendere il codice più chiaro e leggibile ti consiglio di rispettare la spaziatura e l'indentazione e di riportare una sola istruzione per riga.

Premesso che ho dato solo un'occhiata veloce all'ultimo codice che hai postato, ma ti rendi conto che la funzione ritorna un puntatore che, causa vari incrementi, non punta all'inizio della memoria allocata?

Relativamente all'algoritmo di ricerca dei massimi "parziali", non sarebbe più semplice fare qualcosa del genere:
void trovaMax(int *v, int n)
{
    for(unsigned int i = 0; i < n; ++i)
    {
        if((!i || v[i] > v[i - 1]) && (i == n - 1 || v[i] > v[i + 1]))
        {
            printf("%d ", v[i++]);
        }
    }
}


Inoltre ancora non hai risposto alla domanda che ti ho posto in precedenza. Ipotizziamo che all'interno della funzione allochi memoria per il caso peggiore, ossia $[(n+1)/2]$, e che al ritorno nel main tu voglia stampare i massimi trovati, come fai? Sai che quell'array ha dimensione $[(n+1)/2]$, ma non conosci la dimensione "utile", ossia il numero di massimi effettivamente trovati.
E a tal proposito, visto che il prototipo della funzione deve essere quello, l'unica strada percorribile diventa il punto 3) prospettato da @apatriarca.

Suwako27
Ammetto che l'uso di nomi strani è stato fatto solo per "goliardia". Ora capisco cosa ha causato il problema ed effettivamente è stato un lapsus incredibile anche se rimane grave come errore. Invece per la domanda che mi hai fatto non riesco ancora a rispondere; è il motivo principale per il quale ho cominciato questa discussione. Inoltre che sia meglio che la funzione non restituisca nulla e svolga tutto al suo interno è ovvio perché non devi preoccuparti di nulla nel main ma l'esercizio chiede purtroppo altro.

DeltaEpsilon
"Suwako27":
Invece per la domanda che mi hai fatto non riesco ancora a rispondere; è il motivo principale per il quale ho cominciato questa discussione.

Sei stato abbondantemente risposto.

"Suwako27":

Inoltre che sia meglio che la funzione non restituisca nulla e svolga tutto al suo interno è ovvio perché non devi preoccuparti di nulla nel main ma l'esercizio chiede purtroppo altro.


Meglio? Ovvio? Purtroppo? Assolutamente no.

Capisco la comodità della stampa a video per vedere sin da subito se un determinato algoritmo funziona come dovrebbe... ma poi finisce lì, deve finire lì.

E' assolutamente sconsigliato usare la stampa o l'inserimento da tastiera all'interno di funzioni, poichè queste sono pensate per svolgere un ruolo ben preciso e ritornare, nel caso, un risultato come output al chiamante (che magari sta usufruendo della tua libreria). Tutto ciò senza dare per scontato che la macchina che utilizzerà questa funzione sia dotata di un output screen o di una tastiera :wink:

Suwako27
"DeltaEpsilon":
[quote="Suwako27"]Invece per la domanda che mi hai fatto non riesco ancora a rispondere; è il motivo principale per il quale ho cominciato questa discussione.

Sei stato abbondantemente risposto.

"Suwako27":

Inoltre che sia meglio che la funzione non restituisca nulla e svolga tutto al suo interno è ovvio perché non devi preoccuparti di nulla nel main ma l'esercizio chiede purtroppo altro.


Meglio? Ovvio? Purtroppo? Assolutamente no.

Capisco la comodità della stampa a video per vedere sin da subito se un determinato algoritmo funziona come dovrebbe... ma poi finisce lì, deve finire lì.

E' assolutamente sconsigliato usare la stampa o l'inserimento da tastiera all'interno di funzioni, poichè queste sono pensate per svolgere un ruolo ben preciso e ritornare, nel caso, un risultato come output al chiamante (che magari sta usufruendo della tua libreria). Tutto ciò senza dare per scontato che la macchina che utilizzerà questa funzione sia dotata di un output screen o di una tastiera :wink:[/quote]
non ho capito cosa hai detto :lol:. in questo caso se la funzione dovrebbe soltanto trovare dei valori non sarebbe meglio semplicemente stamparli a video senza andare a "disturbare" la memoria ? :?

DeltaEpsilon
"Suwako27":

non ho capito cosa hai detto :lol:


Sei stato risposto sulle questioni precedenti, e poni la stessa domanda.
Ti ho risposto sul perchè non è buona norma usare la stampa nelle funzioni, e poni la stessa domanda.

Direi (anzi, ripeto) che le risposte ti son state già date... e pure in italiano per quanto ne so... lavora sulla comprensione a questo punto, che ti devo dire...

"Suwako27":

se la funzione dovrebbe soltanto trovare dei valori non sarebbe meglio semplicemente stamparli a video senza andare a "disturbare" la memoria ? :?


Negli esercizi scolastici si può anche fare questo strappo, ma non è assolutamente buona norma di programmazione. E siccome state imparando a programmare, non vedo perchè insegnarvi e abituarvi male.

Se tu chiami la funzione sqrt per ottenere la radice quadrata di un numero, per poi utilizzarla in un altro calcolo, hai bisogno che quella funzione ritorni il valore atteso... e così succede.

Non ti darebbe fastidio se la funzione si permettesse di stampare il valore anzichè ritornartelo? Oltre ad essere tremendamente inutile...




Se ti preoccupi così tanto della memoria, libera quella allocata dinamicamente :lol:

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