PDA

View Full Version : [c++] ESERCIZIO ARRAY DI PUNTATORI CHAR


mistergks
04-03-2012, 12:19
Ho svolto questo esercizio...mi compila ma mi da un errore "il programma ha smesso di funzionare ecc..." in fase di esecuzione! Cosa non va??

La tua amica Renata Limbranata è nei guai. Si è sposata solo pochi giorni fa eppure il suo matrimonio sembra già andare a rotoli. Suo marito passa la maggior parte del giorno al computer a scrivere mail di lavoro (dice lui!), ma lei è molto sospettosa, non riesce a credere che si sia portato il lavoro anche in viaggio di nozze… E così ha deciso! Approfittando delle assenze del marito ti ha inoltrato tutte le sue mail (circa un centinaio), pregandoti di leggerle e farle sapere se, come sospetta lei, il marito ha un’amante. Tu però, che conosci Renata e che sai quanto possa essere paranoica a volte, decidi di non sprecare belle giornate a leggere mail con molta probabilità noiose e di affidarti alle tue abilità informatiche per risparmiare tempo. A tale scopo, si scriva in C++ un programma completo opportunamente modularizzato in funzioni che, dato in input l’elenco delle mail di Renata (che per semplicità si può implementare come array di stringhe) conti quante sono le mail in cui è contenuta almeno una tra le seguenti parole: amore, tesoro, cucciolotto, trottolino.

MIA SOLUZIONE:


#include <iostream>
using namespace std;

int confronta(char *email[], char *parole[]);

int main(){
int numero_email=0;
char *email[10]={"Ciao amore come va","senti tesoro", "sei un cretino" };
char *parole[10]={"amore","tesoro","cucciolotto", "trottolino"};
numero_email=confronta(email,parole);
cout<<"Il numero delle email sospette è:"<<numero_email<<endl;


system("pause");
return 0;
}

int confronta(char *email[], char *parole[]){
int conta=0;
for(int i=0; email[i]; i++){
for(int j=0; parole[i]; j++){
if(email[i] == parole[j])
conta++;
}
}
return conta;
}

ndakota
04-03-2012, 13:47
Soprassederò sull'opportunamente modularizzato e sul fatto che è poco C++ :O

Un errore evidente è che confronti le stringe che usi, che sono quelle del C, con l'operatore ==. Dovresti usare la funzione strcmp (http://www.cplusplus.com/reference/clibrary/cstring/strcmp/). Altrimenti, anziché usare le stringe del C(char*), potresti usare quelle definite nella standard library del C++(string) e continuare ad usare ==.

Un altro errore, questa volta logico, è che il numero di mail sospette sarà sempre 0, a meno di avere intere mail uguali ad una delle parole da ricercare.

mistergks
04-03-2012, 17:40
Quindi metto la strcmp()...ok

Mentre per l errore logico come risolvo?

Inviato dal mio GT-I9003 usando Tapatalk

ndakota
04-03-2012, 18:47
Usa la funzione strstr (http://www.cplusplus.com/reference/clibrary/cstring/strstr/). A questo punto strcmp non ti serve più :D

mistergks
05-03-2012, 00:11
Ma a me serve un modo di far restituire alla funzione il risultato di conta che sarebbe il numero delle enail che contengoni una parola tra quelle

Inviato dal mio GT-I9003 usando Tapatalk

mistergks
05-03-2012, 00:19
Ma a me serve un modo di far restituire alla funzione il risultato di conta che sarebbe il numero delle enail che contengoni una parola tra quelle

Inviato dal mio GT-I9003 usando Tapatalk

ndakota
05-03-2012, 08:48
if(strstr(parole[j], email[i]))
conta++;


Verifica che la parola è contenuta nella mail. Non è quello che vuoi?

mistergks
05-03-2012, 09:49
if(strstr(parole[j], email[i]))
conta++;


Verifica che la parola è contenuta nella mail. Non è quello che vuoi?


No! Io voglio CONTARE le email che contengono una di quelle parole!

ndakota
05-03-2012, 10:08
E' quello che vuoi eh. Poi se vuoi contare al massimo 1 per ogni mail c'è solo una piccola modificare da fare e mi sembra che a questo punto puoi anche fartela da solo :)

mistergks
05-03-2012, 11:13
E' quello che vuoi eh. Poi se vuoi contare al massimo 1 per ogni mail c'è solo una piccola modificare da fare e mi sembra che a questo punto puoi anche fartela da solo :)

ho provato ma non va lo stesso.. mi restituisce ancora 0!
#include <iostream>
using namespace std;

int confronta(char *email[], char *parole[]);

int main(){
int numero_email=0;
char *email[4]={"Ciao amore come va","senti tesoro", "sei un cretino" };
char *parole[5]={"amore","tesoro","cucciolotto", "trottolino"};
numero_email=confronta(email,parole);
cout<<"Il numero delle email sospette e':"<<numero_email<<endl;


system("pause");
return 0;
}

int confronta(char *email[], char *parole[]){
int conta=0;
for(int i=0; email[i]; i++){
for(int j=0; parole[j]; j++){
if(strstr(parole[j], email[i]))
conta++;
}
}
return conta;
}




Mi sorge un dubbio... può essere che le parole di ogni frase vanno separate?

ndakota
05-03-2012, 11:22
Ho fatto caso ora alle condizioni dei for. Perchè le hai fatte così?

mistergks
05-03-2012, 11:38
Ho fatto caso ora alle condizioni dei for. Perchè le hai fatte così?

cioè?

Comunque ho fatto una prova con la strcmp() e mi restituisce 12...cioè il numero delle lettere di tutte le parole contenute in tutte le email..
sarebbero "amore" e "tesoro".. ed evidentemente mette un carattere in piu o conta lo spazio..

Ora... a me servirebbe contare quante email contengono una di quelle parole specificate! Come faccio?

ndakota
05-03-2012, 15:03
Scusa, gli argomenti di strstr dovevano essere passati all'inverso.

