• Programmazione Android
  • CORSI ONLINE
  • Web Agency

Logo

Corsi di programmazione web e mobile online
Navigation
  • Home
  • CORSI ONLINE
  • Tutorial Pratici
  • GUIDE COMPLETE
    • Corso completo di C
    • Corso videogame con Cocos2d
    • Programmazione Cocoa Touch
  • Sezioni
    • Libri e manuali
    • Tips & Tricks
    • Risorse utili
    • Strumenti di Sviluppo
    • Materiale OpenSource
    • Framework
    • Guide Teoriche
    • Guide varie
    • Grafica e Design
    • iPad
    • News
    • Video Tutorial
    • Windows Phone
  • Pubblicità
  • About
    • Chi siamo
    • Pubblicazioni
    • Collabora
    • Sostieni devAPP

16. Stringhe o array di caratteri?

By IgnazioC | on 3 Agosto 2011 | 12 Comments
Corso completo di C

corso-completo-c-stringhe-o-array-di-caratteri-00 Ed eccoci nuovamente qui per parlare di programmazione C. Purtroppo gli impegni lavorativi mi hanno costretto a prendere una (lunga) pausa ed il corso è stato fermo per un pò ma appena sono riuscito a ritagliarmi un pò di tempo libero eccomi qui, pronto a chiacchierare insieme a voi del più bel linguaggio di programmazione del mondo, quindi… prendete pure una sedia che stiamo per iniziare 🙂

L’argomento della lezione di oggi è la gestione delle stringhe di testo.

Ma cos’è esattamente una stringa? Senza perderci in definizioni matematiche e formali (per questo c’è wikipedia: link) possiamo dire che una stringa è una sequenza di caratteri alfabetici e non, come ad esempio “Ciao mondo” o anche “(3 + 5)” oppure ” # ± % “.

Ma come mai una cosa tanto semplice richiede un’intera lezione di un corso C? E per di più la lezione numero 16 dopo aver parlato di argomenti più complessi come strutture, array e allocazione dinamica della memoria? La risposta è che nulla di quanto abbiamo trattato fino ad ora poteva essere tralasciato per capire le stringhe; e questo per un semplice dato di fatto: Il C non ha il tipo di dato stringa.

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ù 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.

string a = "Ciao "
string b = "mondo"
string c = a + b; 

Ed in C? In C visto che non esiste un tipo predefinito “stringa” bisogna arrangiarci con quello che abbiamo: le variabili di tipo char e gli array… infatti si dice che in C le stringhe sono definite come array di caratteri. Questa frase va scolpita indelebilmente nelle nostre menti:

“le stringhe non esistono, esistono gli array di caratteri”

perché la consapevolezza di questo limite ci farà risparmiare errori grossolani nella stesura dei nostri programmi.

A questo punto la lezione potrebbe concludersi qui perché gli array li abbiamo già visti, le variabili di tipo “char” anche… quindi cos’altro aggiungere? Come vedremo ci sono alcune particolarità che meritano di essere approfondite; inoltre non si può prescidere da un’analisi della libreria che fa parte della libreria standard del C e permette di effettuare le più comuni operazioni su questi array di char.

La dichiarazione

Dichiarare un array di caratteri è semplice e segue la stessa sintassi che abbiamo già visto:

char *nomeVariabile; //allocazione dinamica della memoria
char nomeVariabile[100]; //allocazione statica.

Nella prima riga abbiamo dichiarato un singolo puntatore a char, quindi sarà necessario passare dalle funzioni malloc/calloc per utilizzarlo, mentre nel secondo caso abbiamo dichiarato un array statico di dimensione 100.

L’inizializzazione

Se avete letto già quache pagina sul linguaggio C avrete sicuramente letto che “le stringhe vanno terminate con il carattere ” ” ma in pochi forse spiegano il perché… quindi partiamo dall’inizio…

Abbiamo detto che una stringa è 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’è verso di sapere la lunghezza dell’array che le viene passato… infatti molto spesso si sopperisce a questa mancanza accettando due parametri separati, un array ed un intero che rappresenta la taglia… vi suona familiare? Beh, in effetti ci sarebbe anche un secondo metodo… quello di usare un “marcatore” per indicare che l’array è finito… ad esempio potremmo inserire in un array di interi positivi il valore -1 in ultima posizione così che la funzione che si trovi ad analizzare questo array possa riconoscere autonomamente e senza ulteriori parametri quando l’array è terminato.

