Salta al contenuto
Note per Studenti Array e stringhe in C

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.

c
#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 0 a N - 1; v[i] si trova all'indirizzo v + i * sizeof(int), per questo l'accesso è O(1)O(1).
  • Nessun controllo degli indici: v[N] o v[-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.
  • const dichiara che la funzione non modificherà gli elementi.

Matrici

c
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 char che 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.

c
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' (O(n)O(n))
strcpy(dst, src) copia src in dst (dst deve essere abbastanza grande)
strncpy(dst, src, n) copia al più n caratteri (può non aggiungere '\0')
strcat(dst, src) accoda src a dst
strcmp(a, b) < 0, 0, > 0 se a precede, è uguale, segue b (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.

c
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 == s2 per confrontare stringhe: confronta gli indirizzi. Usare strcmp.
  • s = "testo"; per assegnare a un array di char: errore; usare strcpy o 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.

c
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 */

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.

c
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; const vieta 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.

c
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', O(n)O(n)), 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 == s2 confronta gli indirizzi: usare strcmp.
  • s = "testo"; su un array di char è errore: usare strcpy.
  • 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