A me così funziona


#include <iostream>
#include <cstring>
using namespace std;

int confronta(const char *email[], const char *parole[]);

int main(){
int numero_email=0;
const char *email[3]={"Ciao amore come va","senti tesoro", "sei un cretino" };
const char *parole[4]={"amore","tesoro","cucciolotto", "trottolino"};
numero_email=confronta(email,parole);
cout<<"Il numero delle email sospette e':"<<numero_email<<endl;

return 0;
}

int confronta(const char *email[], const char *parole[]){
int conta=0;
for(int i=0; i < 3; i++){
for(int j=0; j < 4; j++){
if(strstr(email[i], parole[j]))
conta++;
}
}
return conta;
}


Compilo con


g++ -Wall -o es es.cpp


Ed eseguo con


./es


Output


Il numero delle email sospette e':2


Bè, è chiaramente da sistemare. Ho cablato nel codice le dimensioni degli array.

Qualche nota sparsa:
Ho riaddato la dimensione degli array a quella che usavi effettivamente
Ho aggiunto la libreria cstring per poter usare strstr() o strcmp()
Ho invertito come detto gli argomenti a strstr()
Ho cambiato le condizioni dei for

mistergks
05-03-2012, 15:44
Ora funziona anche a me!! Però mi rimangono dei dubbi:
1)perché gli array char li hai dichiarati const? Ho provato a cancellare const da dichiarazioni e funzione ma mi da errori di compilazione
2)se volesso farlo generico e quindi senza sapere la size degli array? I cicli for sarebbero sbagliati..perchè dovrebbero continuare su tutti gli elementi
3)la strstr() non so se posso usarla! C'é un altro metodo?!

ndakota
05-03-2012, 18:36
1) E' buona norma aggiungerlo negli argomenti di funzione se non devi modificarli. Così ti proteggi da modifiche accidentali. In ogni caso togliendoli tutti non dovrebbe darti errore, credo al massimo warning.

2) Negli array stile C non c'è modo di sapere la dimensione.

Modo C++ C++(sì, due volte)


vector<string> parole;

// gli metto dentro degli elementi

for(int i = 0; i < parole.size(); i++) {


Modo C++ stile C


const int dim = 5;
char* parole[dim] = { ... };

confronta(parole, dim);

// nella funzione confronta

for(int i = 0; i < dim; i++) {


Modo C++ stile C con variabili globali


const int dim = 5;

// nel main

char* parole[dim] = { ... };

confronta(parole);

// nella funzione confronta

for(int i = 0; i < dim; i++) {


Quindi insomma, non c'è un vero e proprio modo in C. A meno di non crearti una sorta di array dinamico, dove ogni volta che ce n'è bisogno riallochi il vettore con un elemento in più. C'è da sbattersi un attimo.

3) Certo.. Puoi ad esempio scorrere la mail carattere per carattere finchè non becchi l'iniziale della parola(se c'è, almeno sembra essere abbastanza efficiente) e controllare che sia quella. E' un po' intricato ma un buon esercizio ;)

mistergks
06-03-2012, 18:35
Ho provato a fare una versione con input generico... cioè le email le inserisce l'utente..e ho messo una variabile int che riceve la lunghezza dell'array email.
Ho compilato ed eseguito...mi fa inserire le email ma appena premo INVIO mi crasha e smette di funzionare terminandosi.
Cos'è che non va?!
Se può servire...ho compilato con windows..




#include <iostream>
#include <cstring>
using namespace std;

int confronta(char *email[], char *parole[], int size);

int main(){
int numero_email=0;
char *email[20];
char *parole[]={"amore","tesoro","cucciolotto", "trottolino"};
int size=0;
cout<<"inserisci le emails: "<<endl;
cin.getline(*email,20);
size=strlen(*email);

numero_email=confronta(email,parole,size);
cout<<"Il numero delle email sospette e':"<<numero_email<<endl;

system("pause");
return 0;
}

int confronta(char *email[], char *parole[], int size){
int conta=0;
for(int i=0; i < size; i++){
for(int j=0; j < size; j++){
if(strstr(email[i], parole[j]))
conta++;
}
}
return conta;
}

rootshooter
07-03-2012, 10:21
Ho provato a fare una versione con input generico... cioè le email le inserisce l'utente..e ho messo una variabile int che riceve la lunghezza dell'array email.
Ho compilato ed eseguito...mi fa inserire le email ma appena premo INVIO mi crasha e smette di funzionare terminandosi.
Cos'è che non va?!
Se può servire...ho compilato con windows..




#include <iostream>
#include <cstring>
using namespace std;

int confronta(char *email[], char *parole[], int size);

int main(){
int numero_email=0;
char *email[20];
char *parole[]={"amore","tesoro","cucciolotto", "trottolino"};
int size=0;
cout<<"inserisci le emails: "<<endl;
cin.getline(*email,20);
size=strlen(*email);

numero_email=confronta(email,parole,size);
cout<<"Il numero delle email sospette e':"<<numero_email<<endl;

system("pause");
return 0;
}

int confronta(char *email[], char *parole[], int size){
int conta=0;
for(int i=0; i < size; i++){
for(int j=0; j < size; j++){
if(strstr(email[i], parole[j]))
conta++;
}
}
return conta;
}


Stai iterando parole[] con la stessa dimensione di email[] ?

mistergks
07-03-2012, 18:38
Stai iterando parole[] con la stessa dimensione di email[] ?

E' vero...ma anche correggendo:

int confronta(char *email[], char *parole[], int size){
int conta=0;
for(int i=0; i < size; i++){
for(int j=0; j < 4; j++){
if(strstr(email[i], parole[j]))
conta++;
}
}
return conta;
}


la situazione non cambia!!

