Array e stringhe in C
In questa pagina 5
In questa pagina 4
Array
Un array è una sequenza di N elementi dello stesso tipo in celle di memoria contigue. La dimensione è fissata alla dichiarazione.
#define N 5
int v[N]; /* valori indeterminati */
int w[5] = {3, 1, 4, 1, 5};
int z[100] = {0}; /* tutti a zero */
int u[] = {2, 7, 1}; /* dimensione dedotta: 3 */
for (int i = 0; i < N; i++) {
v[i] = i * i;
}Definizione (array in C)
- Indici da
0aN - 1;v[i]si trova all'indirizzov + i * sizeof(int), per questo l'accesso è .- Nessun controllo degli indici:
v[N]ov[-1]leggono/scrivono memoria altrui (comportamento indefinito: valori casuali, crash, variabili vicine modificate).- Non si può assegnare un array a un altro (
w = v;è un errore) né confrontarli con==: si copia elemento per elemento.sizeof(w) / sizeof(w[0])dà il numero di elementi, ma solo dove l'array è dichiarato, non dentro una funzione che lo riceve.
Esempio. Con int w[5] = {3, 1, 4, 1, 5}; si ha w[2] == 4 e sizeof(w) / sizeof(w[0]) == 5.
Rispetto alle Liste in Pythonlist come sequenza mutabile (array dinamico); indici, slicing e assegnamento a fette; metodi e loro costo; aliasing, copia superficiale e profonda; list comprehension; liste annidate e matrici.Liste in Python →: niente append, niente lunghezza memorizzata, niente tipi misti. Per una dimensione decisa a run-time serve l'allocazione dinamica (Gestione della memoria in CSegmenti di memoria di un processo (codice, dati statici, stack, heap); durata delle variabili; allocazione dinamica con malloc, calloc, realloc e free; errori classici: memory leak, dangling pointer, double free, buffer overflow; strumenti di controllo.Gestione della memoria in C →).
Array e funzioni
Proprietà (array passato a una funzione). Il nome di un array, in quasi tutte le espressioni, vale l'indirizzo del primo elemento (vedi Puntatori in CUn puntatore contiene un indirizzo di memoria; operatori & e *, NULL, puntatori come parametri per modificare variabili del chiamante, aritmetica dei puntatori, legame tra array e puntatori, const, puntatori a puntatori.Puntatori in C →). Passandolo a una funzione si passa quell'indirizzo:
int somma(const int v[], int n) { /* equivalente a: const int *v */ int s = 0; for (int i = 0; i < n; i++) s += v[i]; return s; } void azzera(int v[], int n) { /* modifica l'array del chiamante */ for (int i = 0; i < n; i++) v[i] = 0; } /* chiamate: somma(w, 5); azzera(w, 5); */
Esempio. Con w = {3, 1, 4, 1, 5}, somma(w, 5) restituisce 14; dopo azzera(w, 5) la stessa chiamata restituisce 0, perché la funzione ha modificato l'array del chiamante.
- La lunghezza va sempre passata come parametro.
constdichiara che la funzione non modificherà gli elementi.
Matrici
int m[3][4]; /* 3 righe, 4 colonne, memorizzate riga per riga */
m[1][2] = 7;
void stampa(int m[][4], int righe) { /* tutte le dimensioni tranne la prima vanno indicate */
for (int i = 0; i < righe; i++) {
for (int j = 0; j < 4; j++)
printf("%3d", m[i][j]);
printf("\n");
}
}Stringhe
Definizione (stringa C). Una stringa C è un array di
charche termina con il carattere nullo'\0'(valore 0). La lunghezza non è memorizzata: si conta fino a'\0'.
Esempio. Con char s[] = "ciao"; si ha sizeof(s) == 5 (cinque byte, terminatore compreso) e strlen(s) == 4.
char s[] = "ciao"; /* 5 byte: 'c' 'i' 'a' 'o' '\0' */
char t[20] = "ciao"; /* 20 byte, i restanti a zero */
char c = 'a'; /* carattere: apici singoli */
/* "a" è una stringa di 2 byte: 'a' e '\0' */Una stringa di n caratteri richiede un array di almeno n + 1 char.
string.h
Definizione (funzioni di string.h)
Funzione Effetto strlen(s)numero di caratteri prima di '\0'()strcpy(dst, src)copia srcindst(dstdeve essere abbastanza grande)strncpy(dst, src, n)copia al più ncaratteri (può non aggiungere'\0')strcat(dst, src)accoda srcadststrcmp(a, b)< 0,0,> 0seaprecede, è uguale, segueb(ordine dei codici)strchr(s, c),strstr(s, sub)puntatore alla prima occorrenza, o NULL
Esempio. strlen("ciao") vale 4, strcmp("abc", "abd") è negativo e dopo strcpy(nome, "Ada") si ha strcmp(nome, "Ada") == 0.
char nome[32];
strcpy(nome, "Ada");
if (strcmp(nome, "Ada") == 0) { /* uguali */ }
/* lunghezza scritta a mano */
int lunghezza(const char s[]) {
int n = 0;
while (s[n] != '\0')
n++;
return n;
}<ctype.h>: isdigit(c), isalpha(c), isspace(c), toupper(c), tolower(c).
Lettura di stringhe da tastiera e da file: Input e output in Cprintf con larghezza e precisione, scanf con indirizzi e valore di ritorno, lettura di righe con fgets, file con FILE*, fopen, fclose, fprintf, fscanf, controllo degli errori e della fine del file.Input e output in C →.
Errori tipici
s1 == s2per confrontare stringhe: confronta gli indirizzi. Usarestrcmp.s = "testo";per assegnare a un array dichar: errore; usarestrcpyo inizializzare nella dichiarazione.- Dimenticare lo spazio per
'\0'o non aggiungerlo costruendo una stringa a mano: le funzioni continuano a leggere oltre la fine. - Uscire dai limiti dell'array (
for (i = 0; i <= N; i++)). - Usare
sizeof(v)dentro una funzione per avere la lunghezza: dà la dimensione di un puntatore.
Versione ripasso
Array
Sequenza di N elementi dello stesso tipo in celle contigue, dimensione fissata alla dichiarazione.
int v[5]; /* valori indeterminati */
int w[5] = {3, 1, 4, 1, 5};
int z[100] = {0}; /* tutti a zero */
int u[] = {2, 7, 1}; /* dimensione dedotta: 3 */- Indici da
0aN - 1;v[i]è all'indirizzov + i * sizeof(int)(accesso ). - Nessun controllo degli indici:
v[N]ov[-1]danno comportamento indefinito. - Un array non si assegna (
w = v;è errore) né si confronta con==: si copia elemento per elemento. sizeof(w) / sizeof(w[0])dà il numero di elementi solo dove l'array è dichiarato, non dentro una funzione.- Rispetto alle Liste in Pythonlist come sequenza mutabile (array dinamico); indici, slicing e assegnamento a fette; metodi e loro costo; aliasing, copia superficiale e profonda; list comprehension; liste annidate e matrici.Liste in Python →: niente
append, niente lunghezza memorizzata, niente tipi misti. Dimensione a run-time: allocazione dinamica (Gestione della memoria in CSegmenti di memoria di un processo (codice, dati statici, stack, heap); durata delle variabili; allocazione dinamica con malloc, calloc, realloc e free; errori classici: memory leak, dangling pointer, double free, buffer overflow; strumenti di controllo.Gestione della memoria in C →).
Array e funzioni
Il nome di un array vale l'indirizzo del primo elementoUn puntatore contiene un indirizzo di memoria; operatori & e *, NULL, puntatori come parametri per modificare variabili del chiamante, aritmetica dei puntatori, legame tra array e puntatori, const, puntatori a puntatori.Puntatori in C →: la funzione riceve quell'indirizzo, quindi può modificare l'array del chiamante.
int somma(const int v[], int n) { /* equivalente a: const int *v */
int s = 0;
for (int i = 0; i < n; i++)
s += v[i];
return s;
}- La lunghezza va sempre passata come parametro;
constvieta di modificare gli elementi. - Matrici:
int m[3][4];(3 righe, 4 colonne, memorizzate per righe); come parametro vanno indicate tutte le dimensioni tranne la prima (int m[][4]).
Stringhe
Array di char terminato da '\0'; la lunghezza non è memorizzata. Per n caratteri servono almeno n + 1 char.
char s[] = "ciao"; /* 5 byte: 'c' 'i' 'a' 'o' '\0' */
char c = 'a'; /* carattere: apici singoli; "a" è una stringa di 2 byte */string.h: strlen(s) (conta fino a '\0', ), strcpy(dst, src) (dst abbastanza grande), strncpy (può non aggiungere '\0'), strcat(dst, src), strcmp(a, b) (< 0, 0, > 0 secondo l'ordine dei codici), strchr/strstr (puntatore alla prima occorrenza o NULL). <ctype.h>: isdigit, isalpha, isspace, toupper, tolower. Lettura da tastiera e file: Input e output in Cprintf con larghezza e precisione, scanf con indirizzi e valore di ritorno, lettura di righe con fgets, file con FILE*, fopen, fclose, fprintf, fscanf, controllo degli errori e della fine del file.Input e output in C →.
Errori tipici
s1 == s2confronta gli indirizzi: usarestrcmp.s = "testo";su un array dicharè errore: usarestrcpy.- Dimenticare lo spazio per
'\0'o non aggiungerlo costruendo una stringa a mano. - Uscire dai limiti (
for (i = 0; i <= N; i++));sizeof(v)dentro una funzione dà la dimensione di un puntatore.
Esercizi su questo argomento
Teoria collegata
- Heap
- Puntatori, struct e memoria dinamica in C
- Rappresentazione dei grafi
- Dal Python al C
- File di record e controllo degli errori riga per riga
- Funzioni in C
- Liste in Python
- Puntatori in C
- Rappresentazione binaria dei dati
- C++ - puntatori, array e cast
- Richiami di C per la programmazione di rete - memoria, puntatori, struct ed endianness