I CARATTERI
•
Ogni carattere viene memorizzato come un numero intero
•
“smallest addressable unit of the machine that can contain basic character set.
It is an integer type. Actual type can be either signed or unsigned depending
on the implementation.”
•
•
•
•
Dichiarazione di un carattere: char c = ‘p’;
La conversione classica carattere ßà numero è codificata all’interno di una
tabella standard chiamata ASCII table
•
•
Il segno (se non si definisce signed o unsigned) è definito
dall’implementazione (-funsigned-char su GCC per forzarlo)
Serve a farci della “matematica”
rappresentazione di 1 carattere con 7 bit
Domanda:
•
•
char c = ‘1’;
printf(“c=%d\n”, (int)c ); //cosa stampa?
ASCII TABLE
UNICODE
•
•
Problema: come rappresentare le lettere non comprese
dal’alfabeto americano
• ad. es. ò, è, ù
• ma anche le lettere cirilliche/ideogrammi cinesi etc.
Unicode: sistema di codifica di più di 110000 caratteri,
gestione e rappresentazione
•
•
•
ad es. gli arabi scrivono da destra a sinistra
standard (attualmente v 6.3) mantenuto dall’Unicode
Consortium
Codifica: tra le piu’ usate, UTF-8
•
•
Se il carattere è nella tabella ASCII, allora usiamo la
codifica ASCII
• Altrimenti scriviamo il valore codificato (fino 4 byte)
Unicode != UTF
•
•
Unicode: character set (mappa ad ogni carattere un
valore univoco), UTF: codifica (come memorizzare/
inviare quel valore)
“UTF-8 and Unicode cannot be compared. UTF-8 is an
encoding used to translate binary data into numbers.
Unicode is a character set used to translate numbers into
characters.”
UNICODE: ESEMPIO
LE STRINGHE
• Array di char terminate dal carattere NULL
‘c’
• NULL è il carattere ‘\0’ ovvero il numero 0
• “null terminated array of char”
‘i’
‘a’
‘o’
• Esempio:
• char mia_stringa[] = “ciao”;
•
Se una stringa viene inizializzata in questo
modo, la terminazione è automatica. La dimensione
è quindi 5 byte
• Metodo alternativo:
•
char mia_stringa[5] = {‘c’, ‘i’, ‘a’, ‘o’, ‘\0’};
‘\0’
ESERCIZIO CON
STRINGHE
•
•
Accettare una stringa, memorizzarla e stamparla a video come
stringa e come insieme di numeri
• ovvero l’ASCII code corrispondente ai suoi caratteri
Funzioni utili:
•
•
•
•
•
scanf(“%s”, mia_stringa); // per accettare input e scriverli dentro
l’array
printf(“%s”, mia_stringa); //per stampare la stringa
printf(“%c”, mia_stringa[0]); // per stampare un carattere
scanf(“%c”, &mia_stringa[0]); // per accettare un carattere
scanf("%[^\n]s", mia_stringa); //accetta fino al newline
•
Cosa succede se scriviamo più caratteri della dimensione dell’array?
•
Cosa succede se non terminiamo con NULL la stringa?
SICUREZZA E BUFFER
OVERFLOW?
http://www.dmi.unipg.it/~bista/didattica/sicurezza-pg/bufferoverrun/letture-buffer-overrun/Buffer-Overflows-0.7.pdf
I PUNTATORI
• Variabili i cui valori sono indirizzi di memoria
• Variabili che contengono l’indirizzo di un’altra variabile
• I puntatori hanno un tipo (ad es. puntatore ad intero)
• Esempio: int *mio_puntatore
• int *a, b; //dichiara un puntatore di tipo a e un intero di tipo b
• Buona pratica: Inizializzare i puntatori a NULL
• esempio: int *mio_puntatore = NULL;
• costante simbolica definita come 0
OPERATORE DI
INDIRIZZO
• L’operatore “&” restituisce
l’indirizzo di una variabile
OPERATORE DI
INDIREZIONE
int a = 5;
int *myptr = NULL;
myptr = &a;
int a = 5;
int *myptr = NULL;
myptr = &a;
•
L’operatore “*” il valore della
variabile puntata da un puntatore
•
“dereferenziare” un puntatore
printf(“a=%d”, *myptr);
printf(“myptr=%p”, myptr)
• Gli operatori possono essere concatenati (ad es **a)
• Se applicati insieme (ad es *&a) restituiscono la variabile
originaria (ad es a)
PASSAGGIO DI
ARGOMENTI PER
RIFERIMENTO
•
In C tutti gli argomenti vengono
passati per valore
•
Passando il puntatore ad una
variabile, si “emula” il
passaggio per riferimento
void make_square(int *);
int main () {
int test = 200;
•
•
Molto utile per motivi di
efficienza
• Utile per far modificare ad
una funzione più variabili
E’ un passaggio delicato…
#include <stdio.h>
•
•
Quando si può, passare per
valore per il principio del
privilegio minimo (facilita il
debug)
oppure usare const (vedi
dopo)
make_square(&test);
printf(“test=%d\n”, test);
return 0;
}
void make_square(int *n){
*n = *n * *n;
}
QUALIFICATORE
CONST
• Se una variabile non cambia all’interno di una funzione,
deve essere dichiarata come const
• esempio: const int a = 10;
• Valido anche per gli argomenti: esempio prova_funzione
(const int b)
•
Non viene modificata la copia di b
• Qualora venga modificata, errore in compilazione
Attenzione!
void test(char* c);
puntatore non costante a dati non costanti
void test(const char* c);
puntatore non costante a dati costanti
void test(char * const c);
puntatore costante a dati non costanti
void test(const char * const c);
puntatore costante a dati costanti
NOTA: “const char *c” e “char* const c” sono la stessa cosa
PUNTATORI E ARRAY
Esempio:
int my_array[10];
• my_array (senza indice) è un puntatore costante al primo
elemento dell’array
• il passaggio di un array ad una funzione avviene quindi per
riferimento
• E’ possibile far puntare un puntatore al primo elemento
dell’arrary
• int *ptr;
• ptr = my_array; // equivalente a ptr = &my_array[0]
• … muoverlo per far puntare diversi elementi dell’array
• *(ptr + 3); // notazione puntatore/offset
• ptr[3]; //notazione puntatore/indice
• sono equivalenti
ARRAY DI PUNTATORI
Esempio: array di stringhe
const char *mie_stringhe[3] = {‘pippo’, ‘pluto’, ‘ciao’};
mie_stringhe[0]
mie_stringhe[1]
mie_stringhe[2]
p
i
p
p
o
\0
p
l
u
t
o
\0
c
i
a
o
\0
Che differenza c’e’ con un array bidimensionale di caratteri?
ARGC - ARGV
• La funzione main accetta tre parametri
• int argc: numero di argomenti passati alla funzione (+1)
•
ad es. ./main test1 test2 à argc = 3
• char *argv[]: array di stringhe (o array di puntatori a
carattere) che rappresentano i valori degli argomenti
•
•
•
ad es. ./main test1 test2 à argv[1] = ‘test1’
Il primo argomento è sempre il nome del programma
stesso
argv[argc] è NULL
• char *envp[]: array di stringhe che rappresentano i valori
delle variabili di ambiente
•
poco usata (ricerca lineare) meglio “getenv” (lib standard)
ESEMPIO OPERATORI
*E&
• char c, *p, **pp;
• c = ‘x’;
• p = &c; //ok
• pp = &p; //ok
• printf(“%c\n”, **pp); //ok scrive c
• pp = &&c; //errore!
PUNTATORI A
FUNZIONE
Per dichiarare un puntatore a funzione:
• tipo_restituito (*nome_puntatore_a_funz)(arg1, arg2 …);
• Esempi:
• int (* pippo)(char c, int *p);
• Dichiaro un puntatore a funzione che si chiama pippo e puo’ puntare ad una
funzione che accetti come parametri un char e un puntatore a intero, e che
ritorni un intero.
• int *pippo(char , int *p);
• Questo non è un puntatore a funzione, ma un prototipo di funzione
Esempio di utilizzo:
•
•
double somma( double a, double b) ; /* dichiarazione */
int main() {
•
•
•
•
•
•
}
….
double (*ptrf) ( double g, double f);
double c
ptrf = somma;
c = ptrf (A,B);
CASTING DI
PUNTATORI
E’ possibile fare il casting dei puntatori cosi’ come per gli
altri tipi
• char *c = ‘ciao’;
• short x = (short*)c;
• A volte è usato “void *” ad indicare un puntatore che
prima di essere dereferenziato obbliga al casting
NON E’ COSI’
SEMPLICE…
char *c = “ciao”;
“string literals”, è sempre di tipo const char[N]
c != c2
char *c2 = “ciao”;
char *c = “ciao”;
char *c2 = “pippo”;
c = c2
Non stiamo copiando le stringhe
ma stiamo facendo puntare due
puntatori alla stessa stringa
• In C, manipolare le stringhe è come manipolare degli array
di numeri
• E’ per questo che non viene usato in alcuni contesti (ad es il
web)
• Stesso discorso per la concatenazione di stringhe…
STRINGHE: COPIARE E
CONFRONTARE
<string.h>
Copiare
char *strcpy(char *s1, const char *s2);
Copia s2 in s1, ritorna s1
char *strncpy(char *s1, const char *s2,
size_t n);
Copia al massimo n caratteri da s2 in s1,
ritorna s1
char *strcat(char *s1, const char *s2);
Concatena s2 in fondo a s1
char *strncat(char *s1, const char *s2,
size_t n);
Concatena al massimo n caratteri di s2
in fondo a s1
Confrontare
int strcmp(char *s1, const char *s2);
Confronta s1 e s2, ritorna 0 se sono
uguali
int strncpy(char *s1, const char *s2,
size_t n);
Confronta n caratteri, ritorna 0 se sono
uguali
STRINGHE:
CONVERSIONE
<stdlib.h>
double strtod(const char *nPtr, char
**endPtr);
converte la stringa “nPtr” in un double,
restituendolo.
endPtr è l’indirizzo di un puntatore a
carattere che viene fatto puntare subito
dopo la fine della stringa convertita
long strtol(const char *nPtr, char
**endPtr, int base);
converte la stringa in long
unsigned long strtoul(const char *nPtr,
char **endPtr, int base);
converte la stringa in unsigned long
STRINGHE:
FORMATTAZIONE
Scrivere una stringa formattata
• sprinf(mia_stringa, “pippo=%d, pluto=%d”, pippo, pluto);
• come printf, ma scrive su stringa e non su std output
Leggere una stringa formatta
• sscanf(mia_stringa, “pippo=%d, pluto=%d”, &pippo,
&pluto)
• presa la stringa precedente, salviamoci le variabili
STRINGHE: ALTRE
FUNZIONI UTILI
char *strchr(const char *s, int c);
ritorna la prima occorrenza di c in s,
oppure NULL
char *strstr(const char *s1, const
char *s2);
ritorna il puntatore alla prima
occorrenza della stringa s2 in s1 o
NULL
char *strtok(char *s1, const char
*s2);
Separa la stringa s1 in base ai
caratteri definiti in s2. La prima
chiamata restituisce l’indirizzo del
primo token. Le chiamate
successive, se s1==NULL,
restituisono i token successivi,
oppure NULL se non ci sono altri
token.
PER MAGGIORI INFO
apt-get install manpages-dev
apt-get install manpages-posix-dev
(e ovviamente se non l’avete ancora fatto installate “man”)
e quindi:
man strlen
ESERCIZIO:
PRODOTTO SCALARE
Realizzare un programma che accetti come parametri due vettori e ne
ritorni il prodotto scalare
Specifiche tecniche:
•
I due vettori verranno passati come stringhe al programma e l’output
sarà un numero che verrà sia stampato a video che impostato come
valore di ritorno (return X)
•
Ogni elemento del vettore è un intero con segno (puo’ essere
positivo o negativo)
•
usare i puntatori
•
scrivere una funzione “parser” (input stringa à output vettore)
•
ESEMPIO
•
•
•
./mio_programma “{1,2,3,4}” “{0,1,2,0}”
à calcolo 1*0 + 2*1 + 3*2 + 4*0 = 8
return 8
ESERCIZIO IN AULA
Scrivere una funzione che cambi il valore di un puntatore
inizializzandolo a NULL.
OPERAZIONI CON LA
MEMORIA
char *memcpy(void *s1, const void *s2,
size_t n);
Copia n caratteri da s2 in s1, ritorna s1
char *memmove(void *s1, const void *s2, Copia n caratteri da s2 in s1 utilizzando
size_t n);
un array temporaneo, ritorna s1.
Ad esempio per spostare di un byte un
insieme di caratteri
int memcmp (void *s1, const void *s2,
size_t n);
Ritorna 0 se i primi n caratteri sono
uguali
char *memchr(const void *s1, int c,
size_t n);
Cerca la prima occorrenza di c in s1. Ne
ritorna il puntatore o NULL.
void *memset(void *s, int c, size_t n);
Copia c nei primi n caratteri dell’oggetto
puntato da s.
© Copyright 2025 Paperzz