Questo secondo approccio è quello che si è scelto di utilizzare per le stringhe, utilizzando come marcatore di fine stringa il carattere ‘Null’ (codice ascii: 0 rappresentazione: ‘ ‘ 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.

Allora come si inizializzano le stringhe?

Si può usare la stessa sintassi usata per inizializzare gli array (solo in fase di dichiarazione) che è questa:

char variabile[5] = {'c','i','a','0',''};

Notare che abbiamo dichiarato un’array di dimensione 5 anche se la stringa da memorizzare è composta da soli 4 caratteri, giusto per fare spazio al terminatore di stringa.

Per questa sintassi esiste una versione ridotta che è la seguente:

char variabile[5] = "ciao"; //oppure
char variabile[] = "ciao";

notare che in questo caso non abbiamo inserito il carattere ‘ ‘ perché lo fa automaticamente il linguaggio per noi.

NOTA: Le stringhe racchiuse tra doppi apici sono dette “string literals” e possono essere utilizzate laddove dal codice viene richiesto un array di caratteri.

“Ok, ma questi due modi di inizializzare le stringhe vanno bene solo per l’allocazione statica e soprattutto come faccio ad assegnare un nuovo valore ad una variabile già inizializzata?”

Ottima domanda, grazie per averla fatta 😉 la risposta è “dobbiamo ricorrere alle funzioni della libreria string.h”

String.h

Prima di vedere qualche esempio dell’uso della libreria “string.h” una breve nota, è possibile stampare a schermo una stringa utilizzando il carattere ” %s” come in questo esempio:

char prova[] = "Ciao mondo";
printf(" La stringa è: %s", prova);
strlen

size_t strlen(const char *s);

Restituisce la lunghezza della stringa s. La lunghezza viene considerata fino al primo carattere ‘ ‘ trovato quindi prima di usare questa funzione assicuratevi di avere correttamente inserito il terminatore di stringa.

Esempio:

char string1[] = "abc";
int len = strlen(string1);
printf("La lunghezza è: %d\n", len);
strcpy

char *strcpy(char *s1, const char *s2);

Copia la stringa s2 nella stringa s1, incluso il carattere di terminazione .

Può essere utilizzato per modificare il valore di una stringa dopo la sua dichiarazione, come in questo esempio:

Esempio:

char string1[] = "Hello, world!";
char string2[20];
strcpy(string2, string1);
strcmp

int strcmp(const char *s1, const char *s2);

Confronta la stringa s1 con s2.

Viene utilizzata per effettuare il confronto lessicografico tra le stringhe, restituisce un valore 1 viceversa. Restituisce 0 se le due stringhe sono uguali.

Esempio:

char string3[] = "Ciao";
char string4[] = "DevAPP";

if(strcmp(string3, string4) == 0)
   printf("strings are equal\n");
else
   printf("strings are different\n");
strcat

char *strcat(char *dest, const char *src);

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.

Attenzione: la stringa deve quindi avere spazio vuoto a sufficienza per contenere la seconda stringa.

Esempio:

char string1[20] = "Hello, ";
char string2[] = "world!";

printf("%s\n", string1);
strcat(string1, string2);
printf("%s\n", string1);

Errori comuni

Ci sono alcuni errori che è facile commettere lavorando con le stringhe in C e che risultano essere piuttosto insidiosi poiché non vengono rilevati dal compilatore… senza nessuna pretesa di completezza eccone alcuni:

Errore 1

char variabile[4] = "ciao";

Questo codice è errato perché non alloca lo spazio necessario per il terminatore di stringa, con un risultato imprevedibile.

Soluzione:

char variabile[5] = "ciao";

Errore 2

char variabile1[5] = "ciao";
char *variabile2;

variabile2 = variabile1;

printf("indirizzo: %x ",variabile1);
printf("indirizzo: %x ",variabile2);

Questo non è 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é questo codice assegna (come si vede dal printf) lo stesso indirizzo di memoria alle due variabili, quindi praticamente sono la stessa variabile

Soluzione:

char variabile1[5] = "ciao";
char *variabile2;

variabile2 = malloc(5 * sizeof(char));
strcpy(variabile2, variabile1);

Errore 3

char *variabile2;
variabile2 = "Ciao mondo";

//oppure

variabile2 = malloc(11 * sizeof(char));
variabile2 = "Ciao mondo";

Questo errore è piuttosto comune e particolarmente insidioso, se provate a compilarlo non vi darà errori e probabilmente sembrerà anche funzionare, ma è profondamente errato perché la riga variabile2 = “Ciao mondo”, che sia preceduta da malloc o meno, sta assegnando al puntatore variabile2 un indirizzo di memoria temporaneo, l’indirizzo creato per noi dal compilatore che contiene la stringa “Ciao mondo”. Proprio perché temporaneo non possiamo fare affidamento a questo indirizzo, ma dobbiamo necessariamente copiare il contenuto della stringa in un array di cui siamo proprietari.

Soluzione:

variabile2 = malloc(11 * sizeof(char));
strcpy(variabile2, "Ciao mondo");

Errore 4

char variabile1[5] = "ciao";
char variabile2[6] = "mondo";

printf(" %s", variabile1 + variabile2);

Questo errore viene commesso dai programmatori java e python 🙂 la concatenazione di due stringhe non si fa con il ” + ” ma con l’operatore strcat e bisogna sempre verificare che sulla destinazione ci sia spazio a sufficienza.

Soluzione:

char string1[20] = "Hello, ";
char string2[] = "world!";

printf("%s\n", string1);
strcat(string1, string2);
printf("%s\n", string1);

Errore 5

char variabile1[6] = "abaco";
char variabile2[4] = "zoo";

if (variabile1 < variabile2 ){
    printf("La prima parola è minore della seconda");
}

L’operatore ” < " non effettua il confronto tra stringhe, ma sul valore dei puntatori quindi non vi darà errore e sembrerà funzionare in modo arbitrario

Soluzione:

char string1[] = "abaco";
char string2[] = "zoo";

if(strcmp(string1, string2) < 0)
   printf("La prima parola è minore della seconda");

E con questo è veramente tutto sull’argomento, non mi resta che consigliarvi una lettura attenta di tutte le pagine di man relative alla libreria string.h e augurarvi buona programmazione!

bye^2
IgnazioC

Letture consigliate:

C-Corso-Completo-di-Programmazione-kernighan-ritchie-devAPP Il linguaggio C. Principi di programmazione e manuale di riferimento (Accademica)
Brian W. Kernighan – Dennis M. Ritchie
Editore: Pearson | Lingua: Italiano | Brossura: 313 pagine
Prezzo Listino: EUR 27,00
Prezzo Promozione: EUR 22,95 con Spedizione gratuita

C-Corso-Completo-di-Programmazione-Deitel-Deitel-devAPP C. Corso completo di programmazione
Paul J. Deitel – Harvey M. Deitel
Editore: Apogeo | Lingua: Italiano | Brossura: 640 pagine
Prezzo Listino: EUR 39,00
Prezzo Promozione: EUR 33,15 con Spedizione gratuita

Share this story:
  • tweet

Tags: array caratteri Ccorso completo di Ccorso di Cerrori comuni stringhe Cesempi codice programmazione Cesercizi programmazione CIgnazio Calòstrcat Cstrcmp Cstrcpy Cstring.h Cstringhe in Cstrlen C

Recent Posts

  • Parte il percorso programmatori iOS in Swift su devACADEMY.it

    20 Dicembre 2017 - 0 Comment
  • Android, crittografare dati velocemente con Encryption

    24 Settembre 2018 - 0 Comment
  • Sql2o, accesso immediato ai database tramite Java

    3 Settembre 2018 - 0 Comment
  • Okio, libreria per ottimizzare l’input/output in Java

    27 Agosto 2018 - 0 Comment

Related Posts

  • iSketch: la lavagna magica di Ignazio Calò disponibile GRATUITAMENTE in App Store

    29 Agosto 2011 - 2 Comments
  • 17. La gestione dei file in C

    22 Agosto 2011 - 4 Comments
  • Uno sguardo a Unit test: impariamo a prevenire ore e ore di debug durante lo sviluppo di Applicazioni iOS

    8 Agosto 2011 - 2 Comments

Author Description

12 Responses to “16. Stringhe o array di caratteri?”

  1. 3 Agosto 2011

    Elder

    Mi sembra piuttosto chiaro 🙂
    Solo un appunto: mi rendo conto che forse non e’ esattamente adatto a un corso base, ma credo sia importante parlare di strncpy oltre che di strcpy e sopratutto sottolineare l’importanza di verificare la dimensione del buffer di destinazione.
    Si’, magari non e’ un concetto base, ma penso che chiunque studi c deve inculcarsi bene in testa questo genere di controlli 😉

  2. 3 Agosto 2011

    ignazioc

    Concordo in pieno. Sono stato indeciso sul parlarne o meno ed alla fine ho pensato di aver già fatto una lezione fin troppo lunga sull’argomento…ma la verità è che si potrebbe scrivere un intero libro!
    Diciamo quindi per completezza che esistono alcune varianti delle funzioni come strcpy e strcat che hanno una ‘n’ in mezzo (strncpy,strncat…) e che non usano il terminatore di stringa ma usano l’altro approccio di cui abbiamo parlato ovvero accettano come parametro il numero di caratteri da copiare.
    Perché sono importanti? per due motivi: il primo è che così facendo siete sicuri di non far crashare il programma qualora vi siate dimenticati del terminatore di stringa…e secondo (e forse più importante) è quello di rendere il nostro programma più resistente agli attacchi degli hacker che potrebbero sfruttare un maldestro strcpy per causare un buffer overrun e far eseguire codice arbitrario al computer ospitante.
    http://en.wikipedia.org/wiki/Buffer_overflow

    grazie per il commento.

  3. 7 Agosto 2011

    tommaso

    finalmente sei tornato (-:

  4. 27 Agosto 2011

    Elia

    Negli esempi di errori ci sono varie ripetizioni dell’errore 1:

    nell’errore 2 char variabile1[4] = “ciao”;
    nell’errore 4 char variabile1[4] = “ciao”; char variabile2[5] = “mondo”;
    nell’errore 5 char variabile1[4] = “abaco”;

    è stato fatto volutamente o è una svista?

  5. 28 Agosto 2011

    Ignazioc

    non è voluto, è colpa di una svista e del copia/incolla. Questo dimostra quanto sia davvero insidioso l’errore 1 🙂

  6. 28 Agosto 2011

    Ignazioc

    ho corretto gli esempi.

  7. 7 Gennaio 2012

    Tanner

    Ho visto anche altri esempi su internet del tipo

    char miastringa[] = “sono una stringa”;

    ma non capisco se il non dichiarare la lunghezza dell’array di caratteri sia risolto dal compilatore o meno, anche se immagino di si.

    Ma è solamente un orpello estetico o una manifestazione di eleganza (o di mancanza di eleganza) dichiarare una stringa in sto modo?

    Scusa la puntigliosità! 😉

  8. 7 Gennaio 2012

    Ignazioc

    la puntigliosità non va scusata, anzi va premiata perché la domanda è veramente interessante.
    Stavo per risponderti che “si se ne occupa il compilatore” ma mi hai fatto venire un dubbio e cercherò in rete la risposta.
    Diciamo innanzitutto che una dichiarazione di quel tipo è corretta ed il compilatore non ha necessità di sapere qual’è la lunghezza della stringa perché basta avere un puntatore al primo carattere in quanto le stringhe tra doppi apici vengono copiate tutte in una zona dell’eseguibile e non è necessario spiegare al compilatore che ci serviranno tot caratteri.
    Il dubbio che mi hai fatto venire è che cosa succede con una dichiarazione del tipo stringa[3] = “AA”; come io stesso ho fatto nell’articolo perché stando così le cose qui ci sarebbe uno spreco di memoria. Il compilatore prima riserva lo spazio per la variabile stringa, poi lascia lo spazio per 3 catteri..ma poi la variabile punta ad un’allocazione dove è memorizzata la stringa “AA” quindi i lo spazio riservato per i caratteri risulterebbe sprecato. Farò delle prove e ti faccio sapere.

  9. 5 Luglio 2013

    Uforob

    Po’ si scrive con l’apostrofo.
    Il più bel linguaggio del mondo è un parere personale…
    Errore 3 in realtà c’è anche senza il malloc
    http://codepad.org/8RRTTmKp
    Infatti poi la stringa non viene modificata anche se pensiamo di averlo fatto (in C++ invece viene dato almeno un warning in fase di compilazione). Quindi comprende il fatto che la stringa è costante sia dati non più accessibili, il garbage (non ci abbiamo messo dentro niente però è allocata). Invece così con la sintassi [] che hai riportato tu funziona
    http://codepad.org/cTQ7xpvA
    come hai messo tu. Bisogna ricordare che la sintassi [] è più del dichiarare semplicemente il puntatore (e non perché lo so, ho controllato lo standard o conosco come funziona il compilatore ma perché l’ho verificato adesso con i due esempi che ho linkato ^_^)

  10. 5 Luglio 2013

    Ignazioc

    Si, infatti dico nel testo “preceduta da malloc o meno”

  11. 6 Luglio 2013

    Uforob

    Hai ragione, mi sono impegnato sul codice ma il commento l’ho scritto un po’ di fretta (come si vede anche dalle ripetizioni e dagli errori di sintassi).
    Ispirato dal tuo articolo ho scritto un post sul mio blog che parla di (quasi) tutti i modi di allocare e inizializzare una stringa in C++:
    http://blog.libero.it/uforob/12179011.html
    Gli esempi di codice sono questi
    http://codepad.org/TXhTaW4s
    http://codepad.org/fDUpPk8r
    http://codepad.org/u5Nqe8wJ
    Nel secondo e nel terzo ci sono gli esempi derivati dal C (il terzo è perché non avevo pensato che potevo copiare anche il terminatore dato che la strncpy di solito si usa per copiare pezzi di stringa e non per copiarne una intera e quindi dopo non c’è il terminatore a meno di essere alla fine).
    Mi sono ricordato per il C-style 2 del secondo esempio che gli string literals (le espressioni tra virgolette) sono di tipo const char* e in quel caso si possono assegnare direttamente al puntatore, comunque poi non si può modificare la stringa (ma si può modificare il valore del puntatore farlo puntare ad altri dati). Ecco l’esempio
    http://codepad.org/exwzOE8k
    Decommentando la riga commentata il codice non compila perché si tenta di modificare un valore costante.
    Non è del tutto vero che NULL è diverso da ”, c’erano compilatori una volta che usavano valori esotici per NULL però adesso usano tutti zero ed essendo il carattere ” equivalente all’intero zero si può assegnare al puntatore (ricordando che è proprio il valore del puntatore e non un dato a cui punta anche se è un carattere). È un po’ contorto e neanch’io lo farei così anche se l’ho appena fatto… http://codepad.org/Hxb6l1Ff . Con 0 il programma è equivalente http://codepad.org/gX7Rdzh2 . Se non ricordo male in C++11 il fatto che 0 debba essere un valore di puntatore valido è proprio parte della specifica del linguaggio e non è una caratteristica arbitraria del compilatore (meglio comunque nullptr). Come vedi ho scelto C per questi due esempi (ma anche in C++ non cambia niente, puoi provare a cambiare nel menù a tendina) e i programmi restituiscono 1 (true, vero, sì) a tutte le domande sul confronto.
    Anche scartando le cose in C++ che aggiungono altri strati, dopo tutto questo si può dire che il C sia il più bel linguaggio del mondo?

  12. 7 Luglio 2013

    Uforob

    Mi sono accorto che “bello” non è oggettivo, le cose che ho scritto nel commento precedente possono forse far vedere che il C non è semplice o pulito però lo rendono interessante. Bello posso anche concordare, infatti per me è stato il primo linguaggio che ho affrontato “seriamente” (all’università) e ci sono legato però se dentro quel “bello” c’è anche “migliore” allora non concordo.

Leave a Reply

Your email address will not be published. Required fields are marked *


*
*

Corso online di programmazione android e java

SEZIONI

  • Android
  • Comunicazioni
  • Contest
  • Corsi ed Eventi
  • Corso completo di C
  • Corso programmazione videogiochi
  • Framework
  • Grafica e Design
  • Guida rapida alla programmazione Cocoa Touch
  • Guide Teoriche
  • Guide varie
  • iPad
  • Le nostre applicazioni
  • Libri e manuali
  • Materiale OpenSource
  • News
  • Pillole di C++
  • Progetti completi
  • Risorse utili
  • Strumenti di Sviluppo
  • Swift
  • Tips & Tricks
  • Tutorial Pratici
  • Video Tutorial
  • Windows Phone

Siti Amici

  • Adrirobot
  • Allmobileworld
  • Apple Notizie
  • Apple Tribù
  • Avvocato360
  • Blog informatico 360°
  • bubi devs
  • fotogriPhone
  • GiovaTech
  • iApp-Mac
  • iOS Developer Program
  • iPodMania
  • MelaRumors
  • Meritocracy
  • SoloTablet
  • TecnoUser
  • Privacy & Cookie Policy
©2009-2018 devAPP - All Rights Reserved | Contattaci
devAPP.it è un progetto di DEVAPP S.R.L. - Web & Mobile Agency di Torino
Str. Volpiano, 54 - 10040 Leini (TO) - C.F. e P.IVA 11263180017 - REA TO1199665 - Cap. Soc. € 10.000,00 i.v.

devACADEMY.it

Vuoi imparare a programmare?

Iscriviti e accedi a TUTTI i corsi con un’unica iscrizione.
Oltre 70 corsi e migliaia di videolezioni online e in italiano a tua disposizione.

ISCRIVITI SUBITO