Sunteți pe pagina 1din 21

09.11.

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.

• Spre exemplu, declaraţia


typedef int Lungime;
 face numele Lungime sinonim cu int.

typedef  tipul Lungime poate fi folosit în declaraţii, conversii


etc., în exact aceleaşi moduri ca şi tipul int:
Lungime lung, maxlung;
Lungime *lungimi[];
18:00 PCLP CURS 10 4

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

• O situaţie des întâlnită este folosirea numelor typedef


definite cu typedef pentru diferite mărimi
întregi şi apoi 2. A doua utilizare a construcţiilor typedef este
 alcătuirea câte unei colecţii corespunzătoare de să furnizeze o documentaţie mai bună pentru un
variante pentru program
 short, int şi long pentru fiecare maşină
gazdă.
• un tip numit Ptrarbore poate fi mai uşor de
înţeles decât
• Tipuri precum size_t şi ptrdiff_t din
biblioteca standard  unul declarat doar ca un pointer la o structură
complicată.
 constituie astfel de exemple.
18:00 PCLP CURS 10 11 18:00 PCLP CURS 10 12

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.

UNIUNI • Uniunile furnizează o modalitate de a manipula diferite


tipuri de date folosind o singură zonă de memorie,
 fără a introduce informaţii dependente de maşină în
program.
18:00 PCLP CURS 10 14

• Ca un exemplu ce poate fi întâlnit în rutina de Uniuni


gestionare a tabelei de simboluri a unui compilator,
 imaginaţi-vă o constantă ce poate fi • Aceasta este menirea unei uniuni:
 un int,  o singură variabilă care poate în mod legal să
 un float sau stocheze o valoare
 un pointer spre un caracter.  ce poate aparţine oricăruia dintr-o anumită
colecţie de tipuri.
• Valoarea unei anumite constante trebuie stocată într-
union n_nume {
o variabilă aparţinând unui tip corespunzător,
• Sintaxa se bazează int ival;
 dar pentru rutina de gestionare a tabelei este foarte
float fval;
convenabil dacă valoarea pe structuri:
char *sval;
 ocupă la fel de mult spaţiu şi este
}u;
 stocată în acelaşi loc indiferent de tipul său.
18:00 PCLP CURS 10 15 18:00 PCLP CURS 10 16

• Variabila u va fi suficient de voluminoasă Uniuni


 pentru a stoca cel mai voluminos dintre cele trei
tipuri; • Este responsabilitatea programatorului să
 dimensiunea efectivă este dependentă de urmărească
implementare.  ce tip este stocat în uniune la momentul curent

• 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

• Din punct de vedere sintactic, membrii unei if (utip == INT)