[Kendall]
08-03-2012, 09:04
Le sfaccettature dei metodi di i/o sono davvero molte, però non mi sembra proprio corretto l'utilizzo che fai delle stringhe stile c per immettere le email. Una stringa stile c altro non è che un array di char che termina con un carattere NULL ('\0'). La si può pertanto utilizzare con un puntatore char al primo elemento di tale array (il nome di un array, d'altro canto, altro non è che un puntatore al primo elemento dell'array). Tu dichiari una serie di puntatori:

char *mail[20];

per la precisione 20 puntatori a stringhe stile c che però non inizializzi!
Un puntatore char non è una stringa, se non viene inizializzato, cioè se ad esso non viene assegnata un'area di memoria contenente per l'appunto una stringa null-termined.
Per esempio:

const char *parola = "questo è un literal!";

altro non fa che definire un literal (una stringa tra doppie virgole) assegnandoli un'area di memoria, quindi tale area viene fatta puntare dal puntatore parola (che punterà il primo carattere della stringa/array così generato).

Tornando al tuo esempio, se devi inserire delle stringhe a runtime (inserendole da tastiera) o utilizzi la classe delle librerie standard "string" che gestisce l'allocazione di memoria da sè, oppure allochi tu staticamente della memoria per le stringhe che andrai ad inserire. Mettiamo per esempio che vuoi gestire un massimo di 5 mail contenente ognuna un massimo di 200 caratteri. Allora dovrai scrivere così:

char mail[5][200];
for (int i = 0; i < 5; i++) {
cin.getline(mail[i],200);
}


e dopo confrontare le stringhe puntando di volta in volta all'iesima posizione dell'array: array[i].

mistergks
08-03-2012, 10:50
;37059441']Le sfaccettature dei metodi di i/o sono davvero molte, però non mi sembra proprio corretto l'utilizzo che fai delle stringhe stile c per immettere le email. Una stringa stile c altro non è che un array di char che termina con un carattere NULL ('\0'). La si può pertanto utilizzare con un puntatore char al primo elemento di tale array (il nome di un array, d'altro canto, altro non è che un puntatore al primo elemento dell'array). Tu dichiari una serie di puntatori:

char *mail[20];

per la precisione 20 puntatori a stringhe stile c che però non inizializzi!
Un puntatore char non è una stringa, se non viene inizializzato, cioè se ad esso non viene assegnata un'area di memoria contenente per l'appunto una stringa null-termined.
Per esempio:

const char *parola = "questo è un literal!";

altro non fa che definire un literal (una stringa tra doppie virgole) assegnandoli un'area di memoria, quindi tale area viene fatta puntare dal puntatore parola (che punterà il primo carattere della stringa/array così generato).

Tornando al tuo esempio, se devi inserire delle stringhe a runtime (inserendole da tastiera) o utilizzi la classe delle librerie standard "string" che gestisce l'allocazione di memoria da sè, oppure allochi tu staticamente della memoria per le stringhe che andrai ad inserire. Mettiamo per esempio che vuoi gestire un massimo di 5 mail contenente ognuna un massimo di 200 caratteri. Allora dovrai scrivere così:

char mail[5][200];
for (int i = 0; i < 5; i++) {
cin.getline(mail[i],200);
}


e dopo confrontare le stringhe puntando di volta in volta all'iesima posizione dell'array: array[i].

Forse mi sono un pò perso! Vuoi dire che sbaglio proprio la struttura dati?! O meglio non la sbaglio..ma andrebbe inizializzata oppure non usata proprio..vero?
Ma quello che hai proposto tu non è una matrice di char?! non ho ben capito come funziona


Forse intendi una cosa del genere?


#include <iostream>
#include <cstring>
using namespace std;

int confronta(char email[5][200], char *parole[], int size);

int main(){
int numero_email=0;
char email[5][20];
char *parole[]={"amore","tesoro","cucciolotto", "trottolino"};
int size=0;
cout<<"inserisci le emails: "<<endl;
for(int i=0; i<5; i++)
cin.getline(email[i],20);
cout<<"Il numero delle email sospette e':"<<confronta(email,*parole,size)<<endl;

system("pause");
return 0;
}

int confronta(char email[5][200], char *parole[], int size){
int conta=0;
for(int i=0; i < size; i++){
for(int j=0; j < 4; j++){
if(strstr(email[i], parole[j]))
conta++;
}
}
return conta;
}

[Kendall]
08-03-2012, 11:56
Forse mi sono un pò perso! Vuoi dire che sbaglio proprio la struttura dati?! O meglio non la sbaglio..ma andrebbe inizializzata oppure non usata proprio..vero?
Ma quello che hai proposto tu non è una matrice di char?! non ho ben capito come funziona


Quello che intendevo è che sbagliavi proprio ad utilizzare i puntatori che avrebbero contenuto le stringhe delle email, in quanto non facevi loro puntare ad alcuna area di memoria allocata.
Il puntatore non è un contenitore di variabili, array od oggetti, è solo l'indirizzo di un'area della memoria. Una volta dichiarato un puntatore (nel tuo caso un array di puntatori a char, cioè "char *email[5]"), se esso non viene inizializzato ad un area di memoria del giusto tipo punterà ad un area non ben definita (tanto che è sempre prudente inizializzare un puntare a NULL se non si usa subito).
Successivamente, a parte l'erroneo uso del cin.getline(...), cerchi di inserire qualcosa dentro l'area puntata da questo puntatore, che però ripeto non è idonea a contenere una stringa (essendo un'area a "caso")! In queste situazioni salta fuori spesso e volentieri (e credo sia il tuo caso) un errore di "segmentation fault", che sopraggiunge per l'appunto quando si tenta di scrivere in un area non idonea, o sulla quale non si hanno permessi.

Nel mio caso, impiegando un array di char, la memoria viene allocata e pertanto il cin.getline(...) va a scrivere su un'area esistente ed idonea.

Credo comunque che se sei all'inizio dell'apprendimento del c++ parlare di puntatori a char, allocamento di memoria e quant'altro sia parecchio arduo, ti consiglio pertanto di utilizzare (finchè non avrai fatto tuoi i concetti dei puntatori e dell'allocamento statico o dinamico di memoria) invece che le stringhe stile c le più "prudenti" stringhe c++. Ti basta includere l'header <string> e istanziare un array di stringhe come una qualsiasi altra variabile:


