I CARATTERI - stud.netgroup.uniroma2.itstud.netgroup.uniroma2.it/~lorenzo/fondinf2015/C4.pdf · I...

Post on 23-Feb-2019

225 views 0 download

Transcript of I CARATTERI - stud.netgroup.uniroma2.itstud.netgroup.uniroma2.it/~lorenzo/fondinf2015/C4.pdf · I...

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

•  Il segno (se non si definisce signed o unsigned) è definito dall’implementazione (-funsigned-char su GCC per forzarlo)

•  Serve a farci della “matematica” •  Dichiarazione di un carattere: char c = ‘p’;

•  La conversione classica carattere ßà numero è codificata all’interno di una

tabella standard chiamata ASCII table •  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

•  NULL è il carattere ‘\0’ ovvero il numero 0 •  “null terminated array of char”

•  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’};

‘c’ ‘i’ ‘a’ ‘o’ ‘\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?

ESERCIZIO IN AULA Calcolare se una frase (input) è palindroma: Radar

Otto

ecc.

SICUREZZA E BUFFER OVERFLOW? http://www.dmi.unipg.it/~bista/didattica/sicurezza-pg/buffer-overrun/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

int a = 5;

int *myptr = NULL;

myptr = &a;

OPERATORE DI INDIREZIONE

•  L’operatore “&” restituisce l’indirizzo di una variabile

int a = 5;

int *myptr = NULL;

myptr = &a;

printf(“a=%d”, *myptr); printf(“myptr=%p”, myptr)

•  L’operatore “*” il valore della variabile puntata da un puntatore •  “dereferenziare” un puntatore

•  Gli operatori possono essere concatenati (ad es **a) •  Se applicati insieme (ad es *&a) restituiscono la variabile

originaria (ad es a)

CREAZIONE DI UNA STRINGA 1.  char s[10] = “prova”;

Alloca un array di 10 caratteri e lo inizializza a “prova\0” 2.  char s[] = “prova”;

Alloca un array di 5 caratteri e lo inizializza a “prova\0” 3.  char *s = “prova”;

Crea una stringa “prova\0” e fa puntare da s (non è detto che sia scrivibile)

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!

ESERCIZIO CON ARRAY Giochiamo a filetto! •  Creare un array multidimensionale 3 X 3 •  Finchè la partita non è conclusa:

•  Far inserire la scelta dell’utente (numero da 1 a 9) •  Far generare al computer una scelta random •  Calcolare se la partita è conclusa

•  Stampare il risultato (hai vinto/perso/pari)

PUNTATORI E ARRAY •  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

Esempio: int my_array[10];

PASSAGGIO DI ARGOMENTI PER RIFERIMENTO

#include <stdio.h> void make_square(int *); int main () { int test = 200; make_square(&test); printf(“test=%d\n”, test); return 0; } void make_square(int *n){ *n = (*n) * (*n); }

•  In C tutti gli argomenti vengono passati per valore

•  Passando il puntatore ad una variabile, si “emula” il passaggio per riferimento •  Molto utile per motivi di

efficienza •  Utile per far modificare ad

una funzione più variabili •  E’ un passaggio delicato…

•  Quando si può, passare per valore per il principio del privilegio minimo (facilita il debug)

•  oppure usare const (vedi dopo)

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

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

Attenzione!

PUNTATORI AD ARRAY int a[8]; int *pa = a; // metodi uguali

a[2] = 4;

*(pa+2) = 4;

Possiamo usare i puntatori per accedere agli elementi dell’array!

Aritmetica dei puntatori incrementiamo il puntatore di sizeof( ELEMENTO_PUNTATO)

PUNTATORI AD ARRAY MULTIDIMENSIONALI int a[4][2] = {{1,2,3,4},{5,6,7,8}};

ARRAY DI PUNTATORI Esempio: array di stringhe const char *mie_stringhe[3] = {“pippo”, “pluto”, “ciao”};

c i a o \0

p i p p o \0

p l u t o \0

mie_stringhe[0] mie_stringhe[1] mie_stringhe[2]

Che differenza c’e’ con un array bidimensionale di caratteri?

ESERCIZIO

Creare una funzione void che •  accetti un puntatore a una stringa e

che lo modifichi per puntare al primo carattere ‘s’ o a NULL se non lo trova

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)

int main(int argc, char *argv[], char *envp[])

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);

•  } •  Proviamo ad inserire anche la funzione “sottrazione”…

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”; char *c2 = “ciao”;

c != c2

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…

è sempre di tipo const char[N]

STRINGHE: COPIARE E CONFRONTARE 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

<string.h>

Confrontare

int strcmp(char *s1, const char *s2); Confronta s1 e s2, ritorna 0 se sono uguali

int strlen(char *s1); Ritorna la lunghezza della stringa

STRINGHE: FORMATTAZIONE Scrivere una stringa formattata

•  sprintf(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

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

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

ESERCIZIO: PRODOTTO SCALARE Realizzare un programma che accetti come parametri due vettori e ne ritorni (return del main) 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 double con segno (puo’ essere positivo o negativo) - max

100 elementi in ogni vettore (100 numeri) •  i vettori hanno stesso numero di argomenti e le virgole parantesi sono corrette; gli spazi

possono essere ovunque e in numero arbitrario tra i numeri, le virgole e le parenetesi •  il valore di ritorno deve essere arrotondato all’intero piu’ vicino •  Le virgolette non compaiono nell’argomento (non sono in argv): servono per passare

tutto il vettore come unico argomento, altrimento ad ogni spazio ci sarebbe un argomento nuovo

•  Piu’ file .c e almeno un .h, NO GOTO

•  ESEMPIO •  ./mio_programma “{1,2,3, 4}” “{0,1, 2,0}” •  à calcolo 1*0 + 2*1 + 3*2 + 4*0 = 8 •  return 8

Attenzione agli spazi!

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, size_t n);

Copia n caratteri da s2 in s1 utilizzando 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.