Piccolo Cheat Sheet per il C – parte 3

Terza parte del Cheat Sheet per il C

  • Operazioni su File

file di testo possono effettuano trasformazioni dei caratteri (es ‘\n’), file binari non effettuano nessuna trasformazione.

di defautlt i file sono aperti come file di testo.

Puntatore a file: FILE *f

apertura file f = fopen("nome", "modalità") modalità = r, w, a, rb, wb, ab, r+, w+, a+, r+b, w+b, a+b

chiusura file: fclose(f)

feof(f) (0 = no fine, !=0 = fine)

fputs("stringa",f), fgets(char *s, length + 1, f) (legge fino a \n incluso, o fino a length)

rewind() = riavvolge il file

ferror(f) (0 = no errori, != 0 = errore) [reset ad ogni operazione]

remove("nome file")

fflush(f)

fread(void *buffer, num_byte, numero, f), fwrite(void *buffer, num_byte, numero, f) (num_byte = dimensione di un oggetto, numero = numero di oggetti da leggere o scrivere)

fseek(f, long offset, int origine) (origine = SEEK_SET, SEEK_CUR, SEEK_END)

fprintf(f, "%%%%", ,,,), fscanf(f, "%%%%", &&&&)

./nome_prog < INPUT > OUTPUT

stdout, stdin, stderr

freopen("nome", "modalità", f) (permette di redirezionare uno stream, ad esempio per redirezionare stdout)

  • Preprocessore

direttive eseguite prima della compilazione

#define MACRO val_macro

#error msg (chiede al compilatore di interrompere la compilazione, viene restituito msg)

#include <stdio.h> / #include "mioheader.h"

#if ESPRESSIONE_COSTANTE, #else, #elif ESPRESSIONE_COSTANTE, #eindf (#endif obbligatorio al termine del blocco condizionale #if [[#elif] #else])

#ifdef MACRO (== #if defined MACRO), #ifndef MACRO (== #if !defined MACRO) [finiscono obbligatoriamente con #endif]

#undef MACRO (elimina la macro)

#line numero ["nomefile"] (permette di cambiare il valore di __LINE__ e __FILE__ che contengono il numero di riga e il nome del file)

#pragma (invia comandi al compilatore, dipende dal compilatore)

#, utilizzato con #define permette la conversione di quello che viene dopo in stringa, es:

#define mkstr(s) # s

...

printf(mkstr(pippo));

...

trasforma la printf in printf("pippo")

##, utilizzato con #define concatena quello che viene dopo, es:

#define concat(a,b) a ## b

...

int xy = 10;

printf("%d", concat(x,y));

...

converte la printf in printf("%d", xy)

macro predefinite:

__LINE__

__FILE

__DATE__ (stringa "mese/giorno/anno", indica la data dell’ultima compilazione)

__TIME__ (stringa "ore:minuti:secondi", indica l’ora dell’ultima compilazione)

__STDC__ (dipende dall’implementazione)

__cplusplus (se compilatore standard C++ contiene almeno sei cifre)

Piccolo Cheat Sheet per il C++ parte 1

Questo post segue il precedente “Piccolo Cheat Sheet per il C” (diviso in più parti) e tratta delle caratteristiche principali del C++

  • Tipi di dati

wchar (caratteri a 16 bit, i letterali si indicano con L’char’)

  • Classi

class nomeClasse {

dati e funzioni privati // private è opzionale

specificatori di accesso: //private, public, protected

dati e funzioni // normalmente si mette solo il prototipo delle funzioni

specificatori di accesso:

dati e funzioni

} elenco oggetti; // dichiarazione contemporanea alla definizione

tipo myclass::funzione(parametri) //implementazione

{

...

}

si può usare anche struct per definire una classe invece di class, la differenza sta nel fatto che di default con class i dati e le funzioni sono private, mentre con struct sono public (la stessa cosa vale anche per le union)

  • unioni anonime

in C++ si possono dichiarare unioni anonime, es:

int main()

{

union {

long l;

double d;

};

...

l = 1000000;

d = 123.2342;

...

si usano direttamente le variabili membro dell’unione, come se fossero variabili normali.

  • Funzioni friend

possono accedere agli oggetti private della classe di cui sono friend (non sono membri della classe)

class nome {

...

friend tipo funzione(parametri);

...

}

tipo funzione(parametri)

{

...

}

int main()

{

...

funzione(parametri);

...

}

  • Classi friend

class nome {

...

friend class nome1;

...

};

class nome1 {

...

}

gli oggetti di tipo nome1 hanno accesso a tutti i dati privati della classe nome.

  • Funzioni inline

inline tipo funzione(parametri) // globale

{

...

}

funziona come una macro del C (il compilatore la sostisuisce ogni volta che viene richiamata, se è possibile)

si può fare anche per le funzioni membro di una classe, dichiarando il prototipo normalmente e specificando inline nell’implementazione della funzione, oppure si può mettere l’implementazione all’interno della definizione della classe, al posto del prototipo (in questo caso non è necessario aggiungere inline)

  • Costruttori e istanze

Se il costruttore non ha parametri o non c’è il costruttore si può evitare di specificarlo e l’istanziazione avviene come nel caso di normali variabili:

myclass a, b; // gli oggetti sono istanziati

a.xy = 10; // posso utilizzarli subito

se il costruttore ha un parametro l’inizializzazione può essere fatta così:

myclass a = 10; //ammettendo che il costruttore di myclass sia del tipo myclass(int x) { xy = x; }

se il costruttore ha 2 o più parametri l’inizializzazione può essere fatta così (vale anche per 1 o 0 parametri)

myclass a(10, 3.4); // equivale a myclass a = myclass(10, 3.4)

per dichiarare un array:

myclass a[3]; //deve esserci il costruttore senza parametri

il costruttore di un oggetto può essere richiamato in seguito come un normale metodo:

myclass ob;

ob = myclass(par1, par2);

  • membri static di una classe

è possibile usare static per attributi membro di una classe, questi sono condivisi per tutti gli oggetti della classe. è necessario definire esplicitamente le variabili static esternamente alla classe:

class nome {

static int x; // in questo caso x è privata

....

}

int nome::x; //definisco la variabile e alloco la relativa memoria, se x fosse stata pubblica, per accedervi esternamente alla classe si usa l'operatore :: (nome::x = 10)

le funzioni static operano solo su variabili static e non possono essere virtuali, const o volatile, si accede ad esse con ::

  • operatore ::

:: si usa anche per accedere a variabili globali quando sono ridefinite localmente, ad es:

int x;

int main()

{

int x;

x = 4; // accesso alla variabile locale

::x = 10; // accesso alla variabile globale

...

}

  • Classi nidificate e interne a funzioni

È possibile dichiarare delle classi interne ad altre classi e classi interne al corpo di una funzione, in entrambi i casi ne limito la visibilità al solo elemento dentro cui sono dichiarate

  • Passaggio di oggetti a funzioni

quando si passa un oggetto ad una funzione, l’oggetto è passato per valore, quindi si crea una copia dell’oggetto originale, ma non viene richiamato il costruttore, la copia avviene bit per bit, questo potrebbe essere un problema nel caso in cui l’oggetto allochi memoria, perchè le due copie condividono la stessa area di memoria, quindi all’uscita della funzione l’area di memoria viene rimossa e l’oggetto originale non può più accedervi.

  • Restituzione di oggetti da parte di funzioni

viene restituito un oggetto temporaneo creato dalla funzione e al termine della funzione l’oggetto viene distrutto, questo può portare a problemi come quelli espressi nel punto sopra.

  • Assegnamento fra oggetti

myclass a,b:

a = b; // effettua una copia bit a bit, quindi stessi problemi descritti sopra.

Piccolo Cheat Sheet per il C – parte 2

Seconda parte del Cheat Sheet per il C (prima parte qui).

  • Puntatori

printf(“%p”, ptr); doppi puntatori int **p; i puntatori locali contengono un valore random se non inizializzati, quelli globali sono messi a NULL.

  • Puntatori a funzioni

int f(int x, char c) {

...

}

...

int (*f_ptr)(int x, char c)

f_ptr = f;

f2(2.3, f_ptr); // == f2(2.3, f);

...

int f2(double d, int (*f_ptr_X)(int x, char c))

{

...

}

  • Allocazione dinamica

void *malloc(size_t byte) (restituisce un puntatore a void, ovvero un puntatore ad un tipo qualsiasi, serve un cast. size_t ~ unsigned short int)

void free(p)

  • argc e argv

int argc = numero parametri (>=1), char *argv[] = array di stringhe con i parametri passati da linea di comando, il primo è sempre il nome del programma.

  • funzioni

In C++ tutte le funzioni devono avere il prototipo, in C non è obbligatorio. in C si usa char f(void) per funzioni senza parametri, in C++ va bene anche char f()

  • funzioni con elenco di parametri con lunghezza variabile

se una funzione ha almeno un parametro, ma non si sa bene quanti è possibile dichiararla come int f(char par1, ...) (esempio printf)

#include <stdarg.h>

TYPE func(TYPE arg1,TYPE arg2, ...)
{
    va_list ap;
    TYPE x;
    va_start(ap,arg2);
    x = va_arg(ap,TYPE);
       /* and so on */
    va_end(ap);
}

i parametri opzionali possono essere solo double e int (o unsigned int), un parametro float è convertito in double, e un char o uno short int è convertito in int

non c’è un metodo standard per capire se sono arrivato all’ultimo parametro, quindi devo “inventare” una mia convenzione, tipo printf che vuole tanti parametri quanti sono i %X del primo parametro (la stringa)

  • dichiarazione di funzioni vecchio stampo

prima le funzioni si dichiaravano come:

tipo nome_funz(par1, par2, par3)

tipo1 par1;

tipo2 par2;

tipo3 par3;

{

...

}

  • Strutture con campi bit

struct nome {

tipo nome1: lunghezza;

tipo nome2: lunghezza;

...

}

es:

struct struttura_bit {

unsigned bit1: 1;

unsigned bit2: 1;

...

}

struttura_bit_instance.bit1 = 0; // imposto il bit a 0

  • Unioni

le unioni sono come le strutture, ma tutti gli elementi condividono la stessa area di memoria:

union type_x {

int word; // ad es: 16 bit (2 byte)

char low_byte; // il byte basso della coppia

}

  • Enumerazioni

enum tipo_enum {

a, b, c, d, e, f

};

tipo_enum istanza;

istanza = a;

if(istanza == b)

  • Specificatori di formato per I/O formattato

%d == %i

%e (notazione scientifica con ‘e’), %E (notazione scientifica con ‘E’)

%g/%G (usa il più corto tra %e/%E e %f)

%o (ottale)

%u (unsigned int)

%x/%X (esadecimale, lettere minuscole/maiuscole)

%p puntatore

%n puntatore a interi in cui viene scritto il numero di caratteri scritti su output

%10f (almeno 10 caratteri, se ne servono meno mette spazi bianchi, allineamento a destra)

%'c'10f (almeno 10 caratteri, se ne servono meno mette tanti ‘c’ quanti ne servono (‘c’ = un carattere, gli apici non servono realmente))

%-10f (allineamento a sinistra)

%10.4f (almeno 10 caratteri, con 4 decimali, se meno mette tanti 0)

%4.8s (stringa min 4, max 8 caratteri

%ld (long int)

%Lf (long double, L maiuscola)

%#f (stampa le cifre decimali anche se non ci sono)

%#x (stampa 0x davanti al numero esadecimale)

%*.*f (la dimensione minima e la precisione decimale sono specificati da due parametri della printf, es: printf("%*.*f", 10, 4, 123.45678);)

%[XYZ] (per scanf, riferito ad un array, dice a scanf di leggere solo i caratteri presenti tra [], in questo caso X,Y,Z, quando l’utente inserisce un altro carattere, si passa alla variabile successiva)

%*c (per scanf, leggo un carattere ma non lo memorizzo da nessuna parte, funziona con un qualsiasi %*, d, f, g, e, u,…)

Piccolo Cheat Sheet per il C – parte 1

Questa serie di post vuole essere un piccolo Cheat Sheet per il linguaggio C. Lo scrivo prima di tutto per me, visto che non programmo in C da molto tempo e rischio di dimenticarmi qualche cosa, ma magari può tornare utile anche a qualcun’altro.

Lo scopo di questo post non è ricapitolare tutte le caratteristiche o le strutture del C, ma di annotare alcune caratteristiche che altrimenti rischierei di dimenticare.

  • Tipi di dati

char, int, float, double, void

  • Modificatori dei tipi

signed, unsigned (solo char e int), short (solo int), long (int e double)

  • Modificatori di accesso

const (valore solo in inizializzazione) utile nelle funzioni con parametri puntatori, per impedire modifiche all’oggetto puntato dal parametro, volatile la variabile può essere modificata esternamente al programma

  • Specificatori di classe di memorizzazione

extern per accedere a variabili globali definite in altri file, static variabili "permanenti" all’interno di una funzione o di un file (nel secondo caso la variabil pur essendo globale sarà nota solo all’interno del file), register chiede al compilatore di trattare "con riguardo" la variabile, ad esempio mantenendola in un registro (se possibile aumenta le prestazioni)

  • Letterali

123 = int, 123L = long int, 123 = short int, 123U = unsigned int, 123.0F = float, 123.0 = double, 123.0L = long double, 0x123 = int esadecimale, 0123 = int ottale, '1' = char, "123" = char*

  • Costanti speciali (escape)

\b (backspace), \f (form feed), \t (tabulazione orizzontale), \v (tabulazione verticale), (carattere nullo), \a (bip), \? (punto interrogativo), \N (costante ottale), \xN (costante esadecimale)

  • Operatori bit a bit

& (and), | (or), ^ (xor), ~ (complemento a 1), >> (scorrimento a destra), << (scorrimento a sinistra), negli scorrimenti i bit da aggiungere all’estremità opposta allo scorrimento sono sempre 0, nel caso di numero negativo si mette un 1 all’ultimo bit

  • Operatori per puntatori

& (l’indirizzo di var) * (valore all’indirizzo di val)

  • sizeof

sizeof var (o (var)), sizeof (int)

  • Operatore ,

esegue tutte le operazioni da sinistra a destra, e restituisce il valore dell’ultima operazione (quella più a destra)

  • Operatore . e ->

. per accesso a elementi di strutture, -> per accesso a elementi di strutture tramite puntatori

  • Ordine di valutazione delle espressioni

L’ordine di valutazione è deciso dal compilatore, non c’è un ordine fisso

  • Vero e Falso

==0 = falso, !=0 =vero (anche <0)

  • dichiarazione di variabili in cicli e selezioni (if, switch)

non si può

  • dichiarazione di variabili

solo all’inizio di un blocco

  • dichiarazione e definizione

dichiarazione = no allocazione (ad esempio con extern), definizione = dichiarazione + allocazione (caso standard)

  • array

funzione con array multidimensionale come parametro tipo func(tipo a[][N][M][O]), occorre specificare la lunghezza delle dimensioni (dalla seconda in poi) perchè il compilatore deve sapere di quanto spostarsi ad ogni accesso.

int *p, a[10];

p = a;

*(p+5) = a[5]; //=p[5]

a = &a[0];

  • Inizializzazione array

int i[] = {1, 2, 3, 4};

char str[] = "string";

int d[][2] = { 1,1, 2,2, 3,3 4,4};

int d[][2] = { {1,1}, {2,2}, {3,3}, {4,4}};