string email[MaxEmailNumber];

e lì farci tutti i lavori del caso. Tra l'altro ci sono, se guardi nella documentazione online, metodi specifici per confrontare tra loro le stringhe, cosa che fa al caso tuo.

mistergks
08-03-2012, 12:39
;37060749']Quello che intendevo è che sbagliavi proprio ad utilizzare i puntatori che avrebbero contenuto le stringhe delle email, in quanto non facevi loro puntare ad alcuna area di memoria allocata.
Il puntatore non è un contenitore di variabili, array od oggetti, è solo l'indirizzo di un'area della memoria. Una volta dichiarato un puntatore (nel tuo caso un array di puntatori a char, cioè "char *email[5]"), se esso non viene inizializzato ad un area di memoria del giusto tipo punterà ad un area non ben definita (tanto che è sempre prudente inizializzare un puntare a NULL se non si usa subito).
Successivamente, a parte l'erroneo uso del cin.getline(...), cerchi di inserire qualcosa dentro l'area puntata da questo puntatore, che però ripeto non è idonea a contenere una stringa (essendo un'area a "caso")! In queste situazioni salta fuori spesso e volentieri (e credo sia il tuo caso) un errore di "segmentation fault", che sopraggiunge per l'appunto quando si tenta di scrivere in un area non idonea, o sulla quale non si hanno permessi.

Nel mio caso, impiegando un array di char, la memoria viene allocata e pertanto il cin.getline(...) va a scrivere su un'area esistente ed idonea.

Credo comunque che se sei all'inizio dell'apprendimento del c++ parlare di puntatori a char, allocamento di memoria e quant'altro sia parecchio arduo, ti consiglio pertanto di utilizzare (finchè non avrai fatto tuoi i concetti dei puntatori e dell'allocamento statico o dinamico di memoria) invece che le stringhe stile c le più "prudenti" stringhe c++. Ti basta includere l'header <string> e istanziare un array di stringhe come una qualsiasi altra variabile:


string email[MaxEmailNumber];

e lì farci tutti i lavori del caso. Tra l'altro ci sono, se guardi nella documentazione online, metodi specifici per confrontare tra loro le stringhe, cosa che fa al caso tuo.

e se invece inizializzo char *email[5]={NULL,NULL,NULL,NULL,NULL}; ?!?
Purtroppo non posso usare <string> ...lo so che sarebbe molto piu' semplice...ma sto preparando un esame di fondamenti...quindi posso usare solo i char!

[Kendall]
08-03-2012, 13:20
e se invece inizializzo char *email[5]={NULL,NULL,NULL,NULL,NULL}; ?!?
Purtroppo non posso usare <string> ...lo so che sarebbe molto piu' semplice...ma sto preparando un esame di fondamenti...quindi posso usare solo i char!

No, così non fai altro che far puntare i cinque puntatori all'indirizzo NULL (o zero che dir si voglia), ma non istanzi nessuna area di memoria (se non quella che contiene i puntatori stessi, che sono però tutt'altra cosa rispetto a quella che vorresti contenesse le stringhe).
Non capisco perchè tu non voglia usare la forma:

char email[5][200];

edit: ancor meglio nella forma:

char email[5][200] = {"\0","\0","\0","\0","\0"};

così inizializzi i 5 array con delle stringhe vuote in stile c;

mistergks
08-03-2012, 15:58
Ma non capisco: sarebbe una matrice di char con 5 righe e 200 colonne vero? Se non è cosi potresti "disegnarmela" piú o meno!??


In generale é sempre equivalente al modo che volevo usare io? Quindi se ogni volta che vorrei usare gli array di puntatori uso questo modo non sbaglio?
Un 'ultima cosa..per accedere e fare i controlli? Non cambia? Sempre con due for




Inviato dal mio GT-I9003 usando Tapatalk

[Kendall]
08-03-2012, 16:59
Ma non capisco: sarebbe una matrice di char con 5 righe e 200 colonne vero? Se non è cosi potresti "disegnarmela" piú o meno!??


In generale é sempre equivalente al modo che volevo usare io? Quindi se ogni volta che vorrei usare gli array di puntatori uso questo modo non sbaglio?
Un 'ultima cosa..per accedere e fare i controlli? Non cambia? Sempre con due for




Inviato dal mio GT-I9003 usando Tapatalk

Il fatto è che il modo che volevi usare tu (nella seconda versione, quella in cui inserivi tu manualmente le stringhe) è errato, quindi no, non sono equivalenti.
Comunque si, è una matrice 5x200, 5 righe da 200 char l'unca (che nel tuo caso starebbe a significare 5 stringhe da 200 caratteri massimo). Il fatto è che tu la singola riga, che la richiami tramite la sintassi "array[i]" (senza il secondo blocco di parentesi quadre) puoi benissimo darla "in pasto" al cin.getline(...), in quanto la sintassi array[i] è assimilabile ad un puntatore (per la precisione è il puntatore al blocco iesimo di 200 char). Se per esempio tu fai questo:

char emails[5][200] = {"pinco","pallino","pluto","pippo","topolino"};
char *stringa1 = emails[0];
char *stringa2 = emails[1];

cout << stringa1 << std::endl << stringa2 << std::endl;

E' una sintassi valida, e avrà come risultato la rappresentazione a schermo delle stringhe "pinco" e "pallino".

Per quanto concerne i controlli si, quello non cambio, nel primo scorri le stringhe email, nel secondo scorri le parole da confrontare.

mistergks
09-03-2012, 11:13
;37063038']

char emails[5][200] = {"pinco","pallino","pluto","pippo","topolino"};
char *stringa1 = emails[0];
char *stringa2 = emails[1];

