[C++] Aiuto con funzioni e puntatori
Salve a tutti ragazzi. E' da ieri che cerco di fare un esercizio al compilatore. L'esercizio in questione è costituito dai seguenti passaggi: 1) acquisire dallo stdin un array di interi. 2) visualizzare a video l'array inserito. 3)ordinare gli elementi dell'array in ordine crescente. 4) visualizzare a video l'array ordinato.
Il tutto dovrei farlo preferibilmente mediante l'uso di funzioni. Riscontro dei problemi col secodno punto e con i succesivi in quanto non so come far ritornare un array da una funzione e in che modo manipolarla nella funzione successiva. So che posso farlo tramite un puntatore ma non so dove sia più corretto dichiarare l puntatore e come utilizzarlo.
Posto di seguito una bozza del codice sorgente da me scritto nella speranza che qualcuno di voi mi aiuti a capire se questa prima parte è corretta ed aiutarmi a capire come affrontare i punti successivi.
P.S. se provate a compilare il codice noterete che non mi visualizza a video l'array.
Sareste cosi gentili da aiutarmi?
Ringrazio in anticipo per l'attenzione.
Il tutto dovrei farlo preferibilmente mediante l'uso di funzioni. Riscontro dei problemi col secodno punto e con i succesivi in quanto non so come far ritornare un array da una funzione e in che modo manipolarla nella funzione successiva. So che posso farlo tramite un puntatore ma non so dove sia più corretto dichiarare l puntatore e come utilizzarlo.
Posto di seguito una bozza del codice sorgente da me scritto nella speranza che qualcuno di voi mi aiuti a capire se questa prima parte è corretta ed aiutarmi a capire come affrontare i punti successivi.
#include <iostream> #include <stdlib.h> //dichiarazioni const int M=100; int a[M]; int n; using namespace std; //inserimento array di interi void input(int a[], int n){ bool ok=true; int temp[M]; do{ ok=true; cout << "inserire numero di elementi: "<<endl; cin >> n; if(n<=0){ cout << "il numero di elementi deve essere positivo"<<endl; ok=false; } else if(n>0){ cout << "inserire elementi dell'array: "<<endl; for(int i=0; i<n; i++) cin >>temp[i]; ok=true; } }while(!ok); for(int j=0; j<n; j++){ a[j]=temp[j]; } return; } //visualizzo la lista inserita void visualizza(int a[] ){ cout << "la lista di elementi inserita e': "<<endl; for(int i=0; i<n; i++) cout << a[i]; cout <<endl; return; } //MAIN int main(){ int lista[M]; int numero; input(lista, numero); visualizza(lista); system("pause"); return 0; }
P.S. se provate a compilare il codice noterete che non mi visualizza a video l'array.
Sareste cosi gentili da aiutarmi?
Ringrazio in anticipo per l'attenzione.
Risposte
Ci sono alcune osservazioni importanti:
1. [tt]strlen[/tt] è implementata in modo simile al seguente codice che ho scritto:
Per trovare la lunghezza scorre quindi l'intera stringa in cerca del terminatore. E' quindi assurdo usare tale funzione in un ciclo che scorre la stringa perché trasformi un codice lineare in uno quadratico (scorri la stringa \(n\) volte invece di una sola..).
2. Una volta che hai letto il valore da input, se la stringa era più lunga di 100 caratteri, la tua memoria è stata ormai corrotta ed è abbastanza inutile verificare a quel punto la lunghezza della stringa. Sarebbe stato meglio usare get o getline. Il codice dentro [tt]inputstringa[/tt] non ha insomma alcun senso..
3. Il vero motivo per cui non funziona il codice è che stai confrontando ogni volta le stesse stringhe. Avresti insomma dovuto confrontare [tt]str1[/tt] con [tt]ar + i[/tt] (cioè la parte della stringa che parte dal carattere i-esimo. Non è tuttavia possibile usare strcmp perché questa funzione si aspetta che entrambe le stringhe finiscono nella stessa posizione. Non è insomma possibile usare tale funzione per testare che una stringa sia una sottostringa di un'altra. Una possibilità è quella di fare un ciclo sulla seconda stringa e confrontare ogni carattere. Un'altra alternativa è di usare strstr che fa la ricerca di una sottostringa per te o confrontare con strncmp che limita la ricerca ad un numero limitato di caratteri (la lunghezza della sottostringa per farlo funzionare come desideri).
4. Non capisco il senso di stampare un carattere per volta in visualizza..
5. Il tuo professore probabilmente non conosce affatto il C++. Sa qualcosa di C e ha visto l'IO del C++ e deciso che lo preferiva (la cosa assurda è che conosco molti che programmano in C++ che preferiscono quello del C..).
1. [tt]strlen[/tt] è implementata in modo simile al seguente codice che ho scritto:
size_t strlen(const char *str) { size_t result = 0; while (str[result] != '\0') { ++result; } return result; }
Per trovare la lunghezza scorre quindi l'intera stringa in cerca del terminatore. E' quindi assurdo usare tale funzione in un ciclo che scorre la stringa perché trasformi un codice lineare in uno quadratico (scorri la stringa \(n\) volte invece di una sola..).
2. Una volta che hai letto il valore da input, se la stringa era più lunga di 100 caratteri, la tua memoria è stata ormai corrotta ed è abbastanza inutile verificare a quel punto la lunghezza della stringa. Sarebbe stato meglio usare get o getline. Il codice dentro [tt]inputstringa[/tt] non ha insomma alcun senso..
3. Il vero motivo per cui non funziona il codice è che stai confrontando ogni volta le stesse stringhe. Avresti insomma dovuto confrontare [tt]str1[/tt] con [tt]ar + i[/tt] (cioè la parte della stringa che parte dal carattere i-esimo. Non è tuttavia possibile usare strcmp perché questa funzione si aspetta che entrambe le stringhe finiscono nella stessa posizione. Non è insomma possibile usare tale funzione per testare che una stringa sia una sottostringa di un'altra. Una possibilità è quella di fare un ciclo sulla seconda stringa e confrontare ogni carattere. Un'altra alternativa è di usare strstr che fa la ricerca di una sottostringa per te o confrontare con strncmp che limita la ricerca ad un numero limitato di caratteri (la lunghezza della sottostringa per farlo funzionare come desideri).
4. Non capisco il senso di stampare un carattere per volta in visualizza..
5. Il tuo professore probabilmente non conosce affatto il C++. Sa qualcosa di C e ha visto l'IO del C++ e deciso che lo preferiva (la cosa assurda è che conosco molti che programmano in C++ che preferiscono quello del C..).
Approfitto del topic per chiedere anche io una cosa.
Provando a svolgere l'esercizio ho trovato alcune difficoltà sull'utilizzo della funzione getline. Più precisamente se inserivo da tastiera un numero di caratteri superiore al valore passato a getline, una successiva chiamata alla funzione getline non mi permetteva di inserire una nuova stringa da tastiera. Facendo alcune ricerche sono venuto a conoscenza dei flag relativi all'oggetto cin e al concetto di pulizia del buffer. Premesso che la mia conoscenza della classe iostream è pressoché nulla, volevo sapere se il modo in cui ho implementato la funzione "inserisci_stringa" è accettabile oppure bisogna cambiare qualcosa.
Provando a svolgere l'esercizio ho trovato alcune difficoltà sull'utilizzo della funzione getline. Più precisamente se inserivo da tastiera un numero di caratteri superiore al valore passato a getline, una successiva chiamata alla funzione getline non mi permetteva di inserire una nuova stringa da tastiera. Facendo alcune ricerche sono venuto a conoscenza dei flag relativi all'oggetto cin e al concetto di pulizia del buffer. Premesso che la mia conoscenza della classe iostream è pressoché nulla, volevo sapere se il modo in cui ho implementato la funzione "inserisci_stringa" è accettabile oppure bisogna cambiare qualcosa.
#include <iostream> #include <cstring> #include <limits> using namespace std; void inserisci_stringa(char *stringa, const unsigned int &max_characters, unsigned int &len) { cout << "INSERIRE STRINGA(MAX " << max_characters << " CARATTERI): "; cin.getline(stringa, max_characters + 1); if(cin.good()) { len = strlen(stringa); } else { cout << "STRINGA TROPPO LUNGA, I CARATTERI IN ECCESSO NON SARANNO CONSIDERATI" << endl; len = max_characters; cin.clear(); cin.ignore(numeric_limits<streamsize>::max(), '\n'); } } void estrai_prima_parola(char *stringa, unsigned int &len) { bool flag = false; unsigned int spazio = 0; unsigned int i; for(i = 0; i < len; i++) { if(stringa[i] == ' ') { if(flag) { break; } ++spazio; } else { stringa[i - spazio] = stringa[i]; flag = true; } } stringa[i - spazio] = '\0'; len = i - spazio; } unsigned int trova_parola(char *parola, char *stringa, const unsigned int &len_parola, const unsigned int &len_stringa) { unsigned int cont = 0; unsigned int j; bool flag; for(unsigned int i = 0; i <= len_stringa - len_parola; i++) { flag = true; for(j = 0; j < len_parola; j++) { if(stringa[i + j] != parola[j]) { flag = false; break; } } if(flag) { ++cont; } } return cont; } int main() { const unsigned int MAX_CHARACTERS = 100; char stringa_1[MAX_CHARACTERS + 1]; char stringa_2[MAX_CHARACTERS + 1]; unsigned int len_1; unsigned int len_2; inserisci_stringa(stringa_1, MAX_CHARACTERS, len_1); inserisci_stringa(stringa_2, len_1, len_2); estrai_prima_parola(stringa_2, len_2); cout << "NELLA STRINGA:" << endl << "<" << stringa_1 << ">" << endl; cout << "LA PAROLA:" << endl << "<" << stringa_2 << ">" << endl; cout << "SI RIPETE " << trova_parola(stringa_2, stringa_1, len_2, len_1) << " VOLTE"; }
Quella funzione è abbastanza ok, anche se la cambierei così:
Non mi è invece chiaro come mai estrai la prima parola e poi usi trova parola per calcolare il numero.
Personalmente cambierei quella funzione in:
Ovviamente quest'ultima avrebbe problemi se le stringhe non sono state inizializzate in modo appropriato. Ma lo stesso si può dire di molte funzioni di cstring.
#include <iostream> #include <limits> using namespace std; size_t inserisci_stringa(char * stringa, size_t max_characters) { size_t len = 0; cout << "INSERIRE STRINGA(MAX " << max_characters << " CARATTERI): "; cin.getline(stringa, max_characters + 1); if (cin.good( )) { len = cin.gcount( ) - 1; } else { cout << "STRINGA TROPPO LUNGA, I CARATTERI IN ECCESSO NON SARANNO " "CONSIDERATI" << endl; len = max_characters; cin.clear( ); cin.ignore(numeric_limits<streamsize>::max( ), '\n'); } return max_characters; }
Non mi è invece chiaro come mai estrai la prima parola e poi usi trova parola per calcolare il numero.
Personalmente cambierei quella funzione in:
#include <cctype> using namespace std; size_t conta_ripetizioni(char * parola, char * stringa) { if (!parola || !stringa || *parola == '\0' || *stringa == '\0') { return 0; } size_t ripetizioni = 0; char * s = parola; for (; *stringa != '\0'; ++stringa) { if (*s == *stringa) { ++s; continue; } if (*s == '\0') { ripetizioni += !!isspace(*stringa); } s = parola; } return ripetizioni + (*s == '\0'); }
Ovviamente quest'ultima avrebbe problemi se le stringhe non sono state inizializzate in modo appropriato. Ma lo stesso si può dire di molte funzioni di cstring.
Quella funzione è abbastanza ok, anche se la cambierei così: ...
Non conoscevo il metodo gcount, ma oltre ad evitare di includere la libreria cstring (per l'utilizzo di strlen), comporta anche un minor numero di calcoli? Nel senso gcount è cmq implementato con un ciclo oppure riporta semplicemente un membro dell'oggetto cin?
L'ultima riga dovrebbe essere "return len", giusto?
Vedo che utilizzi spesso il tipo size_t, presumo sia cmq un intero, ma quali sono le sue particolarità?
Non mi è invece chiaro come mai estrai la prima parola e poi usi trova parola per calcolare il numero.
Visto che la seconda stringa inserita deve essere una parola (intesa come sequenza di caratteri escluso lo spazio), la funzione estrai_prima_parola si assicura che tale condizione venga rispettata.
Personalmente cambierei quella funzione in: ...
Interessante il modo in cui hai implementato le condizioni del ciclo for. Se ho ben interpretato il tuo codice nella frase "il nilo" la parola "il" si ripete 1 volta giusto?
Io invece ho interpretato la consegna dell'esercizio diversamente e ho implementato la funziona trova_parola affinché nel suddetto esempio la parola "il" si ripete 2 volte.
"Super Squirrel":Quella funzione è abbastanza ok, anche se la cambierei così: ...
Non conoscevo il metodo gcount, ma oltre ad evitare di includere la libreria cstring (per l'utilizzo di strlen), comporta anche un minor numero di calcoli? Nel senso gcount è cmq implementato con un ciclo oppure riporta semplicemente un membro dell'oggetto cin?
L'ultima riga dovrebbe essere "return len", giusto?
Vedo che utilizzi spesso il tipo size_t, presumo sia cmq un intero, ma quali sono le sue particolarità?
A direi il vero non la conoscevo neanche io, l'ho trovata per caso. Suppongo sia implementata come una variabile membro.
"Super Squirrel":Personalmente cambierei quella funzione in: ...
Interessante il modo in cui hai implementato le condizioni del ciclo for. Se ho ben interpretato il tuo codice nella frase "il nilo" la parola "il" si ripete 1 volta giusto?
Io invece ho interpretato la consegna dell'esercizio diversamente e ho implementato la funziona trova_parola affinché nel suddetto esempio la parola "il" si ripete 2 volte.
In realtà mi sa che non controllo per la presenza di spazi all'inizio. Quindi "il pail" produce 2 mentre "il nilo" ne trova solo una. D'altra parte, ci sarebbe anche il problema delle auto-intersezioni della parola che si sta cercando. Per esempio non sono sicuro che il mio codice trovi "aaab" in "aaaab", quindi suppongo di non averci pensato abbastanza.
A direi il vero non la conoscevo neanche io, l'ho trovata per caso. Suppongo sia implementata come una variabile membro.
Tramite codeblocks ho aperto l'implementazione del metodo ed effettivamente ritorna semplicemente la variabile membro _M_gcount.