Problema con funzione tolower
Ho un problema riguardo all'utilizzo della funzione tolower quando tratto i puntatori.
Ad esempio se ho una situazione del genere:
supponiamo che voglio che l'elemento i del vettore sia riconosciuto in lettera minuscola:
ma poi quando eseguo il programma mi da problemi.
Ad esempio se ho una situazione del genere:
char *array[]={"M","V","T","M","G"};
supponiamo che voglio che l'elemento i del vettore sia riconosciuto in lettera minuscola:
*array[i]=tolower(*array[i])
ma poi quando eseguo il programma mi da problemi.
Risposte
tolower() funziona, quello che non puoi fare è assegnare il risultato ad *array.
Il tipo di "M" è const char *, quindi "array" è un array di stringhe costanti. Tu lo assegni ad "array", che un array di stringhe non costanti, e tenti di modificare le stringhe. Questo ha comportamento indefinito.
Dovresti assegnare ad "array" delle stringhe allocate dinamicamente e copiarci le singole stringhe usando strcpy(). Oppure puoi usare un array di stringhe di lunghezza fissata. Qualcosa del genere:
(se non ho fatto confusione con gli indici). A questo punto dovresti poter fare
Il tipo di "M" è const char *, quindi "array" è un array di stringhe costanti. Tu lo assegni ad "array", che un array di stringhe non costanti, e tenti di modificare le stringhe. Questo ha comportamento indefinito.
Dovresti assegnare ad "array" delle stringhe allocate dinamicamente e copiarci le singole stringhe usando strcpy(). Oppure puoi usare un array di stringhe di lunghezza fissata. Qualcosa del genere:
char array[2][5]; strcpy("M", array[0]); strcpy("V", array[1]); strcpy("T", array[2]); strcpy("M", array[3]); strcpy("G", array[4]);
(se non ho fatto confusione con gli indici). A questo punto dovresti poter fare
*array[i]=tolower(*array[i])
Ricordiamo che tolower accetta come parametro un intero (il carattere), non una stringa (puntatore)
http://www.cplusplus.com/reference/clibrary/cctype/tolower/
http://www.cplusplus.com/reference/clibrary/cctype/tolower/
quindi dovrei scrivere
Il primo consiglio non l'ho capito tanto.
Perchè copiare array in "M" ha senso?
e poi "M" non è è *array[0] ?
c=*array[i]; c=tolower(*array[i]);?
Il primo consiglio non l'ho capito tanto.
Perchè copiare array in "M" ha senso?
e poi "M" non è è *array[0] ?
In effetti avevo fatto confusione con gli indici, inoltre ho invertito gli argomenti di strcpy(). Questo funziona:
Adesso "array" è un array di array non costante, non inizializzato. Ci copi dentro le stringhe "M", "V", ... poi puoi modificare i caratteri delle stringhe di "array". Prima non potevi, perché "array" conteneva puntatori alle costanti letterali "M", "V", ... Le costanti letterali sono ovviamente costanti.
@nessuno.nobody
*array è un char, non un puntatore. array è un puntatore all'i-esima stringa, dereferenziandolo con *array si ottiene il primo carattere.
// char *array[]={"M","V","T","M","G"}; char array[5][2]; strcpy(array[0], "M"); strcpy(array[1], "V"); strcpy(array[2], "T"); strcpy(array[3], "M"); strcpy(array[4], "G"); for (int i = 0; i < 5; ++i) { *array[i]=tolower(*array[i]); printf("%s\n", array[i]); }
Adesso "array" è un array di array non costante, non inizializzato. Ci copi dentro le stringhe "M", "V", ... poi puoi modificare i caratteri delle stringhe di "array". Prima non potevi, perché "array" conteneva puntatori alle costanti letterali "M", "V", ... Le costanti letterali sono ovviamente costanti.
@nessuno.nobody
*array è un char, non un puntatore. array è un puntatore all'i-esima stringa, dereferenziandolo con *array si ottiene il primo carattere.
@claudio86: certamente! Intendevo solo ricordarlo a nadia89 in quanto si può fare confusione