uniuni sunt accesaţi astfel printf("%d\n", u.ival);
if (utip == FLOAT)
nume-uniune.membru
printf(”%f\n", u.fval);
• sau
if (utip == SIR)
pointer_spre_uniune -> membru
printf(“%s\n", u.sval);
• la fel ca în cazul structurilor. else
printf("tip necorespunzator %d in utip\n", utip);
• Dacă variabila utip este folosită pentru a ţine
evidenţa tipului curent stocat în u, • Uniunile pot apărea în interiorul structurilor şi
 atunci aţi putea întâlni cod precum: tablourilor şi invers.
18:00 PCLP CURS 10 19 18:00 PCLP CURS 10 20

• Notaţia pentru accesarea unui membru al unei Uniuni


uniuni
• Referinţa la membrul ival se
 aflată în interiorul struct { face astfel
unei structuri (şi char *nume;
invers) int indicatori; tabsim[i].u.ival
 este identică aceleia int utip;
folosite pentru union { • Referinţa la primul caracter al
structurile imbricate. int ival;
şirului sval prin oricare dintre
float fval;
char *sval; expresiile
• Spre exemplu, în
}u; *tabsim[i].u.sval
tabloul tabsim[] de
}tabsim[NSIM]; tabsim[i].u.sval[0]
structuri definit prin:
18:00 PCLP CURS 10 21 18:00 PCLP CURS 10 22

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

• Când spaţiul de stocare este prioritar,


 ar putea fi necesar să împachetăm mai multe
obiecte într-un singur cuvânt de maşină.

CÂMPURI DE BIŢI • O practică des întâlnită este o colecţie de


indicatori pe câte un bit
 folosiţi în aplicaţii precum tabelele de simboluri
ale compilatorului.
18:00 PCLP CURS 10 26

Câmpuri de biţi Câmpuri de biţi


• Formatele de date impuse din exterior, • De exemplu:
 cum ar fi interfeţele cu dispozitivele hardware  dacă este sau nu un cuvânt cheie,
 dacă este sau nu extern şi/sau static
• Au deseori nevoie să acceseze componentele unui
cuvânt.  ş.a.m.d.

• 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

Câmpuri de biţi Câmpuri de biţi


• Modalitatea obişnuită de a realiza acest lucru este • Numerele (01, 02, 04) trebuie să fie puteri ale lui
 de a defini un set de „măşti“ corespunzătoare poziţiilor doi.
de biţi relevante, cum ar fi
• După aceasta, accesarea biţilor devine o problemă
#define CUVCHEIE 01
de „jonglerie la nivel de bit“
#define EXTERN 02  cu operatorii de deplasare,
#define STATIC 04  crearea a unei măşti şi
sau  complementare pe biţi,
enum {CUVCHEIE = 01, EXTERN = 02, STATIC = 04}
• descrişi in Cursul 5, Cap. II.7: Operatori pe biţi.
18:00 PCLP CURS 10 29 18:00 PCLP CURS 10 30

5
09.11.2016

Câmpuri de biţi Câmpuri de biţi


• Anumite expresii apar frecvent: indicatori = indicatori & (~EXTERN & ~STATIC)
indicatori |= EXTERN | STATIC;
 setează la 1 biţii EXTERN şi STATIC din SAU pe biţi
indicatori &= ~ (EXTERN | STATIC)
indicatori
Poziţie bit 3 2 1 0 |  setează la 0 Poziţie bit 3 2 1 0& ŞI pe biţi
indicatori x x x x biţii EXTERN şi indicatori x x x x
EXTERN 02 0 0 1 0 STATIC din ~EXTERN ~02 1 1 0 1
STATIC 04 0 1 0 0 bitul EXTERN indicatori ~STATIC ~04 1 0 1 1
indicatori x 1 1 x Complement indicatori x 0 0 x
faţă de 1 bitul EXTERN
bitul STATIC bitul STATIC
18:00 PCLP CURS 10 31 18:00 PCLP CURS 10 32

Câmpuri de biţi • Deşi aceste expresii sunt bine puse la punct,


 ca alternativă, limbajul C oferă posibilitatea
if ((indicatori & (EXTERN | STATIC)) == 0)  de a defini şi
 a accesa
 este adevărată Poziţie bit 3 2 1 0  direct câmpuri din interiorul unui cuvânt,
dacă ambii biţi
EXTERN 02 0 0 1 0 |  în loc de a folosi operatori logici pe biţi.
(EXTERN şi
STATIC) din STATIC 04 0 1 0 0
indicatori EXTERN | STATIC 0 1 1 0 & • Un câmp de biţi, sau pe scurt: câmp,
au valoarea 0. indicatori x 0 0 x  este un set de biţi alăturaţi din cadrul unei unităţi
indicatori 0 0 0 0 din spaţiul de stocare,
 definită prin implementare,
biţii EXTERN şi STATIC din indicatori
 pe care o vom numi un „cuvânt“.
18:00 PCLP CURS 10 33 18:00 PCLP CURS 10 34

• 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

• Câmpurile sunt atribuite • Câmpurile nu pot fi declarate decât ca fiind de tipul


 de la stânga la dreapta pe unele maşini şi int.
 de la dreapta la stânga pe altele.
• Pentru portabilitate,
• Aceasta înseamnă că deşi câmpurile sunt utile pentru  specificaţi în mod explicit
gestionarea structurilor de date definite intern,  signed sau
 problema de a afla care capăt este primul trebuie luată  unsigned.
serios in considerare
 atunci când doriţi să accesaţi în detaliu date definite • Câmpurile
extern;  nu sunt tablouri şi
• Programele care depind de astfel de lucruri nu sunt  nu au adrese, deci
portabile.  operatorul & nu li se poate aplica.
18:00 PCLP CURS 10 39 18:00 PCLP CURS 10 40

Argumentele liniei de comandă


• În mediile care oferă suport pentru limbajul C
 există o modalitate de a transmite argumente sau
parametri din linia de comandă
 unui program atunci când acesta îşi începe execuţia.

• Când este apelată funcţia main, aceasta este apelată


cu două argumente.
ARGUMENTELE LINIEI DE 1. Primul: argc (argument count = număr de
COMANDĂ argumente)
 este numărul de argumente ale liniei de comandă cu
care a fost invocat programul
18:00 PCLP CURS 10 42

7
09.11.2016

Argumentele liniei de comandă #include <stdio.h>


2. Al doilea argument argv (argument vector = vector /* copiaza argumentele liniei de comanda; prima versiune */
de argumente) int main(int argc, char *argv[])
{
 este un pointer la un tablou de şiruri de caractere care
int i;
conţin argumentele, câte unul în fiecare şir.
for (i = 1; i < argc; i++)
• În mod obişnuit folosim pointeri structuraţi pe mai printf("%s%s", argv[i], (i < argc-1)? ” ” : ””);
multe niveluri,
printf("\n");
 pentru manipularea acestor şiruri de caractere.
return 0;
• Exemplu 1: O ilustrare simplă: programul echo }

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

• În exemplul de mai sus, argc are valoarea 3,


Se rulează
programul și  iar argv[0], argv[1] şi argv[2] sunt
rezultă:
respectiv "echo", "salut " şi "lume".
18:00 PCLP CURS 10 45 18:00 PCLP CURS 10 46

• Primul argument opţional este argv[1] şi Argumentele liniei de comandă


 ultimul este argv[argc-1];
• Deoarece argv este un pointer către un tablou
• în plus, standardul cere ca argv[argc] să fie un
de pointeri,
pointer nul.
 putem lucra cu pointerul în loc să parcurgem
tabloul cu ajutorul indicilor.

• Versiunea următoare se bazează


 pe incrementarea lui argv,
 care este un pointer la un pointer la tipul char,
 în timp ce argc descreşte de fiecare dată cu unu
18:00 PCLP CURS 10 47 18:00 PCLP CURS 10 48

8
09.11.2016

#include <stdio.h> • Fiecare incrementare succesivă (++argv) îl deplasează


/* copiaza argumentele liniei de comanda; a 2-a versiune */ mai departe pe argv către următorul argument
main(int argc, char *argv[])  *argv este în acest caz pointerul către acel argument
{
while (--argc > 0)
• În acelaşi timp, argc este decrementat;
printf("%s%s", *++argv, (argc > 1) ? ” ” : ””);
 când ajunge la valoarea zero, nu a mai rămas nici un
printf("\n"); argument de tipărit.
return 0;
} • Ca alternativă, printf poate fi scris astfel:
• Deoarece argv este un pointer către începutul tabloului printf((argc > 1) ? "%s " : "%s", *++argv);
de şiruri de caractere ce conţin argumente,
 incrementarea acestuia cu 1 (++argv) îl face să indice • Aceasta arată că şi argumentul care se referă la specifi-
spre argv[1] şi nu spre argv[0]. catorul de format din printf poate fi o expresie.
18:00 PCLP CURS 10 49 18:00 PCLP CURS 10 50

• 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

• Primul argument opţional spune „tipăreşte toate • atunci comanda


liniile cu excepţia celor pe care apare sablonul“ gaseste -x -n model
• va tipări fiecare linie pe care nu apare şablonul
• Al doilea argument opţional spune „plasează la
 precedată de numărul său de ordine.
începutul fiecărei linii tipărite numărul său de
ordine“. • Argumentele opţionale ar trebui să fie acceptate în
orice ordine,
• Un argument care începe cu semnul minus  iar restul programului ar trebui să fie independent de
introduce un indicator sau un parametru opţional. numărul de argumente existente.

• Dacă alegem ca -x (de la „excepţie“) să • Pentru utilizatori este convenabil ca argumentele


semnaleze inversiunea şi -n („număr“) să solicite opţionale să poată fi combinate, ca de exemplu
numerotarea liniilor, gaseste -nx model
18:00 PCLP CURS 10 55 18:00 PCLP CURS 10 56

• Iată programul: while (--argc > 0 && (*++argv)[0] == ’-’)


while (c = *++argv[0])
#include <stdio.h>
#include <string.h> switch (c) {
#define MAXLINIE 1000 case 'x': exceptie = 1; break;

int getline(char *linie, int max); case 'n': numar = 1; break;

/* gaseste: tipareste liniile cu sablonul din primul argument */


default:
main(int argc, char *argv[]) printf("gaseste: optiune inexistenta %c\n", c);
{ argc = 0;
char linie[MAXLINIE]; gasit = -l;
long nrlinie = 0;
break;
int c, exceptie = 0, numar = 0, gasit = 0;
}
18:00 PCLP CURS 10 57 18:00 PCLP CURS 10 58

if (argc != 1) • argc este decrementat şi argv este incrementat


printf("Mod de folosire: gaseste -x -n model\n"); înainte de fiecare argument opţional.
else
• La sfârşitul ciclului, dacă nu apar erori,
while (getline(linie, MAXLINIE) > 0){
 argc arată câte argumente au rămas neprocesate şi
nrlinie++;
 argv indică spre primul dintre acestea.
if ((strstr(linie, *argv) != NULL) != exceptie) {
 aşadar, argc ar trebuie să fie 1, iar
if (numar)
 argv ar trebui să indice spre model.
printf("%ld:", nrlinie);
printf("%s", linie); • Observati că *++argv este un pointer la un şir de
gasit++; caractere care conţine un argument,
}
}  deci (*++argv)[0] este primul caracter al şirului.
return gasit;
} • O formă alternativă validă ar fi **++argv.
18:00 PCLP CURS 10 59 18:00 PCLP CURS 10 60

10
09.11.2016

• Deoarece parantezele drepte [] au o precedenţă mai


mare decât a operatorilor * şi ++,
 parantezele () sunt necesare;
 în absenţa acestora, expresia ar fi interpretată ca
*++(argv[0]).

• De fapt, am folosit acest lucru în ciclul exterior,


 unde sarcina era să parcurgem un anumit şir de
caractere care conţinea un argument.
INTRĂRI ŞI IEŞIRI
• În ciclul interior, expresia
++argv[0]
 incrementează pointerul argv[0]
18:00 PCLP CURS 10 61

Intrări şi ieşiri Intrări şi ieşiri


• În continuare vom descrie
• Facilităţile de intrare şi ieşire nu fac parte din  biblioteca standard,
limbajul C în sine.
 funcţii care furnizează facilităţi de intrare şi ieşire,
 de manipulare a şirurilor de caractere,
• Cu toate acestea, programele interacţionează cu
mediul lor  de gestionare a spaţiului de stocare,
 rutine matematice şi
 în moduri mult mai complicate decât cele pe care
le-am prezentat anterior.  o gamă variată de alte servicii pentru programele C.

• Ne vom concentra asupra intrărilor şi ieşirilor.

18:00 PCLP CURS 10 63 18:00 PCLP CURS 10 64

Intrări şi ieşiri
• Proprietăţile funcţiilor din bibliotecă sunt specificate
 în mai mult de 12 fişiere antet

• Am făcut deja cunoştinţă cu câteva dintre acestea,


inclusiv cu
 <stdio.h>,
 <string.h> şi
 <ctype.h>. INTRĂRI ŞI IEŞIRI STANDARD
• Nu vom prezenta întreaga bibliotecă aici,
 deoarece suntem mai interesaţi să scriem programe C
care să o folosească.
18:00 PCLP CURS 10 65

11
09.11.2016

Intrări şi ieşiri standard Intrări şi ieşiri standard


• Cel mai simplu mecanism de citire a datelor de
• Biblioteca implementează un model simplu de intrare este
citire şi scriere a textului.
să citim caracter cu caracter de la intrarea standard
 Un flux de text este format dintr-o secvenţă de
 care este în mod normal tastatura,
linii;
 fiecare linie se termină cu un caracter rând nou.  cu ajutorul funcţiei getchar:
int getchar(void)
• Dacă sistemul nu lucrează în acest mod,
 getchar returnează următorul caracter de la
 biblioteca ia măsurile necesare pentru a face să
intrare de fiecare dată când este apelată,
pară că se întâmplă aşa.
 sau EOF când întâlneşte sfârşitul fişierului.
18:00 PCLP CURS 10 67 18:00 PCLP CURS 10 68

Intrări şi ieşiri standard Intrări şi ieşiri standard


• Constanta simbolică EOF • Dacă un program prog foloseşte funcţia getchar
 este definită în <stdio.h>.  atunci linia de comandă

• Valoarea acesteia este în mod tipic -1, prog <fisierintrare


 dar evaluările ar trebui scrise în funcţie de EOF  face ca prog să citească respectivele caractere din
 nu de -1 fisierintrare
 pentru a fi independente de valoarea efectivă a lui EOF
 în locul situaţiei obişnuite (de la tastatură).
• În multe medii, un fişier se poate substitui tastaturii
 folosind convenţia < • Redirectarea intrării se efectuează în aşa fel încât
 pentru redirectarea intrării:  nici chiar prog însuşi nu este conştient de schimbare
18:00 PCLP CURS 10 69 18:00 PCLP CURS 10 70

• Şirul de caractere <fisierintrare nu este inclus • Funcţia


 printre argumentele liniei de comandă din argv. int putchar(int)
 este folosită pentru scriere:
• Redirectarea intrării este de asemenea invizibilă  putchar(c) scoate caracterul c la ieşirea standard
 dacă intrarea provine dintr-un alt program  care este în mod implicit ecranul.
 printr-un mecanism de tipul canalelor de transfer:
 pe unele sisteme, linia de comandă • Funcţia putchar returnează caracterul scris,
altprog : prog  sau EOF dacă apare o eroare.
execută cele două programe altprog şi prog şi • Din nou, ieşirea poate fi redirectată către un fişier
 transmite ieşirea standard a lui altprog printr-un cu ajutorul comenzii
canal de transfer
 la intrarea standard a lui prog.
>numefişier
18:00 PCLP CURS 10 71 18:00 PCLP CURS 10 72

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

#include <stdio.h> • Funcţia tolower este definită în <ctype.h>;


#include <ctype.h>  aceasta converteşte majusculele în litere mici şi
/* litere_mici: rescrie datele de intrare cu litere mici */  returnează celelalte caractere neschimbate.
main()
{ • După cum am menţionat anterior, „funcţii“
precum
int c;
while ((c = getchar()) != EOF)  getchar şi putchar din <stdio.h> şi
putchar(tolower(c));  tolower din <ctype.h>
return 0;  sunt adesea macrouri,
}  evitându-se astfel consumul mare de resurse din
cazul apelării unei funcţii pentru fiecare caracter.
18:00 PCLP CURS 10 77 18:00 PCLP CURS 10 78

13
09.11.2016

• Indiferent de modalitatea de implementare a


funcţiilor din fişierul antet <ctype.h> pe o
anumită maşină,
 programele care le folosesc sunt ferite de
cunoaşterea setului de caractere.

IEŞIRE CU FORMAT - sprintf

18:00 PCLP CURS 10 79

• Funcţia sprintf realizează aceleaşi conversii ca şi


printf,
 dar stochează rezultatul într-un şir de caractere:

int sprintf (char *sir, char *format, arg1, arg2, …)

• sprintf formatează argumentele din arg1, arg2...


 în conformitate cu format, ca şi înainte,
 dar plasează rezultatul in sir în locul ieşirii standard

• sir trebuie să fie suficient de mare pentru a putea


primi rezultatul.
18:00 PCLP CURS 10 81 18:00 PCLP CURS 10 82

• Această secţiune conţine o implementare a unei


versiuni minimale a funcţiei printf,
 cu scopul de a ilustra cum se scrie o funcţie care
procesează
 o listă de argumente de lungime variabilă într-un mod
portabil.

• Deoarece suntem interesaţi în principal de


procesarea argumentelor, funcţia minprintf
LISTE DE ARGUMENTE DE LUNGIME  va procesa şirul de caractere cu specificatorii de format
VARIABILĂ  va procesa argumentele
 dar va apela adevărată printf pentru a realiza
conversiile de format.
18:00 PCLP CURS 10 84

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

sscanf • Şirul de caractere destinat formatului conţine:


• În afara funcției scanf ca și la funcția printf  specificatori de format care sunt folosiţi pentru a
unde exista sprintf, controla conversia datelor de intrare,
 există de asemenea o funcţie sscanf care citeşte  spaţii sau tabulatori, care sunt ignorate,
dintr-un şir de caractere în locul intrării standard:
 caractere obişnuite (care nu sunt %), care în mod
int sscanf (char *sir, char *format, arg1, arg2,…)
normal
• Aceasta citeşte sir-ul în conformitate cu formatul  corespund următorului caracter din fluxul de
din şirul de caractere format şi intrare, care nu este de tip spaţiu alb.
 stochează valorile rezultate în arg1, arg2 etc.
 specificatori de format
 aceste argumente trebuie să fie pointeri.
18:00 PCLP CURS 10 95 18:00 PCLP CURS 10 96

16
09.11.2016

sscanf while (getline(linie, sizeof(linie)) > 0){


if (sscanf(linie, “%d %s %d", &zi, numeluna, &an) == 3)
/* in forma 25 dec 1988 */
• Pentru citirea datelor de intrare al căror format nu
printf("valid: %s\n", linie);
este fixat,
else if (sscanf(linie, “%d/%d/%d", &luna, &zi, &an) == 3)
 adesea cea mai bună soluţie este să citiţi, pe rând, /* in forma ll/zz/aa */
câte o linie şi printf("valid: %s\n", linie);
 apoi să o recitiţi fragmentat cu sscanf. else
/* forma incorecta */
• Să presupunem că dorim să citim linii care pot printf("incorect: %s\n', linie);
conţine date calendaristice în formele:
25 dec 1988
ll/zz/aa
18:00 PCLP CURS 10 97 18:00 PCLP CURS 10 98

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

Accesul la fişiere Accesul la fişiere


• Un program care ilustrează nevoia unor astfel de
operaţii este cat • Spre exemplu, comanda
cat x.c y.c
 care concatenează o colecţie de fişiere cu nume la
ieşirea standard.  scrie conţinutul fişierelor x.c şi y.c (şi nimic altceva)
la ieşirea standard.
• Programul cat este folosit
 pentru afişarea conţinutului fişierelor pe ecran şi • Întrebarea este ce măsuri trebuie luate pentru a fi
citite fişierele cu nume
 cu rolul de colector general orientat al datelor de
intrare  mai exact cum să se facă legătura între numele externe
 pentru programele care nu au capacitatea de a accesa  la care se gândeşte un utilizator şi
fişierele prin intermediul numelui.  și instrucţiunile care citesc datele.
18:00 PCLP CURS 10 101 18:00 PCLP CURS 10 102

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

• Singura declaraţie necesară pentru un pointer de Accesul la fişiere


fişier este exemplificată în
FILE *pf; • Apelul către funcţia fopen dintr-un program este
FILE *fopen(char *nume, char *mod);
pf = fopen(nume, mod);
• Cele de mai sus precizează că
1.Primul argument al funcţiei fopen
 pf este un pointer spre tipul FILE şi
 funcţia fopen returnează un pointer spre tipul FILE  este un şir de caractere ce conţine numele fişierului.

• 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

Accesul la fişiere • Dacă se deschide pentru operaţii de scriere sau de


adăugare un fişier care nu există,
• Printre modurile permise se numără  acesta este creat, dacă acest lucru este posibil.
 citirea - read ("r"),
• Deschiderea unui fişier existent pentru operaţii de
 scrierea - write ("w") şi scriere duce la pierderea vechiului conţinut,
 adăugarea - append (" a").  în timp ce deschiderea pentru operaţii de adăugare
păstrează conţinutul anterior.
• Unele sisteme fac distincţie între
 fişierele text şi • Încercarea de a citi un fişier care nu există constituie o
eroare,
 fișierele binare;
 dar pot exista şi alte cauze pentru erori,
pentru cele din urmă, trebuie adăugată litera "b" la  cum ar fi încercarea de a citi un fişier atunci când nu
şirul de caractere care specifică modul. aveţi această permisiune.
18:00 PCLP CURS 10 107 18:00 PCLP CURS 10 108

18
09.11.2016

• Dacă apare vreo eroare • Funcţia getc returnează următorul caracter


 funcţia fopen returnează NULL.  din fluxul spre care indică pf;
• Următorul lucru necesar este o modalitate  aceasta returnează EOF
 de a citi din fişier sau  în cazul în care s-a întâlnit sfârşitul de fişier
 de a scrie în acesta o dată ce a fost deschis.  sau a apărut o eroare.

• 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

• La fel ca şi getchar şi putchar, • Cei trei pointerii de fişier corespunzători sunt:


 getc şi putc pot fi macrouri şi nu funcţii. 1. stdin
2. stdout
• Când începe execuţia unui program C, 3. stderr şi
 mediul sistemului de operare are sarcina de a  sunt declaraţi în <stdio.h>
deschide trei fişiere şi
 de a furniza trei pointeri de fişier către acestea. • În mod obişnuit,
 stdin este conectat la tastatură, iar
• Aceste trei fişiere sunt
1. intrarea standard,  stdout şi stderr sunt: conectate la ecran,
2. ieşirea standard şi  dar stdin şi stdout pot fi redirecţionate către
3. ieşirea standard pentru erori;  fişiere sau canale de transfer.
18:00 PCLP CURS 10 111 18:00 PCLP CURS 10 112

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

2. al doilea argument este şirul de caractere care


conţine formatul.
• Pentru citirea sau scrierea cu format din sau în
fişiere, int fscanf(FILE *pf, char *format,…)
 pot fi folosite funcţiile fscanf şi fprintf .
int fprintf(FILE *pf, char *format,…)
18:00 PCLP CURS 10 113 18:00 PCLP CURS 10 114

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

/* copiazafisier: copiaza fisierul ipf in fisierul opf */


• Funcţia
void copiazafisier(FILE *ipf, FILE *opf) int fclose(FILE *pf)
{
int c;  este inversa funcţiei fopen;
while ((c = getc(ipf)) != EOF)
• aceasta întrerupe legătura dintre pointerul de
putc(c, opf); fişier şi numele extern,
}
 legătură care fusese stabilită de fopen,
• Pointerii de fişier stdin şi stdout
 sunt obiecte de tipul FILE *. • eliberând pointerul de fişier pentru a fi folosit de
• Totuşi, aceştia sunt constante, nu variabile, un alt fişier.
 deci nu li se pot atribui valori.
18:00 PCLP CURS 10 117 18:00 PCLP CURS 10 118

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

18:00 PCLP CURS 10 121

21

S-ar putea să vă placă și