Documente Academic
Documente Profesional
Documente Cultură
2016
Programarea Calculatoarelor si
Limbaje de Programare • typedef
CUPRINS
• Uniuni
CURS 10 •
•
Câmpuri de biţi
Argumentele liniei de comandă
- suport de curs - • Intrări şi ieşiri
Intrări şi ieşiri standard
Ieşire cu format – sprintf
typedef, uniuni și câmpuri de Liste de argumente de lungime variabilă
Intrare cu format - sscanf
biţi. Intrări și ieșiri
Accesul la fişiere
18:00 PCLP CURS 10 2
typedef
• Limbajul C pune la dispoziţie o facilitate numită
typedef
pentru crearea de noi nume de tipuri de date.
typedef typedef
• În mod asemănător, declaraţia • Observaţi că nume de tip de dată declarat într-o
typedef char *Sir; construcţie typedef
face numele de tip de dată Sir un sinonim pentru apare în poziţia unui nume de variabilă şi
char* (pointer către char), nu imediat după cuvântul typedef.
care apoi poate fi folosit în declaraţii şi conversii:
• Din punct de vedere sintactic, typedef e asemănător
Sir p, ptrlinie[MAXLINII], alloc(int); cu clasele de memorie extern, static etc.
int strcmp(Sir, Sir);
• Am folosit majusculă inițială pentru numele tipurilor
p = (Sir) malloc(100);
de date definite cu typedef pentru a le evidenţia.
18:00 PCLP CURS 10 5 18:00 PCLP CURS 10 6
1
09.11.2016
typedef typedef
• Putem crea nume noi de tipuri de date cu typedef • Aceste linii de cod creează două noi cuvinte cheie
pentru nodurile de arbori prezentate anterior: pentru tipuri de date numite
typedef struct tnod *Ptrarbore; Nodarbore (o structură) şi
Ptrarbore (un pointer la o structură).
typedef struct tnod { /* nodul arborelui:*/
char *cuvant; /* indica spre text */ • Atunci rutina arbaloc ar putea deveni
int nr_ap; /* numarul de aparitii */
Ptrarbore arbaloc(void)
Ptrarbore stanga; /* fiul stang */
{
Ptrarbore dreapta; /* fiul drept */ return(Ptrarbore)malloc(sizeof(Nodarbore));
} Nodarbore; }
18:00 PCLP CURS 10 7 18:00 PCLP CURS 10 8
• Trebuie subliniat faptul că o declaraţie typedef • În afară de chestiunile de ordin pur estetic
NU CREEAZĂ un tip de dată nou;
ea doar atribuie un nume unui tip existent. • Există două motive principale pentru utilizarea
construcţiilor typedef.
• Nici din punct de vedere semantic nu apar noutăţi:
variabilele declarate astfel au exact aceleaşi proprietăţi 1.Primul este protejarea unui program împotriva
ca şi cele ale căror declaraţii sunt exprimate explicit.
problemelor de portabilitate.
• typedef este asemănător cu #define,
• Dacă se folosesc construcţii typedef pentru
exceptând faptul că deoarece typedef este
tipuri de date care pot fi dependente de maşină,
interpretat de compilator,
acesta poate efectua substituţii de text numai construcţiile typedef trebuie modificate
care se situează peste posibilităţile preprocesorului. când programul este mutat.
18:00 PCLP CURS 10 9 18:00 PCLP CURS 10 10
2
09.11.2016
Uniuni
• O uniune este o variabilă care poate stoca la momente
diferite
obiecte de diferite tipuri şi dimensiuni,
compilatorul fiind cel care îndeplineşte cerinţele
referitoare la
dimensiune şi
aliniere.
• Oricare dintre aceste tipuri poate fi atribuit lui u şi • Rezultatele depind de implementare în cazul în
apoi folosit in expresii, care se stochează ceva
atât timp cât modul de folosire este consecvent ca fiind de un anumit tip şi
tipul folosit trebuie să fie tipul cel mai recent
se foloseşte ca fiind de un alt tip.
stocat.
18:00 PCLP CURS 10 17 18:00 PCLP CURS 10 18
3
09.11.2016
Uniuni Uniuni
• Sunt permise aceleaşi tipuri de operaţii cu uniunile,
• De fapt, o uniune este o structură
care sunt permise şi în cazul structurilor:
în care toţi membrii au deplasament zero faţă de atribuirea sau copierea ca o unitate,
adresa de început, citirea adresei şi
accesarea unui membru.
structura este suficient de voluminoasă
pentru a stoca cel mai „întins“ membru, • O uniune nu poate fi iniţializată
decât cu o valoare de tipul primului său membru
iar alinierea este potrivită pentru toate tipurile din
uniune. astfel, uniunea u descrisă anterior
nu poate fi iniţializată decât cu o valoare întreagă.
18:00 PCLP CURS 10 23 18:00 PCLP CURS 10 24
4
09.11.2016
Câmpuri de biţi
• În engleză: bit-fields
• Imaginaţi-vă o componentă a unui compilator, • Cea mai compactă metodă de a codifica aceste
care manipulează o tabelă de simboluri. informaţii este
un set de indicatori pe câte un bit
• Fiecare identificator din program are asociate
în interiorul unui singur char sau int.
anumite informaţii
18:00 PCLP CURS 10 27 18:00 PCLP CURS 10 28
5
09.11.2016
• Sintaxa definirii şi accesării unui câmp este bazată • Acest cod defineşte o variabilă numită indicatori
pe structuri. care conţine 3 câmpuri de câte 1 bit.
• Spre exemplu, tabela de simboluri definite cu • Numărul care urmează după caracterul două puncte :
ajutorul lui #define de mai sus reprezintă dimensiunea câmpului în biţi.
ar putea fi înlocuită cu definiţia a trei câmpuri: • Câmpurile sunt declarate de tipul unsigned int
struct { pentru a asigura faptul că sunt mărimi pozitive.
unsigned int este_cuvcheie: 1; • Referirea individuală la câmpuri se face
unsigned int este_extern : 1; la fel ca pentru alţi membri ai unei structuri:
unsigned int este_static : 1; indicatori.este_cuvcheie
} indicatori;
indicatori.este_extern
18:00 PCLP CURS 10 35 18:00 PCLP CURS 10 36
6
09.11.2016
• Câmpurile se comportă ca nişte întregi mici şi • Aproape tot ce este legat de câmpuri este dependent
pot face parte din expresii aritmetice la fel ca orice alţi de implementare.
întregi.
• Dacă un câmp poate depăşi marginea unui cuvânt
• Astfel, exemplele anterioare pot fi scrise într-un mod depinde de implementare.
mai natural astfel:
• Câmpurile nu au nevoie de nume;
indicatori.este_extern = indicatori.este_static = 1;
câmpurile fără nume
pentru a seta biţii la valoarea 1 doar un caracter două puncte şi dimensiunea
indicatori.este_extern = indicatori.este_static = 0; sunt folosite pentru umplerea spaţiului liber.
pentru a-i seta la 0
• Valoarea specială 0 a dimensiunii
if(indicatori.este_extern == 0 && indicatori.este_static == 0)
poate fi folosită pentru a forţa alinierea la marginea
… pentru a-i evalua. următorului cuvânt.
18:00 PCLP CURS 10 37 18:00 PCLP CURS 10 38
7
09.11.2016
care copiază argumentele din linia de comandă pe o • Această primă versiune a funcţiei echo tratează variabila
singură linie, separate prin spaţiu. argv ca pe un tablou de pointeri către caractere.
18:00 PCLP CURS 10 43 18:00 PCLP CURS 10 44
Pentru testarea programului anterior se • Prin convenţie, argv[0] este numele cu care a
creează un Proiect (vezi indicațiile de la
fost invocat programul,
Laborator 6) apoi din meniul Project se
alege Set program’s arguments… deci argc are cel puţin valoarea 1.
și în caseta de dialog care apare (Select
Target) , pe opțiunea Debug, se • Dacă argc are valoarea 1,
completează cele două argumente ale
programului: salut, lume nu mai există argumente în linia de comandă după
numele programului.
8
09.11.2016
• Exemplu 2: Aduce unele îmbunătăţiri programului • Să modificăm programul (găseşte) astfel încât
pentru a afişarea fiecărei linii de pe intrare care modelul ce urmează ar fi căutat
conţine un model (pattern) particular reprezentat de să fie specificat de primul argument al liniei de comandă.
un şir de caractere (“to”)
/* getline: preia linie in s, intoarce lungimea ei */
prezentat în Cursul 6. int getline(char *s, int lim)
{
int c, i = 0;
• Atunci am implicat modelul căutat în părţi esenţiale while (--lim > 0 && (c = getchar()) != EOF && c != '\n')
s[i++] = c;
ale programului, if (c == '\n')
s[i++] = c;
while (există o altă linie) s[i] = '\0'; #include <stdio.h>
return i; #include <string.h>
if (linia conţine modelul) } #define MAXLINIE 1000
afişează linia care conţine modelul int getline(char *linie, int max);
/* gaseste: tipareste liniile pe care
o alcătuire evident nesatisfăcătoare. apare sablonul din primul argument */
18:00 PCLP CURS 10 51 18:00 PCLP CURS 10 52
int main(int argc, char *argv[]) • Funcţia strstr(s,t) din biblioteca standard
{
char linie[MAXLINIE]; returnează un pointer către prima apariţie a
int gasit = 0; şirului de caractere t în şirul s,
if (argc != 2) sau NULL dacă acesta nu apare.
printf("Mod de utilizare: gaseste model\n"); este declarată în <string.h>
else
while (getline(linie, MAXLINIE) > 0)
if (strstr(linie, argv[1]) != NULL) { • Acest model poate fi elaborat acum pentru a
printf(“%s”, linie); ilustra alte construcţii cu pointeri.
gasit++;
} • Să presupunem că dorim să acceptăm două
return gasit;
} argumente opţionale.
18:00 PCLP CURS 10 53 18:00 PCLP CURS 10 54
9
09.11.2016
10
09.11.2016
Intrări şi ieşiri
• Proprietăţile funcţiilor din bibliotecă sunt specificate
în mai mult de 12 fişiere antet
11
09.11.2016
12
09.11.2016
• Dacă prog foloseşte funcţia putchar, • Datele de ieşire produse de printf îşi găsesc de
prog >fisieriesire asemenea drumul către ieşirea standard.
va scrie ieşirea standard în fisieriesire • Apelurile către putchat pot fi alternate cu cele către
printf
în locul situaţiei obişnuite (i.e. pe ecran).
datele de ieşire apar în ordinea în care au fost făcute
apelurile.
• Dacă sunt implementate canalele de transfer,
prog : altprog • Fiecare fişier sursă care face trimitere la o funcţie de
intrare/ ieşire din bibliotecă trebuie să conţină linia
scrie ieşirea standard a lui prog include <stdio.h>
la intrarea standard a lui altprog. înainte de prima trimitere.
18:00 PCLP CURS 10 73 18:00 PCLP CURS 10 74
• Când numele apare cuprins între < şi >, • Acest lucru este valabil în special dacă se foloseşte
căutarea fişierului antet se efectuează într-un set redirectarea
standard de foldere. pentru a conecta ieşirea unui program la intrarea
următorului.
• Multe programe
citesc numai un singur flux de intrare şi
• De exemplu, consideraţi programul
scriu într-un singur flux de ieşire; litere_mici
care rescrie datele sale de intrare cu litere mici:
• Pentru astfel de programe,
citirea cu getchar şi scrierea cu putchar şi printf
poate fi pe deplin satisfăcătoare,
fiind cu siguranţă suficient pentru început.
18:00 PCLP CURS 10 75 18:00 PCLP CURS 10 76
13
09.11.2016
14
09.11.2016
• Declaraţia corectă pentru printf este • Partea delicată se referă la felul în care funcţia
int printf (char *fmt,…) minprintf parcurge lista de argumente
unde declaraţia “…“ are semnificaţia că atunci când lista nici măcar nu are un nume.
numărul şi tipul acestor argumente poate varia.
• Fişierul antet standard <starg.h> conţine o
• Declaraţia “…“ nu poate apărea decât la sfârşitul colecţie de definiţii de macrouri
unei liste de argumente.
care descriu cum se parcurge o listă de argumente
• Funcţia noastră minprintf este declarată ca
void minprintf(char *fmt, …) • Implementarea acestui fişier antet va fi diferită de
la maşină la maşină,
deoarece nu vom returna numărul de caractere, cum
se întâmplă în cazul lui printf. dar interfaţa pe care o prezintă este uniformă.
18:00 PCLP CURS 10 85 18:00 PCLP CURS 10 86
• Tipul va_list este folosit pentru a declara o • Ultimul argument dintre cele al căror nume se
variabilă care va face referire la fiecare argument pe precizează
rând este folosit de macroul va_start pentru a începe.
în funcţia minprintf, această variabilă se numeşte
pa, • Fiecare apel către va_arg
de la „pointer spre argument“. returnează un argument şi
• Macroul va_start iniţializează variabila pa să indice incrementează pointerul pa
spre primul argument fără nume. astfel încât acesta să indice spre următorul argument
Macroul trebuie apelat o dată înainte ca pa să fie
folosită. • va_arg foloseşte numele unui tip
• Trebuie să existe cel puţin un argument al cărui nume pentru a determina ce tip să returneze şi
să fie precizat cât de mare să fie pasul către următorul argument.
18:00 PCLP CURS 10 87 18:00 PCLP CURS 10 88
#include <stdio.h>
Liste de argumente de lungime variabilă #include <stdarg.h>
/* minprintf: varianta minimala a lui printf cu lista de
argumente variabila */
• În final, va_end elimină ceea ce nu este necesar. void minprintf(char *fmt,…)
{
• Acest macro trebuie apelat înainte ca funcţia să va_list pa;
se încheie. /* indica, pe rand, spre fiecare argument fara nume*/
char *p, *sval;
• Aceste proprietăţi constituie baza variantei int ival;
noastre simplificate a funcţiei printf: double dval;
va_start(pa, fmt);
/* seteaza pa sa indice spre primul argument fara nume */
18:00 PCLP CURS 10 89 18:00 PCLP CURS 10 90
15
09.11.2016
case 'f':
for (p = fmt; *p; p++) {
dval = va_arg(pa, double);
if (*p != ‘%’) { printf(”%f“, dval);
putchar(*p); break;
continue; case 's':
} for (sval = va_arg(pa, char *); *sval; sval++)
putchar(*sval);
switch (*++p){ break;
case 'd': default:
ival = va_arg(pa, int); putchar(*p);
printf("%d", ival); break;
}
break; }
18:00 PCLP CURS 10 91 18:00 PCLP CURS 10 92
va_end(pa);
/* fa curatenie cand totul s-a incheiat */
int main()
{
int a = 9;
float f = 13.99;
char *s="buna ziua";
minprintf("sirul = %s\n",s);
minprintf("intrg = %d\n",a);
INTRARE CU FORMAT - sscanf
minprintf("real = %f\n",f);
return 0;
}
18:00 PCLP CURS 10 93
16
09.11.2016
Accesul la fişiere
• În toate exemplele de până acum
s-a citit de la intrarea standard şi
s-a scris la ieşirea standard,
care sunt definite automat pentru un program de
către sistemul de operare local.
ACCESUL LA FIŞIERE • Următorul pas este scrierea unui program care să
acceseze un fişier
care să nu fie deja conectat la program.
18:00 PCLP CURS 10 100
17
09.11.2016
• Regulile sunt simple. Înainte • Acest pointer (pointer de fişier) indică spre o structură
de a citi din fişier sau care conţine informaţii despre fişier, cum ar fi
de a scrie în acesta, locaţia bufferului,
fişierul trebuie deschis
poziţia caracterului curent din fişier,
prin intermediul funcţiei de bibliotecă fopen.
dacă se citeşte din sau se scrie în fişier şi
• Funcţia fopen dacă au apărut erori
preia un nume extern precum x.c sau y.c, dacă s-a întâlnit sfârşitul de fişier.
efectuează câteva operaţii de economie internă şi
negociere cu sistemul de operare (detalii care nu • Utilizatorii nu au nevoie să cunoască detaliile,
trebuie să ne preocupe) şi deoarece definiţiile obţinute din <stdio.h>
returnează un pointer care să fie folosit la operaţiile includ declaraţia unei structuri, numită FILE.
ulterioare de citire şi scriere în fişier.
18:00 PCLP CURS 10 103 18:00 PCLP CURS 10 104
• Reţineţi că FILE este un nume de tip 2.Al doilea argument este modul,
ca şi int de asemenea un şir de caractere,
nu un nume generic pentru o structură care precizează cum se intenţionează să fie folosit
acesta este definit prin intermediul lui typedef. fişierul.
18:00 PCLP CURS 10 105 18:00 PCLP CURS 10 106
18
09.11.2016
• Există mai multe posibilităţi, dintre care • putc este o funcţie de scriere:
funcţiile getc şi putc sunt cele mai simple. int putc(int c, FILE *pf)
• getc returnează următorul caracter dintr-un fişier
• Funcţia putc scrie caracterul c în fişierul pf şi
aceasta are nevoie de pointerul de fişier pentru a şti
despre ce fişier este vorba. returnează caracterul scris,
int getc(FILE *pf) sau EOF, în cazul în care apare o eroare.
18:00 PCLP CURS 10 109 18:00 PCLP CURS 10 110
• getchar şi putchar pot fi definite în funcţie de • Acestea sunt identice cu scanf şi printf ,
getc, putc, stdin şi stdout astfel: 1. cu excepţia faptului că primul argument
este un pointer de fişier care precizează fişierul
#define getchar() getc(stdin)
din care urmează să se citească sau
#define putchar(c) putc((c), stdout) în care urmează să se scrie;
19
09.11.2016
• Fiind precizate aceste aspecte preliminare, #include <stdio.h> /* cat: concateneaza fisiere, vers. 1 */
main(int argc, char *argv[]){
suntem acum în măsură să scriem programul cat FILE *pf;
care să concateneze fişiere. void copiazafisier(FILE *, FILE*);
if (argc == 1)/* fara argumente; copiaza intrarea standard */
copiazafisier(stdin, stdout);
• Modul de concepţie este unul care s-a dovedit else
potrivit pentru multe programe. while(--argc > 0)
if ((pf = fopen(*++argv, "r")) == NULL){
Dacă există argumente în linia de comandă, printf("cat: nu se poate deschide %s\nf,*argv);
return 1;
acestea sunt interpretate ca nume de fişiere şi }else{
procesate în ordine. copiazafisier(pf, stdout);
fclose(pf);
Dacă nu există argumente, }
return 0;
este procesată intrarea standard. }
18:00 PCLP CURS 10 115 18:00 PCLP CURS 10 116
• Deoarece majoritatea sistemelor de operare impun o • Funcţia fclose este apelată automat pentru
anumită limită fiecare fişier deschis
numărului de fişiere pe care un program le poate atunci când un program se încheie normal.
deschide simultan,
• Puteţi închide stdin şi stdout dacă nu sunt
• este o idee bună să eliberaţi pointerii de fişier
necesare.
atunci când aceştia nu mai sunt necesari,
după cum am procedat în funcţia cat. • Acestea pot fi redeschise prin intermediul funcţiei
de bibliotecă freopen.
• Mai există un motiv pentru folosirea funcţiei fclose
pentru un fişier de ieşire:
goleşte bufferul în care funcţia putc trimite datele de
ieşire.
18:00 PCLP CURS 10 119 18:00 PCLP CURS 10 120
20
09.11.2016
BIBLIOGRAFIE
[1] Kernighan, B., Ritchie, D., The C Programming
Language, ediția a II-a, Ed. Prentice Hall, 1988.
21