"nessuno.nobody":
@claudio86: certamente! Intendevo solo ricordarlo a nadia89 in quanto si può fare confusione
Questo è poco ma sicuro. La prima cosa che ho fatto quando ho letto il primo messaggio è stato andare a vedere cosa faceva tolower(). Non avevo invece controllato per strcpy() (e si è visto

ma *array[0] è "M"?
poi per velocizzare un pò il codice senza scrivere tutta quella lista posso utilizzare :
così poi posso modificare p?o comunque se ho sbagliato qualcosa cercare di velocizzarlo con questo ragionamento?
poi per velocizzare un pò il codice senza scrivere tutta quella lista posso utilizzare :
char *p; strcpy(p,array[i]);
così poi posso modificare p?o comunque se ho sbagliato qualcosa cercare di velocizzarlo con questo ragionamento?
*array[0] è 'M', non "M". La differenza sembra sottile ma non lo è: il primo è un carattere, il secondo è un array di due caratteri, 'M' e lo zero finale.
"M" è un altro modo di scrivere {'M', 0}, e "Mamma" di scrivere {'M', 'a', 'm', 'm', 'a', 0}.
D'ora in poi la variabile "array" la chiamo "kappa", per evitare fraintendimenti, e per lo stesso motivo invece di "M" ci scriviamo dentro "Mamma".
kappa è un array di array di char.
kappa[0] è il primo elemento di kappa, ed è un array di char che vale "Mamma". Un array decade nel puntatore al suo primo elemento in molti casi. Ad esempio quando applichi l'operatore * ad un array.
*kappa[0]: qui kappa[0] decade nel puntatore al primo elemento di kappa[0]. Se kappa[0] == "Mamma" allora decade nel puntatore alla lettera 'M'. Applicando l'operatore * ottieni il valore puntato, quindi il risultato è 'M'. Non è una stringa, è un singolo carattere.
Quando nel codice tu scrivi "Mamma" (con le virgolette) stai scrivendo una costante letterale di tipo stringa (const char [N]). Essendo una costante non puoi modificarla (quello che potrebbe succedere infatti è che il compilatore la mette in un area di memoria in sola lettura). Quindi non puoi fare
Se tu dichiari kappa come avevi fatto all'inizio:
Qui "Mamma" e "Papa" decadono nei puntatori ai loro primi elementi, quindi kappa è un array di puntatori a stringhe. Quindi kappa[0] è un puntatore a "Mamma", che è costante. Quindi non puoi modificarlo:
In realtà non è un errore, ma un comportamento indefinito, che è peggio. Principalmente significa che il compilatore non se ne accorge e causerà problemi casualmente quando lo esegui (cioè non sempre e non sempre gli stessi problemi).
Innanzitutto devi prima inizializzare p con un'area di memoria adatta (es. usando malloc()).
Ora puoi modificare liberamente p (tenendo conto che può contenere al massimo 199 caratteri più lo zero finale). Ma non puoi modificare kappa[0], perché è sempre un puntatore a stringa costante.
Al massimo potresti fare:
"M" è un altro modo di scrivere {'M', 0}, e "Mamma" di scrivere {'M', 'a', 'm', 'm', 'a', 0}.
D'ora in poi la variabile "array" la chiamo "kappa", per evitare fraintendimenti, e per lo stesso motivo invece di "M" ci scriviamo dentro "Mamma".
char *kappa[] = {"Mamma", "Papa"};
kappa è un array di array di char.
kappa[0] è il primo elemento di kappa, ed è un array di char che vale "Mamma". Un array decade nel puntatore al suo primo elemento in molti casi. Ad esempio quando applichi l'operatore * ad un array.
*kappa[0]: qui kappa[0] decade nel puntatore al primo elemento di kappa[0]. Se kappa[0] == "Mamma" allora decade nel puntatore alla lettera 'M'. Applicando l'operatore * ottieni il valore puntato, quindi il risultato è 'M'. Non è una stringa, è un singolo carattere.
Quando nel codice tu scrivi "Mamma" (con le virgolette) stai scrivendo una costante letterale di tipo stringa (const char [N]). Essendo una costante non puoi modificarla (quello che potrebbe succedere infatti è che il compilatore la mette in un area di memoria in sola lettura). Quindi non puoi fare
char * c = "Mamma"; c[3] = 't';
Se tu dichiari kappa come avevi fatto all'inizio:
char *kappa[] = {"Mamma", "Papa"};
Qui "Mamma" e "Papa" decadono nei puntatori ai loro primi elementi, quindi kappa è un array di puntatori a stringhe. Quindi kappa[0] è un puntatore a "Mamma", che è costante. Quindi non puoi modificarlo:
kappa[0][2] = 't'; // Errore *kappa[0] = 't'; // Errore
In realtà non è un errore, ma un comportamento indefinito, che è peggio. Principalmente significa che il compilatore non se ne accorge e causerà problemi casualmente quando lo esegui (cioè non sempre e non sempre gli stessi problemi).
poi per velocizzare un pò il codice senza scrivere tutta quella lista posso utilizzare :
char *p; strcpy(p,array[i]);
così poi posso modificare p?o comunque se ho sbagliato qualcosa cercare di velocizzarlo con questo ragionamento?
Innanzitutto devi prima inizializzare p con un'area di memoria adatta (es. usando malloc()).
char *kappa[]={"Mamma","Papa"}; char * p = malloc(200); strcpy(p, kappa[0]); // Ora p contiene una copia di "Mamma"
Ora puoi modificare liberamente p (tenendo conto che può contenere al massimo 199 caratteri più lo zero finale). Ma non puoi modificare kappa[0], perché è sempre un puntatore a stringa costante.
Al massimo potresti fare:
char *kappa[]={"Mamma","Papa"}; char * p = malloc(200); strcpy(p, kappa[0]); *p = tolower(*p); kappa[0] = p; // Adesso però se modifichi p modifichi anche kappa[0]! // Per convertire in minuscolo anche "Papa" devi allocare altra memoria char * p = malloc(200); strcpy(p, kappa[1]); *p = tolower(*p); kappa[1] = p;
scusami se insisto ma voglio carcare di capire bene visto che ho molte lacune in questo argomento,
ma dicendo kappa[0] è il primo elemento di kappa, vuol dire che kappa[0] punta a "Mamma" oppure al primo carattere 'M'?
e in tal caso kappa[1] quindi sarebbe 'a'?
ma dicendo kappa[0] è il primo elemento di kappa, vuol dire che kappa[0] punta a "Mamma" oppure al primo carattere 'M'?
e in tal caso kappa[1] quindi sarebbe 'a'?
char kappa[4][6];
kappa è un array di array di char. Un elemento di kappa è un array di char. kappa[0] è il primo elemento di kappa, quindi kappa[0] è un array di char. kappa[1] è il secondo elemento di kappa, anche lui è un array di char.
char *kappa[3];
kappa è un array di puntatori a char. Un elemento di kappa è un puntatore a char. kappa[0] è un puntatore a char. A quale char punti non importa, potrebbe essere un char singolo oppure un char appartenente ad un array.
In linea di massima puoi considerare un array come un puntatore al suo primo elemento. È esattamente così che sono implementati dal compilatore: quando definisci un array viene riservata della memoria e nella variabile viene messo l'indirizzo del primo elemento.
Ci sono delle differenze tra array e puntatori (es. non puoi assegnare un valore ad un array, non puoi incrementarlo, l'operatore sizeof() restituisce il numero di elementi), però per l'accesso agli elementi non c'è differenza.
char *kappa[] = {"Mamma", "Papa" }; char **kappap = kappa;
kappa è un array di stringhe, decade in puntatore quando viene assegnato a kappap. kappap punta al primo elemento di kappa, che è la stringa "Mamma".
kappa[0] è un puntatore (al primo elemento di "Mamma", che è il char 'M').
(stringa == array di char)
Diverso sarebbe stato se kappa fosse definito come
char kappa[5][2]; char *kappa0p = kappa[0];
In tal caso kappa[0] sarebbe stato un array di char (una stringa), non un puntatore. E sarebbe decaduto in un puntatore a char quando assegnato a kappa0p, che punterebbe quindi al primo elemento di kappa[0] (qualunque esso sia, 'M' se contiene la stringa "Mamma").
char *kappa[] = {"Mamma", "Papa" }; // kappa[0] Punta al primo elemento di "Mamma" // kappa[1] Punta al primo elemento di "Papa" kappa[0][0] == 'M', *kappa[0] == 'M'; kappa[0][1] == 'a'; kappa[0][2] == 'm'; kappa[0][3] == 'm'; kappa[0][4] == 'a'; kappa[0][5] == 0; kappa[1][0] == 'P', *kappa[1] == 'P'; kappa[1][1] == 'a'; kappa[1][2] == 'p'; kappa[1][3] == 'a'; kappa[1][4] == 0; // Nota che se pippo è un array le due istruzioni sono equivalenti: pippo[0]; *pippo;
Forse il fatto che stiamo usando array di char rende tutto più confuso. Lo stesso discorso vale per array di int, con la differenza che un array di int si deve per forza scrivere con {3,5,6,2}, mentre l'array di char {'a', 'b', 'c', 0} si può anche scrivere "abc".
Dovresti leggere di array e puntatori su un buon libro. Purtroppo di libri di C non ne conosco, forse questo potrebbe andare anche se parla di C++ (limitati ad array e puntatori). Magari qualcun altro ha dei suggerimenti.
Io come libro sul C consiglio sempre: Linguaggio C - Guida alla programmazione, che trovo ottimo (fin dalla prima edizione).
Il libro è adatto anche per un neofita totale al mondo della programmazione, in quanto non si limita a spiegare i costrutti del linguaggio e le particolarità, ma spiega quasi "passo passo" come programmare.
Poi è carino in quanto alla fine di ogni capitolo c'è una sezione di esercizi a verifica delle conoscenze acquisite.
Il libro è adatto anche per un neofita totale al mondo della programmazione, in quanto non si limita a spiegare i costrutti del linguaggio e le particolarità, ma spiega quasi "passo passo" come programmare.
Poi è carino in quanto alla fine di ogni capitolo c'è una sezione di esercizi a verifica delle conoscenze acquisite.
Si ora mi è un pò più chiaro.
L'unica cosa che vorrei chiedere è visto che kappap punta al primo elemento di kappa che è "Mamma" significa che
*kappap="Mamma" quindi kappa="Mamma"?
Cioè visto che *kappa[0]=='M',*kappa[1]=='P', per ottenere "Mamma" come stringa ?
Non so se è per il libro ma stringhe e puntatori è un argomento che non sto riuscendo a "metabolizzare" bene però giustamente se non si capisce bene la teoria ,è difficile fare gli esercizi. Vedrò di trovare qualcosa altrove e capirci meglio.
Ora posto il codice di un esercizio in cui devo trovare la parola maggiore o minore ma ha un carattere indefinito.
L'unica cosa che vorrei chiedere è visto che kappap punta al primo elemento di kappa che è "Mamma" significa che
*kappap="Mamma" quindi kappa="Mamma"?
Cioè visto che *kappa[0]=='M',*kappa[1]=='P', per ottenere "Mamma" come stringa ?
Non so se è per il libro ma stringhe e puntatori è un argomento che non sto riuscendo a "metabolizzare" bene però giustamente se non si capisce bene la teoria ,è difficile fare gli esercizi. Vedrò di trovare qualcosa altrove e capirci meglio.
Ora posto il codice di un esercizio in cui devo trovare la parola maggiore o minore ma ha un carattere indefinito.
#include <stdio.h> #include <stdlib.h> #include <string.h> int main (int argc,char *argv[]) { char *smallest_word; char *largest_word; int i; strcpy(smallest_word,argv[1]); strcpy(largest_word,argv[1]); for (i=2;i<argc;i++) { if(strcmp(argv[i],smallest_word)<0) strcpy(smallest_word,argv[i]); if(strcmp(argv[i],largest_word)>0) strcpy(largest_word,argv[i]); } printf("la parola minore e' %s\n",smallest_word); printf("la parola maggiore e' %s",largest_word); return 0; }
kappa = {"Mamma", "Papa"}
kappa[0] = "Mamma"
kappa[1] = "Papa"
*kappap = "Mamma"
Per ottenere "Mamma" come stringa: kappa[0], oppure *kappa, oppure kappap[0], oppure *kappap.
kappap è uguale a kappa dal punto di vista dell'organizzazione in memoria (come ho detto prima ci sono poche differenze tra array e puntatori).
Stai usando smallest_word e largest_word senza averle inizializzate. Attiva gli avvisi del compilatore, molti problemi si capiscono più in fretta:
Quando dichiari un puntatore (char *smallest_word) stai solo dicendo che quella è una variabile che contiene un indirizzo. Non gli assegni un indirizzo valido.
In questo caso vuoi scrivere a quell'indirizzo una sequenza di caratteri, quindi devi assicurarti che il puntatore punti ad una zona di memoria abbastanza vasta. Con la funzione malloc(N) chiedi al runtime di procurarti una zona di memoria grande N byte, e ti viene restituito il suo indirizzo. Dovrai poi ricordarti di liberare quella memoria con la funzione free(), una volta che non ti servirà più.
In realtà in questo caso avresti potuto usare degli array di caratteri (così eviti di doverti ricordare di liberare la memoria):
kappa[0] = "Mamma"
kappa[1] = "Papa"
*kappap = "Mamma"
Per ottenere "Mamma" come stringa: kappa[0], oppure *kappa, oppure kappap[0], oppure *kappap.
kappap è uguale a kappa dal punto di vista dell'organizzazione in memoria (come ho detto prima ci sono poche differenze tra array e puntatori).
Ora posto il codice di un esercizio in cui devo trovare la parola maggiore o minore ma ha un carattere indefinito.
char *smallest_word; char *largest_word; int i; strcpy(smallest_word,argv[1]); strcpy(largest_word,argv[1]);
Stai usando smallest_word e largest_word senza averle inizializzate. Attiva gli avvisi del compilatore, molti problemi si capiscono più in fretta:
path/to/a.c:11:12: warning: variable 'smallest_word' is uninitialized when used here [-Wuninitialized] strcpy(smallest_word, argv[1]); ^~~~~~~~~~~~~ path/to/a.c:12:12: warning: variable 'largest_word' is uninitialized when used here [-Wuninitialized] strcpy(largest_word, argv[1]); ^~~~~~~~~~~~
Quando dichiari un puntatore (char *smallest_word) stai solo dicendo che quella è una variabile che contiene un indirizzo. Non gli assegni un indirizzo valido.
In questo caso vuoi scrivere a quell'indirizzo una sequenza di caratteri, quindi devi assicurarti che il puntatore punti ad una zona di memoria abbastanza vasta. Con la funzione malloc(N) chiedi al runtime di procurarti una zona di memoria grande N byte, e ti viene restituito il suo indirizzo. Dovrai poi ricordarti di liberare quella memoria con la funzione free(), una volta che non ti servirà più.
char *smallest_word = (char*)malloc(200); char *largest_word = (char*)malloc(200); int i; strcpy(smallest_word,argv[1]); strcpy(largest_word,argv[1]); ... free(smallest_word); free(largest_word); // Ora non puoi più usare la memoria puntata dalle due // variabili (ma puoi assegnare ad esse altre zone di // memoria).
In realtà in questo caso avresti potuto usare degli array di caratteri (così eviti di doverti ricordare di liberare la memoria):
char smallest_word[200]; char largest_word[200]; int i; strcpy(smallest_word,argv[1]); strcpy(largest_word,argv[1]);
ma se avessi inizializzato:
perchè poi strcpy non lo avrei potuto fare?In fondo non sto così modificando la stringa constante...
Ps.Come faccio ad attivare gli avvisi?
char *smallest_word = "a"; char *largest_word = "a"; int i; strcpy(smallest_word,argv[1]); strcpy(largest_word,argv[1]);
perchè poi strcpy non lo avrei potuto fare?In fondo non sto così modificando la stringa constante...
Ps.Come faccio ad attivare gli avvisi?
"nadia89":
ma se avessi inizializzato:
char *smallest_word = "a"; char *largest_word = "a"; int i; strcpy(smallest_word,argv[1]); strcpy(largest_word,argv[1]);
perchè poi strcpy non lo avrei potuto fare?In fondo non sto così modificando la stringa constante...
Sì che stai modificando la stringa costante. smallest_word punta alla stringa costante "a", strcpy() copia la memoria contenuta all'indirizzo puntato da argv[1] nella memoria contenuta all'indirizzo puntato da smallest_word (che è una stringa costante).
Inoltre, se anche "a" fosse stata una stringa non costante, avrebbe comunque avuto dimensione 2 (il carattere 'a' più il carattere nullo). Se argv[1] avesse avuto più di un carattere avresti avuto comunque un errore, perché era più grande della destinazione.
Ps.Come faccio ad attivare gli avvisi?
Se usi GCC con le opzioni -Wall e -Wextra:
gcc -std=c89 -pedantic -Wall -Wextra hello.c -o hello.exe gcc -std=c99 -pedantic -Wall -Wextra hello.c -o hello.exe
Con -std=c89 dici al compilatore che vuoi usare lo standard C del 1989, con -std=c99 lo standard C del 1999 (usa questo).
Grazie!
Ho provato ad inserire il codice ma mi da l'errore:
Ho provato ad inserire il codice ma mi da l'errore:
gcc: error:hello.c :No such file or directory gcc: fatal error: no input files compilation terminated
Hai chiamato il file hello.c? Sei nella cartella corretta? L'errore ti sta dicendo che non trova il file hello.c.