cout << stringa1 << std::endl << stringa2 << std::endl;



con questa sintassi però se io volessi la strlen() come avevo fatto col metodo precedente?
cioè la bastava fare int size=strlen(*email); e mi metteva la lunghezza del char *email[] all'interno di size vero?
Per caso potresti mostrarmi il codice corretto con questo tuo metodo? cioè con il char email[5][200]? Però deve essere generica...cioè con un input inserito dall'utente..

[Kendall]
09-03-2012, 14:07
con questa sintassi però se io volessi la strlen() come avevo fatto col metodo precedente?
cioè la bastava fare int size=strlen(*email); e mi metteva la lunghezza del char *email[] all'interno di size vero?
Per caso potresti mostrarmi il codice corretto con questo tuo metodo? cioè con il char email[5][200]? Però deve essere generica...cioè con un input inserito dall'utente..

Aspetta, secondo me stai facendo un po' di confusione:

char *email[20]

(20 è il valore che hai specificato tu nella tua versione) non è una stringa, è un vettore di 20 puntatori a char, ergo email, nel tuo caso, è un potenziale array di stringhe stile c (dico potenziale perchè quei puntatori diventano stringhe char solo se li fai per l'appunto puntare ad una stringa stile c).

Detto questo, come ti ho detto, email[0], email[1], email[2], email[3] e email[4] sono 4 puntatori a char a tutti gli effetti, quindi possono risiedere senza alcun problema nella chiamata di funzione size = strlen(email[i])

mistergks
09-03-2012, 17:30
;37069264']Aspetta, secondo me stai facendo un po' di confusione:

char *email[20]

(20 è il valore che hai specificato tu nella tua versione) non è una stringa, è un vettore di 20 puntatori a char, ergo email, nel tuo caso, è un potenziale array di stringhe stile c (dico potenziale perchè quei puntatori diventano stringhe char solo se li fai per l'appunto puntare ad una stringa stile c).

Detto questo, come ti ho detto, email[0], email[1], email[2], email[3] e email[4] sono 4 puntatori a char a tutti gli effetti, quindi possono risiedere senza alcun problema nella chiamata di funzione size = strlen(email[i])

Bene..e qua ci siamo..
Quindi se voglio acquisire da input delle frasi dove le memorizzo? Cioe gli array di puntatori vanno dichiarati e inizializzati..a me serve una cosa del tipo :
L' utente inserisce tre frasi e devo farci delle operazioni..molto simile all esercizio delle email..in questo caso l utente inserisce le email! Io non posso inizializzare niente!
Cioe..se devo acquisire da input una parola uso un normale char a[] o char *a e leggo con cin.getline() , mentre per le frasi? Oltre ad acquisirla come unica stringa..perche per lavorarci parola per parola andrebbe divisa con strtok()

mistergks
12-03-2012, 17:25
Utilizzando una matrice di char...trovo problemi nell'effettuare operazioni..ad esempio la funzione confronta:
siccome la strstr(char,char) non ammette matrici(credo)...ho utilizzato l'operatore == ma non funziona.
Qual'è il modo per verificare che nelle email (matrice di char) siano presenti quelle parole?



#include <iostream>
#include <cstring>
using namespace std;

int confronta(char email[][100], const char *parole[]);

int main(){
int numero_email=0;
char email[100][100];
const char *parole[4]={"amore","tesoro","cucciolotto", "trottolino"};
numero_email=confronta(email,parole);
cout<<"Il numero delle email sospette e':"<<numero_email<<endl;


system("pause");
return 0;
}

int confronta(char email[][100], const char *parole[]){
int conta=0;
for(int i=0; i < 100; i++){
for(int j=0; 100; j++){
for(int k=0; k<3; k++){
if(email[i][j]==parole[k])
conta++;
}
}
}
return conta;
}

mistergks
12-03-2012, 22:07
up..

Inviato dal mio GT-I9003 usando Tapatalk

rootshooter
12-03-2012, 23:21
parole[k] non è un char, ma è un puntatore a char.

mistergks
12-03-2012, 23:56
parole[k] non è un char, ma è un puntatore a char.

Lo so! Ma il mio dubbio è...come faccio ad accedere a un puntatore a char? o meglio a un array di puntatori? e come faccio ad assegnare da input a un array di puntatori?
esempio...l'utente deve inserire da tastiera 3 parole...come le leggo e memorizzo in un array di puntatori? si separano con la virgola?

e se poi devo accedere per fare controlli e condizioni? Non si accede come in un normale array di char?

[Kendall]
13-03-2012, 07:48
Prima devi allocare della memoria che conterrà le tue parole, poi fai puntare i tuoi puntatori a questi segmenti di memoria e infine utilizzi la tastiera per inserire dei valori. In linguaggio c++ questo si ottiene in questa maniera:

int main (int argc, char* argv[]) {
char* parola = new char[100];
cin.getline(parola, 100);
}

In questo caso ho allocato memoria per un solo puntatore, nel tuo caso basta che crei un ciclo for destinato a far la stessa cosa con tutti i tuoi puntatori char del vettore char* parole[n];

Il tuo metodo di confronto precedentemente usato comunque è errato perchè, perchè nel momento stesso in cui confronti le due stringhe scrivi questo:

email[i][k] == parole[m];

Questo è errato perchè non devi utilizzare l'operatore "==" perchè ti porterebbe a confrontare il valore di un char (char[i][k]) con un indirizzo di memoria (il puntatore parole[m]).
Lì quindi dovrai utilizzare email[i] (questa qui si che è una stringa), parole[m] e qualche funzionalità di confronto della libreria cstring

mistergks
13-03-2012, 09:51
e questo perche non va bene

int main () {
char* parola []= new char[100];
cin.getline(parola, 100);
}


intendi cosi?

int main () {
for(int i=0; i<100;i++ ){
char* parola = new char[100];
cin.getline(parola, 100);
}
}

[Kendall]
13-03-2012, 10:30
e questo perche non va bene

int main () {
char* parola []= new char[100];
cin.getline(parola, 100);
}


intendi cosi?

int main () {
for(int i=0; i<100;i++ ){
char* parola = new char[100];
cin.getline(parola, 100);
}
}


Intendo questo:

int main(int argc, char* argv[]) {
const int wordnum = 10; // numero di parole sospette da memorizzare
const int wordsize = 20; // numero di caratteri massimi per ogni parola
char* parole[wordnum];
for (int i = 0; i < wordnum; i++) {
parole[i] = new char[wordsize];
}
for (int i = 0; i < wordnum; i++) {
cout << "Parola sospetta " << i + 1 << ": ";
cin.get(parole[i], wordsize);
cin.clear();
while (cin.get() != '\n') {
continue;
}
}
return 0;
}


Fare sempre attenzione alla memoria allocata con "new". In questo caso viene deallocata non appena si raggiunge la fine del programma, ma solitamente la struttura di un programma non è così semplice quindi appena finisci di impiegare quei puntatori (quindi non appena non ti servono più) dealloca la memoria tramite un delete.

vendettaaaaa
13-03-2012, 10:39
e questo perche non va bene

int main () {
char* parola []= new char[100];
cin.getline(parola, 100);
}


intendi cosi?

int main () {
for(int i=0; i<100;i++ ){
char* parola = new char[100];
cin.getline(parola, 100);
}
}

Così alla fine del ciclo for hai solo una parola e hai riempito un po' di memoria con 99 parole irrecuperabili. Senza contare che nel ciclo non usi i...cosa lo fai a fare?
Secondo me ti conviene lasciar perdere per il momento questo esercizio, lavorare un po' con la STL, scrivere molto codice con vector e altre cose, fare altri esercizi, e capire pian piano meglio il concetto di puntatore, l'utilizzo di new e delete, perchè pian piano ci inciamperai. Io ho fatto così, solo adesso riesco a capire abbastanza bene i puntatori, perchè li ho usati in tanti ambiti diversi, senza incapponirmi su esercizi tipo questo.
Cmq si fa così:
int main () {
char* parole[3];
for (int i = 0; i < 3; ++i) {
char* parola = new char[10];
cin.getline(parola, 10);
parole[i] = parola;
}

for (int i = 0; i < 3; ++i) cout << parole[i] << endl;

return 0;
}
Oppure così:
char** parole;
parole = new char* [3];
for (int i = 0; i < 3; ++i) {
char* parola = new char[10];
cin.getline(parola, 10);
parole[i] = parola;
}

for (int i = 0; i < 3; ++i) cout << parole[i] << endl;

Vorrei farti notare che invece questa cosa:
char* parola;
parola = "ciao";
funziona, mentre
char parola[];
parola = "ciao";
no, e neppure
char parola[100];
parola = "ciao";
Mentre il sopracitato
char* parole[3];
parole[i] = "ciao";
sì. Anche
char* parole[];
parole[i] = "ciao";
non va bene. Se hai Visual Studio guarda gli errori che ti da e prova a capire cosa non va. Se non hai Visual Studio, installalo e guarda.

Cmq sia, fai altro per ora.

[Kendall]
13-03-2012, 11:31
... cut ...

Vorrei farti notare che invece questa cosa:
char* parola;
parola = "ciao";
funziona, mentre
char parola[];
parola = "ciao";
no, e neppure
char parola[100];
parola = "ciao";
Mentre il sopracitato
char* parole[3];
parole[i] = "ciao";
sì. Anche
char* parole[];
parole[i] = "ciao";
non va bene. Se hai Visual Studio guarda gli errori che ti da e prova a capire cosa non va. Se non hai Visual Studio, installalo e guarda.

Cmq sia, fai altro per ora.

Tutto giustissimo vendettaaaaa, però forse è meglio spiegargli un pochino (nel senso che non uso Visual Studio perchè programmo in QT solitamente, quindi non conosco il compilatore da lui utilizzato, però solitamente i compilatori in questo caso generano semplicemente un problema di impossibilità di cast, o tipo non compatibile, che magari per un novizio non è sempre ben comprensibile. Il consiglio di sbatterci la testa è ovviamente giustissimo, però è meglio far chiarezza anche su cosa è un literal e cos'è il "nome" di array.

Quando si scrive una cosa tipo:
"Questa è una stringa!"
si scrive un literal, cioè si alloca della memoria, e in particolare un array di caratteri costanti (nel senso che poi quella memoria lì non potrai andare a modificarla, ma potrai solo leggerla per quel che è). Da questo deriva il fatto che è solitamente si vada a memorizzare un listeral in un puntatore a const char, in questa maniera:
const char * frase = "Questa è una stringa!";
ll compilatore alloca della memoria per la stringa, la salva al suo interno, e poi passa al puntatore l'indirizzo del primo carattere (nel nostro caso l'indirizzo di quel const char 'Q');
Come è stato detto il nome di un array altro non è che un puntatore al suo primo carattere, cosa che farebbe pensare che sia la medesima cosa del const char * frase utilizzato sopra. In realtà così non è, perchè il nome di un array è un puntatore costante a char, cioè è un puntatore che punta sempre e solo allo stesso indirizzo in memoria. Tentando quindi questa assegnazione:
char frase1[100];
frase1 = "Questa è una stringa!";
E' un errore, in quanto si cerca di modificare l'indirizzo al quale frase1 punta (il primo carattere di quell'array di 100 char) con l'indirizzo della memoria allocata per il literal.
Ultima cosa, questa assegnazione è corretta:
char frase1[100] = "Questa è una stringa!";
In quanto in questo caso è una inizializzazione e l'array non viene fatto puntare ad un altro indirizzo di memoria, ma il contenuto della stringa viene direttamente copiato nei primi 22 caratteri dell'array (21 + il carattere '\n').

Comunque concordo con vendettaaaaa, credo che ora sia meglio se ti dedichi ad altro e solo quando avrai approfondito i puntatori e tutto quello che ci sta attorno torni a guardare simili argomenti.

vendettaaaaa
13-03-2012, 12:01
;37091273']Tutto giustissimo vendettaaaaa, però forse è meglio spiegargli un pochino (nel senso che non uso Visual Studio perchè programmo in QT solitamente, quindi non conosco il compilatore da lui utilizzato, però solitamente i compilatori in questo caso generano semplicemente un problema di impossibilità di cast, o tipo non compatibile, che magari per un novizio non è sempre ben comprensibile. Il consiglio di sbatterci la testa è ovviamente giustissimo, però è meglio far chiarezza anche su cosa è un literal e cos'è il "nome" di array.

Quando si scrive una cosa tipo:
"Questa è una stringa!"
si scrive un literal, cioè si alloca della memoria, e in particolare un array di caratteri costanti (nel senso che poi quella memoria lì non potrai andare a modificarla, ma potrai solo leggerla per quel che è). Da questo deriva il fatto che è solitamente si vada a memorizzare un listeral in un puntatore a const char, in questa maniera:

ll compilatore alloca della memoria per la stringa, la salva al suo interno, e poi passa al puntatore l'indirizzo del primo carattere (nel nostro caso l'indirizzo di quel const char 'Q');
Come è stato detto il nome di un array altro non è che un puntatore al suo primo carattere, cosa che farebbe pensare che sia la medesima cosa del const char * frase utilizzato sopra. In realtà così non è, perchè il nome di un array è un puntatore costante a char, cioè è un puntatore che punta sempre e solo allo stesso indirizzo in memoria. Tentando quindi questa assegnazione:
char frase1[100];
frase1 = "Questa è una stringa!";
E' un errore, in quanto si cerca di modificare l'indirizzo al quale frase1 punta (il primo carattere di quell'array di 100 char) con l'indirizzo della memoria allocata per il literal.
Ultima cosa, questa assegnazione è corretta:
char frase1[100] = "Questa è una stringa!";
In quanto in questo caso è una inizializzazione e l'array non viene fatto puntare ad un altro indirizzo di memoria, ma il contenuto della stringa viene direttamente copiato nei primi 22 caratteri dell'array (21 + il carattere '\n').

Comunque concordo con vendettaaaaa, credo che ora sia meglio se ti dedichi ad altro e solo quando avrai approfondito i puntatori e tutto quello che ci sta attorno torni a guardare simili argomenti.
Hmm ottimo. Come ho detto, inizio solo ora a comprendere queste cose, ed infatti sapevo che
char frase1[100];
frase1 = "Questa è una stringa!";
non è corretto, ma non avevo presente che
char frase1[100]
è in realtà un
const char* frase
visto che ho sempre lavorato con string e vector...ecco perchè non si può assegnare una stringa nella seconda linea di codice, ma si può invece modificare il contenuto di un eventuale
char frase1[100] = "Questa è una stringa!";
scrivendo
frase1[0] = 'q';

Bello continuare ad imparare :cool:

p.s.: posso tenerti presente quando ho qualche dubbio usando le Qt? Magari contattandoti via pm.

[Kendall]
13-03-2012, 12:15
Hmm ottimo. Come ho detto, inizio solo ora a comprendere queste cose, ed infatti sapevo che
....

cut

...
Bello continuare ad imparare :cool:

p.s.: posso tenerti presente quando ho qualche dubbio usando le Qt? Magari contattandoti via pm.

Figurati, per quel che posso aiutare lo faccio volentieri, quindi se ti serve una mano nessun problema. ;)
Solo una piccola correzione a quel che hai scritto:

in
char frase[100];
il nome frase è un char * cost (cioè un puntatore costante a char), non un const char * (che è invece un puntatore ad un char costante). La differenza è che nel primo caso io posso modificare il valore dei char dell'array ma non posso far puntare il nome frase ad un altro char, mentre nel secondo caso non posso modificare i char puntati dal puntatore ma posso modificare l'indirizzo al quale il puntatore, per l'appunto, punta.
Il caso "estremo" è questo:
const char frase[100];
In questo caso il nome frase è di tipo const char * const, così come questo:
const char * const frase2 = "Questa è una stringa";

In questi casi sia l'array che il puntatore devono essere inizializzati subito altrimenti non potrai più farlo successivamente!

vendettaaaaa
13-03-2012, 12:31
;37091587']Figurati, per quel che posso aiutare lo faccio volentieri, quindi se ti serve una mano nessun problema. ;)
Solo una piccola correzione a quel che hai scritto:

in
char frase[100];
il nome frase è un char * cost (cioè un puntatore costante a char), non un const char * (che è invece un puntatore ad un char costante). La differenza è che nel primo caso io posso modificare il valore dei char dell'array ma non posso far puntare il nome frase ad un altro char, mentre nel secondo caso non posso modificare i char puntati dal puntatore ma posso modificare l'indirizzo al quale il puntatore, per l'appunto, punta.
Il caso "estremo" è questo:
const char frase[100];
In questo caso il nome frase è di tipo const char * const, così come questo:
const char * const frase2 = "Questa è una stringa";

In questi casi sia l'array che il puntatore devono essere inizializzati subito altrimenti non potrai più farlo successivamente!
Uhm questo mi confonde un po'...pensavo che const rendesse costante il type che segue, quindi immaginavo una cosa così:
const char* == const (char*)
invece mi dici che
const char* == (const char)*

Altra cosa che mi confonde è che nelle classi si possono dichiarare funzioni const con sintassi
(return type) nomefunz() const
e in questo caso scrivere
char* const frase
mi ha fatto pensare a "frase è un puntatore a caratteri non modificabili", invece è il contrario...

Questa sintassi è ereditata dal C? Non vedo perchè dare a const, nel C++, lo stesso significato sintattico nonostante l'inversione della posizione...

[Kendall]
13-03-2012, 12:52
Diciamo che il c++ non è un linguaggio propriamente semplice e in alcuni frangenti è facile confondersi. In realtà la keyword const assume diverse sfaccettature come hai visto.
Ti confermo quanto segue:

Variabile di tipo int:
int intero;

Costante di tipo intero:
const int intero;

Puntatore a variabile intero:
int * punt;

Puntatore a costante intero:
const int * punt;

Puntatore costante a variabile intero:
int * const punt;

Puntatore costante a costante intero:
const int * const punt;

Per quanto riguarda le funzioni membro const, in questo caso come hai notato viene utilizzato la keyword const come postfisso per indicare che quella funzione non andrà ad alterare l'oggetto per il quale è invocata (quindi il concetto è diverso rispetto ad entrambi i significati spiegati prima). Bisogna solo ricordarsi di "leggere" correttamente il contesto per il quale una keyword è usata.

Ecco un link che ti rispiega il tutto con qualche esempio corredato: http://www.possibility.com/Cpp/const.html
E' il primo che ho trovato e con una scorsa veloce mi sembra che non riporti scorrettezze, ma ti basta una ricerca generale e ne troverai molti altri di link simili.

vendettaaaaa
13-03-2012, 13:55
;37091867']Diciamo che il c++ non è un linguaggio propriamente semplice e in alcuni frangenti è facile confondersi. In realtà la keyword const assume diverse sfaccettature come hai visto.
Ti confermo quanto segue:

Variabile di tipo int:
int intero;

Costante di tipo intero:
const int intero;]

Puntatore a variabile intero:
int * punt;
Puntatore a costante intero:
const int * punt;

Puntatore costante a variabile intero:
int * const punt;

Puntatore costante a costante intero:
const int * const punt;

Per quanto riguarda le funzioni membro const, in questo caso come hai notato viene utilizzato la keyword const come postfisso per indicare che quella funzione non andrà ad alterare l'oggetto per il quale è invocata (quindi il concetto è diverso rispetto ad entrambi i significati spiegati prima). Bisogna solo ricordarsi di "leggere" correttamente il contesto per il quale una keyword è usata.

Ecco un link che ti rispiega il tutto con qualche esempio corredato: http://www.possibility.com/Cpp/const.html
E' il primo che ho trovato e con una scorsa veloce mi sembra che non riporti scorrettezze, ma ti basta una ricerca generale e ne troverai molti altri di link simili.
Molto interessante, grazie :D

rootshooter
13-03-2012, 14:32
Complimenti per la chiarezza e la pertinenza degli esempi. Molto utile

mistergks
14-03-2012, 14:23
tutto interessante..pero la risposta alla mia domanda non la trovo esplicitamente!
essendo limitato nell usare strutture dati ecc..
per memorizzare tante parole da input e poi accedervi per fare controlli puo andar bene un array di puntatori?
tipo cosi:

char *dizionario[100];
cin.getline(dizionario,100);

[Kendall]
14-03-2012, 15:40
tutto interessante..pero la risposta alla mia domanda non la trovo esplicitamente!
essendo limitato nell usare strutture dati ecc..
per memorizzare tante parole da input e poi accedervi per fare controlli puo andar bene un array di puntatori?
tipo cosi:

char *dizionario[100];
cin.getline(dizionario,100);


:eh: Non demordi eh... Nelle scorse pagine hai ricevuto la risposta molteplici volte quindi ti consiglio di rileggerle. E ripeto, quella forma lì è totalmente sbagliata perchè per prima cosa dizionario non è un puntatore a char ma un puntatore a puntatori char e quindi in quella chiamata non può starci, non senza un indice tra parentesi quadre che specifichi quale di quei 100 puntatori vuoi utilizzare, e in secondo luogo utilizzi quel 100 dentro alla chiamata, che dovrebbero i caratteri massimi letti, ma in realtà par quasi che tu sia convinto che ci sia un legame tra i due 100 sopra scritti (cosa che invece non è vera).
Però davvero non ha senso che continui a fare la stessa domanda senza tentare almeno di rileggerti quello che già ti è stato scritto).

