{"id":7396,"date":"2011-08-03T12:27:15","date_gmt":"2011-08-03T10:27:15","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=7396"},"modified":"2011-10-05T12:27:23","modified_gmt":"2011-10-05T10:27:23","slug":"16-stringhe-o-array-di-caratteri","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/16-stringhe-o-array-di-caratteri\/","title":{"rendered":"16. Stringhe o array di caratteri?"},"content":{"rendered":"<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/corso-completo-c-stringhe-o-array-di-caratteri-00.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/corso-completo-c-stringhe-o-array-di-caratteri-00.jpg\" alt=\"corso-completo-c-stringhe-o-array-di-caratteri-00\" width=\"200\" height=\"100\" class=\"alignleft size-full wp-image-7401\" \/><\/a> Ed eccoci nuovamente qui per parlare di programmazione C. Purtroppo gli impegni lavorativi mi hanno costretto a prendere una (lunga) pausa ed il corso \u00e8 stato fermo per un p\u00f2 ma appena sono riuscito a ritagliarmi un p\u00f2 di tempo libero eccomi qui, pronto a chiacchierare insieme a voi del pi\u00f9 bel linguaggio di programmazione del mondo, quindi&#8230; prendete pure una sedia che stiamo per iniziare \ud83d\ude42<\/p>\n<p>L&#8217;argomento della lezione di oggi \u00e8 la gestione delle stringhe di testo.<!--more--><\/p>\n<p>Ma cos&#8217;\u00e8 esattamente una stringa? Senza perderci in definizioni matematiche e formali (per questo c&#8217;\u00e8 wikipedia: <a href=\"http:\/\/it.wikipedia.org\/wiki\/Stringa_%28formale%29\" target=\"_blank\">link<\/a>) possiamo dire che una stringa \u00e8 una sequenza di caratteri alfabetici e non, come ad esempio &#8220;Ciao mondo&#8221; o anche  &#8220;(3 + 5)&#8221; oppure &#8221; # \u00b1 % &#8220;.<\/p>\n<p>Ma come mai una cosa tanto semplice richiede un&#8217;intera lezione di un corso C? E per di pi\u00f9 la lezione numero 16 dopo aver parlato di argomenti pi\u00f9 complessi come strutture, array e allocazione dinamica della memoria? La risposta \u00e8 che nulla di quanto abbiamo trattato fino ad ora poteva essere tralasciato per capire le stringhe; e questo per un semplice dato di fatto: <strong>Il C non ha il tipo di dato stringa<\/strong>.<\/p>\n<p>In (credo) qualsiasi altro linguaggio di programmazione, se serve una stringa, basta dichiarare la variabile del tipo corretto ed assegnarle il valore, inoltre sono previsti tutti i metodi pi\u00f9 elementari per la gestione delle stesse. Questo potrebbe essere un pezzo di codice sorgente in un linguaggio di alto livello che preveda la gestione delle stringhe.<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nstring a = \"Ciao \"\r\nstring b = \"mondo\"\r\nstring c = a + b; \r\n<\/pre>\n<p>Ed in C? In C visto che non esiste un tipo predefinito &#8220;stringa&#8221; bisogna arrangiarci con quello che abbiamo: le variabili di tipo <em>char<\/em> e gli <em>array<\/em>&#8230; infatti si dice che in C le stringhe sono definite come array di caratteri. Questa frase va scolpita indelebilmente nelle nostre menti:<\/p>\n<p>&#8220;le stringhe non esistono, esistono gli array di caratteri&#8221;<\/p>\n<p>perch\u00e9 la consapevolezza di questo limite ci far\u00e0 risparmiare errori grossolani nella stesura dei nostri programmi.<\/p>\n<p>A questo punto la lezione potrebbe concludersi qui perch\u00e9 gli array li abbiamo gi\u00e0 visti, le variabili di tipo &#8220;char&#8221; anche&#8230; quindi cos&#8217;altro aggiungere? Come vedremo ci sono alcune particolarit\u00e0 che meritano di essere approfondite; inoltre non si pu\u00f2 prescidere da un&#8217;analisi della libreria  che fa parte della libreria standard del C e permette di effettuare le pi\u00f9 comuni operazioni su questi <em>array di char<\/em>.<\/p>\n<h4>La dichiarazione<\/h4>\n<p>Dichiarare un array di caratteri \u00e8 semplice e segue la stessa sintassi che abbiamo gi\u00e0 visto:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar *nomeVariabile; \/\/allocazione dinamica della memoria\r\nchar nomeVariabile[100]; \/\/allocazione statica.\r\n<\/pre>\n<p>Nella prima riga abbiamo dichiarato un singolo puntatore a char, quindi sar\u00e0 necessario passare dalle funzioni malloc\/calloc per utilizzarlo, mentre nel secondo caso abbiamo dichiarato un array statico di dimensione 100.<\/p>\n<h4>L&#8217;inizializzazione<\/h4>\n<p>Se avete letto gi\u00e0 quache pagina sul linguaggio C avrete sicuramente letto che &#8220;le stringhe vanno terminate con il carattere &#8221; &#8221; ma in pochi forse spiegano il perch\u00e9&#8230; quindi partiamo dall&#8217;inizio&#8230;<\/p>\n<p>Abbiamo detto che una stringa \u00e8 un array di caratteri e se avete svolto qualche esercizio tra quelli proposti che riguardano gli array vi sarete resi conto che quando una funzione accetta come parametro un array non c&#8217;\u00e8 verso di sapere la lunghezza dell&#8217;array che le viene passato&#8230; infatti molto spesso si sopperisce a questa mancanza accettando due parametri separati, un array ed un intero che rappresenta la taglia&#8230; vi suona familiare? Beh, in effetti ci sarebbe anche un secondo metodo&#8230; quello di usare un &#8220;marcatore&#8221; per indicare che l&#8217;array \u00e8 finito&#8230; ad esempio potremmo inserire in un array di interi positivi il valore -1 in ultima posizione cos\u00ec che la funzione che si trovi ad analizzare questo array possa riconoscere autonomamente e senza ulteriori parametri quando l&#8217;array \u00e8 terminato.<\/p>\n<p>Questo secondo approccio \u00e8 quello che si \u00e8 scelto di utilizzare per le stringhe, utilizzando come marcatore di fine stringa il carattere &#8216;Null&#8217; (codice ascii: 0 rappresentazione: &#8216;  &#8216; non ha nulla a che vedere con il NULL POINTER) quindi, anche se non tecnicamente necessario, ricordatevi di inserire questo carattere alla fine della stringa.<\/p>\n<p>Allora come si inizializzano le stringhe?<\/p>\n<p>Si pu\u00f2 usare la stessa sintassi usata per inizializzare gli array (solo in fase di dichiarazione) che \u00e8 questa:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar variabile[5] = {'c','i','a','0',''};\r\n<\/pre>\n<p>Notare che abbiamo dichiarato un&#8217;array di dimensione 5 anche se la stringa da memorizzare \u00e8 composta da soli 4 caratteri, giusto per fare spazio al terminatore di stringa.<\/p>\n<p>Per questa sintassi esiste una versione  ridotta che \u00e8 la seguente:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar variabile[5] = \"ciao\"; \/\/oppure\r\nchar variabile[] = \"ciao\";\r\n<\/pre>\n<p>notare che in questo caso non abbiamo inserito il carattere &#8216;  &#8216; perch\u00e9 lo fa automaticamente il linguaggio per noi.<\/p>\n<p><strong>NOTA:<\/strong> Le stringhe racchiuse tra doppi apici sono dette &#8220;string literals&#8221; e possono essere utilizzate laddove dal codice viene richiesto un array di caratteri.<\/p>\n<p>&#8220;Ok, ma questi due modi di inizializzare le stringhe vanno bene solo per l&#8217;allocazione statica e soprattutto come faccio ad assegnare un nuovo valore ad una variabile gi\u00e0 inizializzata?&#8221;<\/p>\n<p>Ottima domanda, grazie per averla fatta \ud83d\ude09 la risposta \u00e8 &#8220;dobbiamo ricorrere alle funzioni della libreria string.h&#8221;<\/p>\n<h4>String.h<\/h4>\n<p>Prima di vedere qualche esempio dell&#8217;uso della libreria &#8220;string.h&#8221; una breve nota, \u00e8 possibile stampare a schermo una stringa utilizzando il carattere &#8221; %s&#8221; come in questo esempio:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar prova[] = \"Ciao mondo\";\r\nprintf(\" La stringa \u00e8: %s\", prova);\r\n<\/pre>\n<h5>strlen<\/h5>\n<p><strong>size_t strlen(const char *s);<\/strong><\/p>\n<p>Restituisce la lunghezza della stringa s. La lunghezza viene considerata fino al primo carattere &#8216; &#8216; trovato quindi prima di usare questa funzione assicuratevi di avere correttamente inserito il terminatore di stringa.<\/p>\n<p>Esempio:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar string1[] = \"abc\";\r\nint len = strlen(string1);\r\nprintf(\"La lunghezza \u00e8: %d\\n\", len);\r\n<\/pre>\n<h5>strcpy<\/h5>\n<p><strong>char *strcpy(char *s1, const char *s2);<\/strong><\/p>\n<p>Copia la stringa s2 nella stringa s1, incluso il carattere di terminazione .<\/p>\n<p>Pu\u00f2 essere utilizzato per modificare il valore di una stringa dopo la sua dichiarazione, come in questo esempio:<\/p>\n<p>Esempio:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar string1[] = \"Hello, world!\";\r\nchar string2[20];\r\nstrcpy(string2, string1);\r\n<\/pre>\n<h5>strcmp<\/h5>\n<p><strong>int strcmp(const char *s1, const char *s2);<\/strong><\/p>\n<p>Confronta la stringa s1 con s2.<\/p>\n<p>Viene utilizzata per effettuare il confronto lessicografico tra le stringhe, restituisce un valore 1 viceversa. Restituisce 0 se le due stringhe sono uguali.<\/p>\n<p>Esempio:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar string3[] = \"Ciao\";\r\nchar string4[] = \"DevAPP\";\r\n\r\nif(strcmp(string3, string4) == 0)\r\n   printf(\"strings are equal\\n\");\r\nelse\r\n   printf(\"strings are different\\n\");\r\n<\/pre>\n<h5>strcat<\/h5>\n<p><strong>char *strcat(char *dest, const char *src);<\/strong><\/p>\n<p>Concatena src alla stringa dest. A differenza di quanto avviene con altri linguaggi non viene restituita una nuova stringa contenete la concatenazione delle due, ma la destinazione viene effettivamente modificata.<\/p>\n<p><strong>Attenzione:<\/strong> la stringa deve quindi avere spazio vuoto a sufficienza per contenere la seconda stringa.<\/p>\n<p>Esempio:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar string1[20] = \"Hello, \";\r\nchar string2[] = \"world!\";\r\n\r\nprintf(\"%s\\n\", string1);\r\nstrcat(string1, string2);\r\nprintf(\"%s\\n\", string1);\r\n<\/pre>\n<h4>Errori comuni<\/h4>\n<p>Ci sono alcuni errori che \u00e8 facile commettere lavorando con le stringhe in C e che risultano essere piuttosto insidiosi poich\u00e9 non vengono rilevati dal compilatore&#8230; senza nessuna pretesa di completezza eccone alcuni:<\/p>\n<p><strong>Errore 1<\/strong><\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar variabile[4] = \"ciao\";\r\n<\/pre>\n<p>Questo codice \u00e8 errato perch\u00e9 non alloca lo spazio necessario per il terminatore di stringa, con un risultato imprevedibile.<\/p>\n<p><strong>Soluzione:<\/strong><\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar variabile[5] = \"ciao\";\r\n<\/pre>\n<p><strong>Errore 2<\/strong><\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar variabile1[5] = \"ciao\";\r\nchar *variabile2;\r\n\r\nvariabile2 = variabile1;\r\n\r\nprintf(\"indirizzo: %x \",variabile1);\r\nprintf(\"indirizzo: %x \",variabile2);\r\n<\/pre>\n<p>Questo non \u00e8 propriamente un errore, a patto che si sappia veramente quello che si sta facendo. Se crediamo di aver creato una copia di variabile1 memorizzata in variabile2 abbiamo commesso un errore perch\u00e9 questo codice assegna (come si vede dal printf) lo stesso indirizzo di memoria alle due variabili, quindi praticamente sono la stessa variabile<\/p>\n<p><strong>Soluzione:<\/strong><\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar variabile1[5] = \"ciao\";\r\nchar *variabile2;\r\n\r\nvariabile2 = malloc(5 * sizeof(char));\r\nstrcpy(variabile2, variabile1);\r\n<\/pre>\n<p><strong>Errore 3<\/strong><\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar *variabile2;\r\nvariabile2 = \"Ciao mondo\";\r\n\r\n\/\/oppure\r\n\r\nvariabile2 = malloc(11 * sizeof(char));\r\nvariabile2 = \"Ciao mondo\";\r\n<\/pre>\n<p>Questo errore \u00e8 piuttosto comune e particolarmente insidioso, se provate a compilarlo non vi dar\u00e0 errori e probabilmente sembrer\u00e0 anche funzionare, ma \u00e8 profondamente errato perch\u00e9 la riga variabile2 = &#8220;Ciao mondo&#8221;, che sia preceduta da malloc o meno, sta assegnando al puntatore variabile2 un indirizzo di memoria temporaneo, l&#8217;indirizzo creato per noi dal compilatore che contiene la stringa &#8220;Ciao mondo&#8221;. Proprio perch\u00e9 temporaneo non possiamo fare affidamento a questo indirizzo, ma dobbiamo necessariamente copiare il contenuto della stringa in un array di cui siamo proprietari.<\/p>\n<p><strong>Soluzione:<\/strong><\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nvariabile2 = malloc(11 * sizeof(char));\r\nstrcpy(variabile2, \"Ciao mondo\");\r\n<\/pre>\n<p><strong>Errore 4<\/strong><\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar variabile1[5] = \"ciao\";\r\nchar variabile2[6] = \"mondo\";\r\n\r\nprintf(\" %s\", variabile1 + variabile2);\r\n<\/pre>\n<p>Questo errore viene commesso dai programmatori java e python \ud83d\ude42 la concatenazione di due stringhe non si fa con il &#8221; + &#8221; ma con l&#8217;operatore <em>strcat<\/em> e bisogna sempre verificare che sulla destinazione ci sia spazio a sufficienza.<\/p>\n<p><strong>Soluzione:<\/strong><\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar string1[20] = \"Hello, \";\r\nchar string2[] = \"world!\";\r\n\r\nprintf(\"%s\\n\", string1);\r\nstrcat(string1, string2);\r\nprintf(\"%s\\n\", string1);\r\n<\/pre>\n<p><strong>Errore 5<\/strong><\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar variabile1[6] = \"abaco\";\r\nchar variabile2[4] = \"zoo\";\r\n\r\nif (variabile1 &lt; variabile2 ){\r\n    printf(&quot;La prima parola \u00e8 minore della seconda&quot;);\r\n}\r\n<\/pre>\n<p>L&#8217;operatore &#8221; &lt; &quot; non effettua il confronto tra stringhe, ma sul valore dei puntatori quindi non vi dar\u00e0 errore e sembrer\u00e0 funzionare in modo arbitrario<\/p>\n<p><strong>Soluzione:<\/strong><\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar string1[] = \"abaco\";\r\nchar string2[] = \"zoo\";\r\n\r\nif(strcmp(string1, string2) &lt; 0)\r\n   printf(&quot;La prima parola \u00e8 minore della seconda&quot;);\r\n<\/pre>\n<p>E con questo \u00e8 veramente tutto sull&#8217;argomento, non mi resta che consigliarvi una lettura attenta di tutte le pagine di man relative alla libreria string.h e augurarvi buona programmazione!<\/p>\n<p>bye^2<br \/>\nIgnazioC<\/p>\n<h4>Letture consigliate:<\/h4>\n<p><a href=\"http:\/\/www.amazon.it\/gp\/search\/ref=as_li_qf_sp_sr_il_tl?ie=UTF8&#038;keywords=887192200X&#038;tag=de0d-21&#038;index=aps&#038;linkCode=as2&#038;camp=3370&#038;creative=23322\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/03\/C-Corso-Completo-di-Programmazione-kernighan-ritchie-devAPP.jpg\" alt=\"C-Corso-Completo-di-Programmazione-kernighan-ritchie-devAPP\" title=\"C-Corso-Completo-di-Programmazione-kernighan-ritchie-devAPP\" width=\"54\" height=\"75\" class=\"alignleft size-full wp-image-7803\" \/><\/a> <a href=\"http:\/\/www.amazon.it\/gp\/search\/ref=as_li_qf_sp_sr_il_tl?ie=UTF8&#038;keywords=887192200X&#038;tag=de0d-21&#038;index=aps&#038;linkCode=as2&#038;camp=3370&#038;creative=23322\" target=\"_blank\"><strong>Il linguaggio C. Principi di programmazione e manuale di riferimento (Accademica) <\/strong><\/a><br \/>\n<em>Brian W. Kernighan &#8211; Dennis M. Ritchie<\/em><br \/>\n<strong>Editore:<\/strong> Pearson | <strong>Lingua:<\/strong> Italiano | <strong>Brossura:<\/strong> 313 pagine<br \/>\n<strong>Prezzo Listino:<\/strong> <del datetime=\"2011-09-03T10:00:08+00:00\">EUR 27,00<\/del><br \/>\n<strong>Prezzo Promozione:<\/strong> EUR 22,95 con Spedizione gratuita<\/p>\n<p><a href=\"http:\/\/www.amazon.it\/gp\/product\/8850329547\/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&#038;tag=de0d-21&#038;linkCode=as2&#038;camp=3370&#038;creative=23322&#038;creativeASIN=8850329547\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/09\/C-Corso-Completo-di-Programmazione-Deitel-Deitel-devAPP.jpg\" alt=\"C-Corso-Completo-di-Programmazione-Deitel-Deitel-devAPP\" title=\"C-Corso-Completo-di-Programmazione-Deitel-Deitel-devAPP\" width=\"54\" height=\"75\" class=\"alignleft size-full wp-image-7550\" \/><\/a> <a href=\"http:\/\/www.amazon.it\/gp\/product\/8850329547\/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&#038;tag=de0d-21&#038;linkCode=as2&#038;camp=3370&#038;creative=23322&#038;creativeASIN=8850329547\" target=\"_blank\"><strong>C. Corso completo di programmazione<\/strong><\/a><br \/>\n<em>Paul J. Deitel &#8211; Harvey M. Deitel<\/em><br \/>\n<strong>Editore:<\/strong> Apogeo | <strong>Lingua:<\/strong> Italiano | <strong>Brossura:<\/strong> 640 pagine<br \/>\n<strong>Prezzo Listino:<\/strong> <del datetime=\"2011-09-03T10:00:08+00:00\">EUR 39,00<\/del><br \/>\n<strong>Prezzo Promozione:<\/strong> EUR 33,15 con Spedizione gratuita<\/p>\n<p><a href=\"http:\/\/www.devapp.it\/wordpress\/supporto-applicazioni\/le-applicazioni-dei-nostri-autori\/parole-vietate-di-ignazio-calo\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/02\/bannerIgnazioc.png\" alt=\"\" width=\"480\" height=\"100\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ed eccoci nuovamente qui per parlare di programmazione C. Purtroppo gli impegni lavorativi mi hanno costretto a&#8230;<\/p>\n","protected":false},"author":53,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[569],"tags":[859,593,588,865,724,723,241,864,863,862,860,858,861],"class_list":["post-7396","post","type-post","status-publish","format-standard","hentry","category-corso-completo-di-c","tag-array-caratteri-c","tag-corso-completo-di-c-2","tag-corso-di-c","tag-errori-comuni-stringhe-c","tag-esempi-codice-programmazione-c","tag-esercizi-programmazione-c","tag-ignazio-calo","tag-strcat-c","tag-strcmp-c","tag-strcpy-c","tag-string-h-c","tag-stringhe-in-c","tag-strlen-c"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7396","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/users\/53"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=7396"}],"version-history":[{"count":9,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7396\/revisions"}],"predecessor-version":[{"id":7820,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7396\/revisions\/7820"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=7396"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=7396"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=7396"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}