Ps: non lo sto dicendo con cattiveria, davvero, ma devi un po' sbatterci la testa su queste cose, altrimenti farai davvero molta molta fatica nel mondo della programmazione.

rootshooter
14-03-2012, 19:55
tutto interessante..pero la risposta alla mia domanda non la trovo esplicitamente!
essendo limitato nell usare strutture dati ecc..
per memorizzare tante parole da input e poi accedervi per fare controlli puo andar bene un array di puntatori?
tipo cosi:

char *dizionario[100];
cin.getline(dizionario,100);


Vuoi il codice scritto per fare copia e incolla? Qui ti hanno spiegato di tutto e di più. E ti hanno anche consigliato su cosa concentrarti per farti le basi di C.

Detto questo, ti devi concentrare sul problema. Vuoi che l'utente immetta delle parole... Quali funzioni ho disponibili per prendere testo in ingresso da terminale? Bene, in questo caso getline(). Che parametri accetta? mmm, andiamo a cercare:

http://www.cplusplus.com/reference/iostream/istream/getline/

Adesso, vediamo che è previsto un puntatore a char. *(nota a pie' di pagina)

Ho padronanza con i puntatori? No? E allora me li studio, mi ci esercito, e per ora mi limito a riuscire a memorizzare e stampare le parole immesse dall'utente.

Successivamente mi concentro sul confronto, e dato che adesso dovrebbe essermi chiaro come sono memorizzate le stringhe nel mio programma, dovrei facilmente implementare il confronto.
Se mi accorgo di dover cambiare la struttura dati per avere un più facile confronto, torno al punto precedente, modifico e vado di nuovo avanti.


* Nota: una volta studiati i puntatori dovrebbe essere chiaro perché quella funzione prevede un puntatore. E la relazione che c'è tra puntatore e vettore.