note de laborator: c++figura 4 figura 7. aici, din lista situat˘a ˆın partea staˆnga˘, ˆın...

227
Note de laborator: C ++ Vers. 2.0 — Corectat: iunie 2013 Octavian G. Mustafa * e-mail address: [email protected] Cuprins Motivat ¸ie ............................................................... 1 Programe din “viat ¸a real˘ a” ............................................ 10 Alte programe ˆ ın C .................................................... 28 Programare ˆ ın C ++ ..................................................... 63 S ¸i acum? ............................................................ 208 Surse bibliografice .................................................... 219 1 Motivat ¸ie: plecˆ and de la zero. . . ˆ Incepem discut ¸ia cu cˆateva programescriseˆ ın limbajul C. Aceasta pentru c˘a,ˆ ın mediul Internet, exist˘ a mult cod C gratuit pe care ˆ ıl putem adapta nevoilor noastre. Limbajul C ++ este o extensie (un superset) a limbajului C, vezi [41, p. 8], astfel c˘a intruct ¸iunile dintr-un program C “portabil” (vezi POSIX, ANSI C etc., cf. [33], [20, p. 151]) vor funct ¸iona excelent ˆ ın cadrul unui program C ++ . Putem, fire¸ ste, studia limbajul C ++ ˆ ın mod direct, f˘ ar˘ a a apela la C, cf. [42, p. 9], ˆ ıns˘a nu vom face aceasta aici. Se obi¸ snuie¸ ste — ˆ ınc˘art ¸ile blˆ ande cu cititorul — s˘a seˆ ınceap˘ a studiul unui limbaj de programare descriind “cum * Acest eseu nu a fost raportat vreunui referent. ˆ In consecint ¸˘ a, cont ¸inutul s˘au trebuie considerat “ca atare.” ˆ In particular, utilizarea instruct ¸iunilor care urmeaz˘a se face pe r˘aspundereadumneavoastr˘ a. Autorul v˘a a¸ steapt˘ a comentariile la adresa de e-mail de mai sus ¸ siv˘amult ¸ume¸ ste anticipat pentru efortul depus. 1

Upload: others

Post on 31-Jan-2021

4 views

Category:

Documents


0 download

TRANSCRIPT

  • Note de laborator:C++

    Vers. 2.0 — Corectat: iunie 2013

    Octavian G. Mustafa∗

    e-mail address: [email protected]

    Cuprins

    Motivaţie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1Programe din “viaţa reală” . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10Alte programe ı̂n C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28Programare ı̂n C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63Şi acum? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208Surse bibliografice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219

    1 Motivaţie: plecând de la zero. . .

    Începem discuţia cu câteva programe scrise ı̂n limbajul C. Aceasta pentrucă, ı̂n mediul Internet, există mult cod C gratuit pe care ı̂l putem adaptanevoilor noastre. Limbajul C++ este o extensie (un superset) a limbajului C,vezi [41, p. 8], astfel că intrucţiunile dintr-un program C “portabil” (veziPOSIX, ANSI C etc., cf. [33], [20, p. 151]) vor funcţiona excelent ı̂n cadrulunui program C++.

    Putem, fireşte, studia limbajul C++ ı̂n mod direct, fără a apela la C, cf.[42, p. 9], ı̂nsă nu vom face aceasta aici. Se obişnuieşte — ı̂n cărţile blânde cucititorul — să se ı̂nceapă studiul unui limbaj de programare descriind “cum

    ∗Acest eseu nu a fost raportat vreunui referent. În consecinţă, conţinutul său trebuieconsiderat “ca atare.” În particular, utilizarea instrucţiunilor care urmează se face perăspunderea dumneavoastră. Autorul vă aşteaptă comentariile la adresa de e-mail de maisus şi vă mulţumeşte anticipat pentru efortul depus.

    1

  • se vede” acesta din urmă dinspre limbajul cu care cititorul este deja obişnuit,vezi, e.g., [45, pg. 4, 5]. Eu cred ı̂n această abordare . . .

    Programele care urmează sunt scrise folosind mediul de dezvoltare Visual Stu-

    dio sub sistemul de operare Windows XP Professional SP 3, accesibil ı̂n multe săli

    de clasă ori via MSDNAA. De asemeni, ele sunt testate sub Windows 7 Profes-

    sional SP 1 (x86). Menţionez că C-ul de la Microsoft este compatibil cu ediţia

    1990 a ANSI C, cf. [7].

    Construim un director (folder) destinat viitoarelor programe C şi C++,C:\ProiecteleMele_Cpp, după care apelăm Visual Studio-ul, vezi Figura1.

    Figura 1

    Alegem New Project, după care, vezi Figura 2, ı̂n lista Installed Tem-plates, optăm pentru Visual C++. În tabelul central, selectăm Empty Pro-ject. Numele proiectului — ı̂n primul din câmpurile albe din partea dejos a ferestrei (pop-up) New Project — va fi primul_program iar pen-tru a stabili locaţia acestuia ı̂n directorul construit anterior folosim bu-tonul Browse. Ultimul câmp al ferestrei New Project, şi anume Solutionname (soluţia. . . ), va deveni, automat, primul_program. Evident, soluţia —fişierul primul_program.sln din directorul C:\ProiecteleMele_Cpp\primul_program — va permite ı̂n urma unei duble apăsări pe butonul stângal mouse-ului ı̂ncărcarea proiectului nostru ı̂n mediul Visual Studio, indifer-ent dacă acesta este ı̂n execuţie sau nu. Însă aceasta numai după ce vom ficonstruit primul nostru proiect!

    2

  • Figura 2

    Dacă totul este ı̂n ordine, apăsăm butonul OK, vezi Figura 2. Mai departe,ı̂n funcţie de setările mediului Visual Studio, pe ecran vor apărea diferiteferestre ı̂n care scriem cod, respectiv sunt afişate diverse informaţii, veziFigura 3. Folosind butonul View din meniul principal, putem vizualiza —dacă nu au fost setate deja — ferestrele Solution Explorer, Properties,Output, Document Outline, Error List ş.a.m.d. Atenţie, deşi ı̂n Figura 3fereastra centrală este de culoare albă, ceea ce noi vom vedea iniţial va fi unspaţiu de culoare albastru metalizat, ca ı̂n centrul Figurii 4.

    În acest moment, putem introduce fişierele proiectului nostru, şi anumecentru.c şi headerulnostru.h. Pentru aceasta, urmărind Figura 4, nepoziţionăm cu cursorul pe elementul Source Files al listei din fereastraSolution Explorer. Apăsând butonul drept al mouse-ului, remarcăm apari-ţia unei noi ferestre, din care vom selecta elementul Add. Acesta, odatăselectat, va face vizibilă o altă fereastră, ı̂n cadrul căreia vom opta pentruelementul New Item.

    Având cursorul poziţionat pe elementul New Item, apăsăm butonul stângal mouse-ului, ceea ce produce apariţia ferestrei Add New Item primul_program, vezi Figura 5. Aici, selectăm din tabelul central elementul C++ File(.cpp). Urmărind Figura 5, ne deplasăm ı̂n partea de jos a ferestrei activepână la câmpul Name. Acesta va fi completat cu numele ı̂ntreg al fişierului

    3

  • Figura 3

    nostru, adică program.c. Atenţie, dacă nu scriem şi particula .c, fişierulva fi salvat ca program.cpp, adică un fişier cu cod C++. La urma urmei,compilatorul cl.exe care stă ascuns sub capota mediului de dezvoltare VisualStudio este un compilator C/C++! Apoi apăsăm butonul Add.

    Finalizarea cu succes a operaţiei ne conduce la apariţia elementului program.c ı̂n lista Source Files din fereastra Solution Explorer, vezi din nouFigura 3. Reluăm procedeul, vezi Figura 4, plecând de la elementul HeaderFiles din fereastra Solution Explorer, şi alegem, urmărind Figura 5, el-ementul Header File(.h) din tabelul central. Odată ı̂ncheiat acest pas,putem practic trece la scrierea codului. . . din primul nostru proiect VisualStudio.

    Poziţionând cursorul pe elementul headerulnostru.h din fereastra Solu-tion Explorer, apăsăm butonul stâng al mouse-ului, ceea ce va produceapariţia unei zone de culoare albă ı̂n centrul ecranului, vezi Figura 3. Înaintede a scrie primul nostru program — desigur, dacă acest detaliu nu a fostı̂ncă setat —, dorim să numerotăm liniile de cod. Ne va fi mai uşor astfelsă depanăm (debug) programele C/C++. Pentru a activa numerotarea ı̂ncauză, apăsăm butonul Tools din meniul principal al Visual Studio-ului, caı̂n Figura 6. Din fereastra nou apărută, selectăm elementul Options.

    Apăsând butonul Options, producem apariţia ferestrei Options, vezi

    4

  • Figura 4

    Figura 7. Aici, din lista situată ı̂n partea stângă, ı̂n zona de culoare albă,alegem elementul Text Editor, ceea ce va permite vizualizarea unei noiliste de opţiuni. Dintre acestea, alegem elementul C/C++. În acest moment,urmărind Figura 7, putem selecta ı̂n zona Display din partea dreaptă a fere-strei active opţiunea Line numbers. Pentru a salva această alegere, apăsămbutonul OK.

    Acum, revenind la câmpul central de culoare albă cu titlul headerulnostru.h, introducem următoarele linii de cod.

    Un header “utilitar” ı̂n C: headerulnostru.h

    1 #i f !defined( HEADERULNOSTRU )

    2 #define HEADERULNOSTRU

    3 /* ---------------------*/

    4

    5 /* diverse headere:*/

    6 #include

    7 #include

    8 #include

    9 #include

    10 #include

    11

    5

  • Figura 5

    12 /* rutina de incheiere */

    13 #undef LA_REVEDERE

    14 #define LA_REVEDERE \

    15 MessageBox(NULL, \

    16 TEXT("\u00CEncheiem minunatul program ?\t"), \

    17 TEXT("Cutie de dialog"), \

    18 MBOK);

    19

    20 /* ---------------------*/

    21 #endif

    În mod identic, adăugăm ı̂n câmpul program.c codul sursă al programu-lui.

    Primul nostru program ı̂n VS C: program.c

    1 #include "headerulnostru.h"

    2

    3 main(){

    4 pr int f ("\nIncepem ...\n");

    5 LA_REVEDERE

    6 }

    6

  • Figura 6

    Trebuie făcut următorul comentariu vizavi de “ciudata” mea preferinţă pen-tru un element vizual, şi anume MessageBox. Programele C sunt programe “deconsolă” — acel ecran negru. . .—, cu execuţie ı̂ntr-un singur fir1, cf. [20, p. 2],ı̂nsă noi ne aflăm ı̂n Windows, deci consola este numai un proces, cf. [35, p. 88,Chap. 4], denumit cmd.exe, ı̂n cadrul căruia ne manifestăm. Acest proces poate fi“văzut” cu Windows Task Manager. Atunci când rulăm un program ı̂n consolă —o instanţă a cmd.exe —, acesta poate fi observat ı̂n lista de procese afişată de TaskManager. Tehnic vorbind, a opta la punctul de intrare ı̂ntre _tmain şi _tWinMaineste o chestiune de linkare (/SUBSYSTEM:CONSOLE), vezi [35, p. 91]. De aceea,mi-am permis să introduc o modalitate grafică de control ı̂n cadrul programuluimeu C.

    Chestiunea mai multor fire de execuţie — multi-threading — este ı̂ncredinţată

    sistemului de operare (via funcţia CreateThread) ı̂nsă se recomandă utilizarea

    funcţiei Windows C/C++ _beginthreadex— care “ştie” cum să apeleze CreateTh-read. . .—, vezi [35, pg. 182–183, Chap. 6].

    Pentru instrucţiunile de preprocesor , marcate cu # ı̂n codul sursă, amurmat recomandările din [20, pg. 89, 90, 229]. Astfel, pentru a defini unmacro pe mai multe linii se foloseşte caracterul “\”. Pentru concatenareamacrourilor, vezi pagina 162, utilizăm ##.

    Odată salvate fişierele din proiect — vezi butonul “cu diskete” de sub me-niul principal al VS-ului —, dorim să le compilăm. Pentru aceasta, urmărindFigura 8, utilizăm butonul Debug (compilare–cu–corectură) al meniului prin-cipal. În fereastra care va apărea, răspundem la ı̂ntrebarea “This pro-

    1La fel şi programele C++, vezi [41, p. 357].

    7

  • Figura 7

    ject is out of date: Would you like to built it?” apăsând buto-nul Yes.

    Putem folosi butonul F5 pentru a comanda compilarea–cu–corectură aunui program.

    Dacă introducerea codului sursă a decurs fără greşeli, rezultatul acţiuniinoastre este asemănător situaţiei din Figura 9. După ce apăsăm butonul OK,execuţia programului se va ı̂ncheia cu codul 0, vezi Figura 10.

    Pentru diversele opţiuni privind “lansarea oficială” a programului (vari-anta de producţie), folosim butonul Build din meniul central: Clean Solu-tion2, Batch Build — aici apare versiunea Release —, etc.

    În sfârşit, primul nostru program C dezvoltat ı̂n mediul Visual Studio estegata. El se găseşte — primul_program.exe — ı̂n directorul C:\ProiecteleMele_Cpp\primul_program\Debug. Îl lansăm ı̂n execuţie apăsând de douăori butonul stâng al mouse-ului atunci când cursorul este poziţionat pestemica imagine (bitmap) intitulată primul_program.exe, vezi Figura 11.

    Un alt comentariu trebuie făcut ı̂n ı̂ncheierea acestei secţiuni. În multesituaţii, atunci când dezvoltăm un proiect C sub mediul Visual Studio,dorim ca, la sfârşitul execuţiei sale, “consola” programului să rămână de-schisă. . . Pentru aceasta avem mai multe opţiuni, printre care şi introducereaunor elemente vizuale gen MessageBox. Astfel, fie apelăm programul din

    2În Visual C++ 2010 Express, vezi pagina 40, utilizăm butonul Tools şi aici optămpentru Settings/Expert Settings ca să ajungem la Clean Solution.

    8

  • Figura 8

    consolă — via Start/Run/cmd —, fie ı̂nlocuim codul sursă din program.c cuurmătorul set de instrucţiuni.

    O altă vizualizare a aplicaţiei: program.c

    1 #include "headerulnostru.h"

    2

    3 main(){

    4 pr int f ("\nIncepem ...\n");

    5 /* LA_REVEDERE */

    6 getch (); /* din */

    7 }

    Există opinia că apelarea uneia dintre variantele funcţiei getch — o im-plementare a sa folosind getchar poate fi citită ı̂n [20, p. 79] — pentruvizualizarea rezultatelor execuţiei va avea drept efect introducerea unor date“aiurea” ı̂n sistem. Trebuie ı̂nsă observat că, la ı̂ncheierea corectă a pro-cesului primul_program.exe, sistemul de operare, printre altele, va eliberamemoria folosită de firul de execuţie principal, cf. [35, p. 124], deci nu vor

    9

  • Figura 9

    rămâne date ı̂n sistem. . .

    2 Programe din “viaţa reală”

    Îmi pare mai atractiv să ne reamintim câteva elemente ale limbajului Cprin intermediul unor programe utilitare — pe care, la o adică, să le punem latreabă rapid! —. Aceste programe pot fi, evident, ı̂mbunătăţite; de exemplu,ele nu ştiu să revină dintr-o ı̂ntrerupere hardware, cf. [42, p. 133].

    Program:> TEX este un sistem de procesare a textelor ştiinţifice, cu o largă răspândire,vezi [46, 27], una dintre implementările sale fiind platforma TEX Live, cf. [47].Codul sursă al platformei conţine librăria (colecţia) kpathsea, folosită d.ex.la căutarea fişierelor cu fonturi. Programul care ne interesează citeşte primalinie dintr-un fişier text, indiferent de lungimea acesteia. Singura restricţieimediată este ca textul din fişierul ı̂n cauză să se ı̂ncheie cu ENTER — ceeace pare rezonabil dacă ne referim la un fişier al cărui conţinut este un şir decaractere introduse de la tastatură. . .—.

    10

  • Figura 10

    Proiectul VS linie_arbitrara, prezentat ı̂n continuare, modifică mini-mal conţinutul fişierelor line.h, line.c din librăria kpathsea. El este for-mat din fişierele headerulnostru.h, linie.h, centru.c şi linie.c. Fişierultext din care citim este test.txt. El trebuie introdus ı̂n directorul C:ProiecteleMele_Cpp\linie_arbitrara\linie_arbitrara ı̂naintea compilării.

    Am inserat ı̂n codul sursă al proiectului mai multe citate din documentaţia

    on-line a VS-ului, vezi [26]. Deşi numărul de linii de cod se măreşte substanţial,

    dat fiind că proiectul va fi păstrat ı̂n calculator, adaosul este justificat.

    Proiectul linie_arbitrara: linie.h

    1 #i f !defined ( LINIE )

    2 #define LINIE

    3 /* ---------------------*/

    4

    5 #define BLOC_DE_DATE 75

    6

    7 #define MODUL_DEBUG 1

    11

  • Figura 11

    8 /* ---

    9 Daca dorim sa dezactivam modul "debug":

    10 #undef MODUL_DEBUG

    11 ---*/

    12

    13 char * read_line(FILE *);

    14

    15 /* ---------------------*/

    16 #endif

    Proiectul linie_arbitrara: centru.c

    1 #include "headerulnostru.h"

    2 #include "linie.h"

    3 #include

    4

    5 int main(){

    6

    12

  • 7 FILE *studiu = NULL;

    8 char *citire = NULL;

    9 errno t eroare = 0;

    10

    11 pr int f s ("\n+++++++\n"

    12 "Urmatorul program citeste\n"

    13 "linia curenta , oricat de lunga ,\n"

    14 "dintr -un fisier ASCII dat.\n"

    15 "+++++++\ n");

    16

    17 i f ( fopen s (&studiu ,"test.txt","r") != 0){

    18 pr int f s ("Probleme cu cititul fisierului...");

    19 }

    20 e l se {

    21 citire = read_line(studiu);

    22 pr int f s ("\nLinia citita este:\n\n%s",citire);

    23

    24 i f ( f c l o s e (studiu) != 0){

    25 pr int f s ("Probleme cu inchiderea fisierului...");

    26 }

    27 }

    28

    29 f ree ((void *) citire);

    30 get errno (&eroare);

    31 pr int f s ("\n\nEroare: %d\n",eroare);

    32 citire = NULL;

    33

    34 LA_REVEDERE

    35 return 0;

    36 }

    Proiectul linie_arbitrara: linie.c

    1 /* ----

    2 Functia "read_line", descrisa in continuare ,

    3 reprezinta o mica variatie a functiei cu acelasi nume

    4 din fisierul "line.c" al programului "kpathsea ".

    5 (" line.c: return the next line from a file , or NULL",

    6 copyright: Karl Berry , Olaf Weber)

    7 "kpathsea " face parte din distributia "TeX Live"

    8 a sistemului publicistic TeX.

    9 ----*/

    10

    11 #include "headerulnostru.h"

    13

  • 12 #include "linie.h"

    13

    14 char * read_line(FILE *fisier){

    15

    16 int c;

    17 unsigned int limit = BLOC_DE_DATE;

    18 unsigned int loc = 0;

    19 char *line = NULL;

    20 char *intermediar = NULL;

    21

    22 i f (( line = (char *) malloc(limit)) == NULL){

    23 #i f defined( MODUL_DEBUG )

    24 pr int f s ("Probleme de alocare a memoriei ...");

    25 #endif

    26 /* ---------------

    27 "malloc returns a void pointer to the allocated space

    28 or NULL if there is insufficient memory available."

    29 "malloc sets errno to ENOMEM if a memory allocation

    30 fails or if the amount of memory requested exceeds

    31 _HEAP_MAXREQ."

    32

    33 citate de pe:

    34 http:// msdn.microsoft.com/en-us/library /6ewkz86d.aspx

    35 constanta "_HEAP_MAXREQ" se gaseste in ""

    36 ----------------*/

    37 }

    38 e l se {

    39 while (((c = getc (fisier)) != EOF)

    40 && (c != ’\n’) && (c != ’\r’)) {

    41 line[loc] = c;

    42 /*----

    43 optiune: afisam (imediat) caracterul pe ecran...

    44 _putch(c);

    45 ----*/

    46 loc++;

    47 /* ------

    48 Testam daca mai avem spatiu liber.

    49 In caz contrar , adaugam spatiu.

    50 -----*/

    51 i f (loc == limit) {

    52 limit += BLOC_DE_DATE;

    53 i f (

    54 (intermediar = (char *) rea l l oc ((void *)line , limit))

    14

  • 55 == NULL

    56 ){

    57 /*----

    58 "If there is not enough available memory to expand

    59 the block to the given size , the original block is

    60 left unchanged , and NULL is returned ."

    61 "realloc sets errno to ENOMEM if the memory alloca -

    62 tion fails or if the amount of memory requested

    63 exceeds _HEAP_MAXREQ."

    64

    65 citate de pe:

    66 http:// msdn.microsoft.com/en-us/library/xbebcx7d .aspx

    67 ----*/

    68 /*----

    69 Daca suntem aici , nu am terminat de citit linia ,

    70 insa nu mai putem mari memoria alocata citirii.

    71 Eliberam memoria folosita pana acum si iesim...

    72 ----*/

    73 f ree ((void *)line);

    74 line = NULL;

    75 /*----

    76 "is safe (throws away the pointer ’s location )."

    77 citat de pe:

    78 http://en.wikipedia.org/wiki/Malloc

    79 ----*/

    80 #i f defined( MODUL_DEBUG )

    81 pr int f s ("Probleme de (re)alocare "

    82 "a memoriei ...");

    83 #endif

    84 return NULL;

    85 }

    86 e l se {

    87 line = intermediar;

    88 }

    89 }

    90 }

    91 i f (c == EOF) {

    92 i f ( f error (fisier)){

    93 /* -----

    94 "To indicate a read error or end -of-file condition ,

    95 getc returns EOF , and getwc returns WEOF. For getc ,

    96 use ferror or feof to check for an error or for end

    97 of file."

    15

  • 98

    99 citat de pe:

    100 http:// msdn.microsoft.com/en-us/library /5231d02a.aspx

    101 -----*/

    102 /*----

    103 Daca suntem aici , nu am terminat de citit linia ,

    104 insa au aparut erori de citire. Eliberam

    105 memoria folosita pana acum si iesim...

    106 ----*/

    107 f ree ((void *)line);

    108 line = NULL;

    109 #i f defined( MODUL_DEBUG )

    110 pr int f s ("Probleme cu stream -ul citit...");

    111 #endif

    112 return NULL;

    113 }

    114 e l se {

    115 /* -----

    116 Daca suntem aici , am ajuns la capatul fisierului...

    117 Ultima linie nu se poate incheia cu NEWLINE ...

    118 Atentie , daca avem un fisier a carui ULTIMA LINIE

    119 nu se incheie cu ENTER , functia returneaza NULL...

    120 -----*/

    121 f ree ((void *)line);

    122 line = NULL;

    123 }

    124 }

    125 e l se {

    126 /*----

    127 Daca suntem aici , caracterul din stream -ul citit

    128 este fie ’\r’, adica CARRIAGE RETURN (CR), fie ’\n’,

    129 adica NEWLINE (LINE FEED sau LF).

    130 Niciunul nu poate fi vizualizat , deci inlocuim

    131 acest caracter cu "zero".

    132 ------*/

    133 line[loc] = 0;

    134 i f (c == ’\r’) {

    135 /*----

    136 Citim caracterul urmator din stream; exista macar

    137 unul , caci "c != EOF".

    138 ----*/

    139 i f ((c = getc (fisier)) != ’\n’){

    140 i f ( f error (fisier)){

    16

  • 141 f ree ((void *)line);

    142 line = NULL;

    143 #i f defined( MODUL_DEBUG )

    144 pr int f s ("Probleme 2 cu stream -ul "

    145 "citit...");

    146 #endif

    147 return NULL;

    148 }

    149 e l se i f (ungetc(c,fisier) == EOF){

    150 /*----

    151 "If c cannot be pushed back or if no character has

    152 been read , the input stream is unchanged and ungetc

    153 returns EOF; ungetwc returns WEOF."

    154

    155 citat de pe:

    156 http:// msdn.microsoft.com/en-us/library /29hykw2y.aspx

    157 ----*/

    158 f ree ((void *)line);

    159 line = NULL;

    160 #i f defined( MODUL_DEBUG )

    161 pr int f s ("Probleme la refacerea "

    162 "stream -ului citit...");

    163 #endif

    164 return NULL;

    165 }

    166 }

    167 }

    168 }

    169 }

    170

    171 #i f defined( MODUL_DEBUG )

    172 /*----

    173 Afiseaza nr. de caractere citite ...

    174 ----*/

    175 pr int f s ("\nNr. de caractere parcurse :"

    176 "\t%d\n",loc);

    177 #endif

    178 return line;

    179 }

    În cadrul proiectului linie_arbitrara, am presupus că pentru a com-pleta fişierul test.txt nu folosim o tastatură locală, ci ne bazăm doar pecaracterele ASCII — aici, un caracter (char) ı̂nseamnă un octet (byte) —,

    17

  • cf. [20, p. 36], [3]. Această prezumţie este corectă atunci când ne referim laTEX, un sistem publicistic care funcţionează pe tastaturi “limitate”. . . creândcaracterele suplimentare ca metaforme. Însă nucleul Windows NT (versiu-nile 5.1, 5.2 pentru Windows XP, respectiv 6.1 pentru Windows 7, vezi [29])foloseşte sistemul Unicode (UTF16) de notare a caracterelor pentru a facefaţă diverselor alfabete. Fireşte, putem utiliza fără probleme “literele” de unoctet lungime, căci funcţiile Windows vor realiza conversiile necesare ı̂ntreUnicode şi ANSI (Windows-1252, etc), ori de câte ori este necesar, cf. [35,p. 35].

    Am folosit şi un macro “de depanare”, MODUL_DEBUG, complementar luiNDEBUG, vezi [20, p. 254], [41, p. 750].

    Program:> Ilustrez, ı̂n tradiţia K&R [20, p. 9], folosirea caracterelor multi-octet prin-tr-un convertor de temperatură primitiv ı̂n cadrul proiectului Visual Studioconvertor_FC_1. Reamintesc formulele de conversie:

    (C → F ) Fahrenheit =

    (

    Celsius ×9

    5

    )

    + 32,

    respectiv

    (F → C) Celsius = (Fahrenheit− 32)×5

    9.

    Vezi şi [11].În codul sursă, am utilizat o variantă “securizată” a funcţiei sprintf

    din biblioteca C standard, cf. [20, p. 245], respectiv [35, p. 42]. Aceastase numeşte StringCchPrintf, se apelează via şi se găseşteı̂n Windows SDK, vezi [50], care trebuie, evident, instalat ı̂naintea rulăriiproiectului VS — ı̂n momentul testării, versiunea SDK-ului este 7.1 —.

    Proiectul convertor_FC_1: fc1.c

    1 /* ---

    2 Copyright: Octavian , 2011 - -2014

    3 ---*/

    4

    5 #define UNICODE

    6 #define _UNICODE

    7

    8 #include

    9 #include

    10

    11 /* ---

    12 Putem include efectiv "" in lista

    18

  • 13 headerelor (continut in "")

    14 cu conditia ca "" sa fie

    15 inaintea sa.

    16 Macro -uri:

    17 -- TEXT in ""

    18 -- S_OK in "", ""

    19 ---*/

    20

    21 #include /* --- pt. _tmain ---*/

    22 #include /* --- pt. "StringCchPrintf";

    23 ne trebuie Windows SDK...

    24 ---*/

    25

    26 void tmain(){

    27

    28 TCHAR sir[] = TEXT("Temperatura este: 9999 \u00B0C");

    29 s i z e t lungime = countof (sir);

    30 /* ---

    31 in cele patru spatii ocupate de "9999"

    32 introducem valoarea temperaturii...

    33 ---*/

    34

    35 int temperatura_F = 49,

    36 temperatura_C = ( int )

    37 (0.556 * temperatura_F - 32);

    38

    39 i f (

    40 StringCchPrintf(

    41 sir ,

    42 lungime ,

    43 TEXT("Temperatura este: %d \u00B0C"),

    44 temperatura_C

    45 ) != S OK

    46 ){

    47 MessageBox(NULL,

    48 TEXT("StringCchPrintf"),

    49 TEXT("Probleme cu func\u01ABia:"),

    50 MBOK);

    51 exit (EXIT FAILURE);

    52 }

    53

    54 MessageBox(NULL,

    55 sir ,

    19

  • 56 TEXT("Rezultat :"),

    57 MBOK);

    58 exit (EXIT SUCCESS);

    59 }

    60 /*----

    61 Alternatively , the main and wmain functions

    62 can be declared as returning void (no return

    63 value). If you declare main or wmain as

    64 returning void , you cannot return an exit code

    65 to the parent process or operating system by

    66 using a return statement. To return an exit

    67 code when main or wmain is declared as void ,

    68 you must use the exit function .

    69

    70 citat de pe:

    71 http:// msdn.microsoft.com/en-us/library /6wd819wh.aspx

    72 ----*/

    De multe ori, atunci când doresc să deschid un fişier header sau să mălămuresc asupra tipului unei anumite variabile, mă poziţionez cu cursorul pemărimea respectivă (d.ex., size_t) şi apăs butonul drept al mouse-ului, caı̂n Figura 12. Alegând opţiunea Go To Definition, aflu detaliile ı̂n cauză,inclusiv numele fişierului — ori DLL-ul3 — ı̂n care acestea sunt conţinute.

    Program:> A doua variantă a convertorului, ı̂n proiectul convertor_FC_2, testeazădacă avem suficientă memorie pentru manipularea şirului de caractere cetrebuie afişate.

    Proiectul convertor_FC_2: fc2.c

    1 /* ---

    2 Copyright: Octavian , 2011 - -2014

    3 ---*/

    4

    5 #define UNICODE

    6 #define _UNICODE

    7

    8 /* ---

    9 Despre utilizarea macro -urilor

    10 "UNICODE", "_UNICODE "

    11 vezi

    12

    13 Richter , Nassare , Windows via C/C++ 5th Ed., pag. 38

    14 Petzold , Programming Windows 5th Ed., pag. 32

    3Abrevierea de la dynamic link library, vezi, d.ex., [2, pg. 491, 492].

    20

  • Figura 12

    15 ---*/

    16

    17 #include

    18 #include

    19 #include

    20 #include

    21

    22 /* ---

    23 lungimi

    24 ---*/

    25 #undef MAX_LUNGIME

    26 #define MAX_LUNGIME 25

    27

    28 /* ---

    29 un macro pentru erori:

    30 ---*/

    31 #undef EROARE

    32 #define EROARE(text ,cod) \

    33 MessageBox(NULL, \

    34 TEXT(text), \

    35 TEXT("Probleme cu func\u01ABia:"), \

    36 MBOK); \

    37 exit (cod);

    38

    21

  • 39 void tmain(){

    40 TCHAR *sir_larg = NULL;

    41 int temperatura_F = 47,

    42 temperatura_C = ( int )

    43 (0.556 * temperatura_F - 32);

    44

    45 /* ---

    46 Doresc sa manipulez sirul:

    47 "Temperatura este: [maxim 4 cifre] 0C".

    48 Avem 25 de caractere , pe care le rotunjesc

    49 la 30, caci un sir TEXT(...) nu se termina

    50 obligatoriu cu ’\0’...

    51

    52 Vezi si:

    53 http:// msdn.microsoft.com/en-us/library/dd374116 .ց

    (cont.) aspx

    54

    55 sau Petzold , pag. 23

    56 ---*/

    57 i f (

    58 (sir_larg = (TCHAR *) malloc(

    59 (MAX_LUNGIME+5) * s i z eo f (TCHAR)

    60 )

    61 ) == NULL

    62 ){

    63 EROARE("malloc",EXIT FAILURE)

    64 }

    65

    66 /* ---

    67 trunchiem sirul sir_larg si copiem ceva in el...

    68 ---*/

    69 i f (

    70 StringCchPrintf(sir_larg ,

    71 ( s i z e t )MAX_LUNGIME ,

    72 TEXT("Temperatura este: %d \u00B0C"),

    73 temperatura_C

    74 ) != S OK

    75 ){

    76 f ree ((void *) sir_larg );

    77 sir_larg = NULL;

    78 EROARE("StringCchPrintf",EXIT FAILURE)

    79 }

    80

    22

  • 81 MessageBox(NULL,

    82 sir_larg ,

    83 TEXT("Cutie de dialog:"),

    84 MBOK);

    85 f ree ((void *) sir_larg);

    86 sir_larg = NULL;

    87 exit (EXIT SUCCESS);

    88 }

    Program:> Revenind la “literele” de un octet lungime (char), formulez următoareaproblemă a convertorului de temperatură: dorim să citim gradele Fahren-heit (număr real) ı̂ntr-un şir care cuprinde caracterele4

    “ -”, “,”, “ ” (spaţiu gol) şi “ C”.

    De exemplu, temperatura ı̂n Bucureşti, la staţia Băneasa, este:

    32,5 C

    Soluţia dată problemei, ı̂n cadrul proiectului VS convertor_FC_3, pre-supune implementarea a două funcţii: funcţia de conversie “(cifră) −→ (cara-cter)”, numită simbol, şi funcţia de transformare “(număr real) −→ (şir decaractere)”, numită populare.

    Se cuvine să reamintim câteva chestiuni. În primul rând, o dată de tipulchar este, practic, un număr ı̂ntreg mic, cf. [20, pg. 42, 36], — deci aresens operaţia 25 -’g’, cu rezultatul -78 — . De asemeni, literele ’a’, ’b’,’c’, etc. formează un bloc continuu (contiguu) ı̂n setul de caractere ASCII.Acest lucru se poate schimba pentru alte seturi de caractere, deci dorim ofuncţie simbol independentă de poziţia caracterelor ı̂n set. D.ex., funcţiiledin sunt independente de setul de caractere, vezi [20, p. 43]. Adoua chestiune se referă la precizia rezultatului afişat. Se ştie că, atunci cândoperăm cu numere reale, funcţiile de conversie realizează trunchieri/rotunjiriale datelor, pe care dorim să le controlăm, vezi [20, p. 45] pentru operatoriide conversie, respectiv [20, pg. 9, 15] pentru două variante ale convertoruluide temperatură. De acest control va răspunde funcţia populare.

    Proiectul convertor_FC_3: program.c

    1 #include "headerulnostru.h"

    2 #include "convertor.h"

    3 #include

    4Atenţie, am folosit ghilimelele ı̂n sens literar, şi nu. . . informatic. Astfel, ı̂n interiorulunui program, "C" desemneză un şir constant , adică un array terminat ı̂n ’\0’, cf. [20,p. 104].

    23

  • 4

    5 main(){

    6 double fahrenheit = 126.2,

    7 celsius = (fahrenheit - 32)*5/9;

    8 char *citire = NULL;

    9 errno t eroare = 0;

    10 pr int f s ("\n%7.3f\n",celsius);

    11 /*---

    12 7: numar minim de caractere afisate;

    13 3: numar de zecimale afisate ,

    14 vezi Jamsa & Klander , pag. 72, Sect. 68

    15 ---*/

    16 citire = populare(celsius);

    17 pr int f s ("\n%s\n",citire);

    18 /*---

    19 curat memoria ...

    20 testez daca am reusit ...

    21 ---*/

    22 f ree ((void *) citire);

    23 get errno (&eroare);

    24 pr int f s ("\n\nEroare: %d\n",eroare);

    25 citire = NULL;

    26 LA_REVEDERE

    27 }

    Proiectul convertor_FC_3: convertor.h

    1 #i f !defined ( CONVERTOR )

    2 #define CONVERTOR

    3

    4 #undef MODUL_DEBUG

    5 #define MODUL_DEBUG 1

    6

    7 #undef LUNGIME

    8 #define LUNGIME 8

    9 /* ---

    10 numar maxim de caractere:

    11 [minus][ zeci][unitati ][ virgula ][zecimala ][ spatiu][C][ց

    (cont.) incheiere]

    12 ---*/

    13 #undef CELSIUS_MIN

    14 #define CELSIUS_MIN -99

    15 #undef CELSIUS_MAX

    16 #define CELSIUS_MAX 99

    24

  • 17

    18 char simbol( int );

    19 char * populare(double);

    20

    21 #endif

    Proiectul convertor_FC_3: simbol.c

    1 #include "headerulnostru.h"

    2 #include "convertor.h"

    3

    4 char simbol( int cifra){

    5 char rezultat ;

    6 switch(cifra){

    7 case 0: return (rezultat = ’0’);

    8 case 1: return (rezultat = ’1’);

    9 case 2: return (rezultat = ’2’);

    10 case 3: return (rezultat = ’3’);

    11 case 4: return (rezultat = ’4’);

    12 case 5: return (rezultat = ’5’);

    13 case 6: return (rezultat = ’6’);

    14 case 7: return (rezultat = ’7’);

    15 case 8: return (rezultat = ’8’);

    16 case 9: return (rezultat = ’9’);

    17 case 10: return (rezultat = ’-’);

    18 case 11: return (rezultat = ’,’);

    19 default: return (rezultat = ’?’);

    20 }

    21 }

    Proiectul convertor_FC_3: populare.c

    1 #include "headerulnostru.h"

    2 #include "convertor.h"

    3

    4 char * populare(double celsius){

    5 char *sir = NULL;

    6 int contor = 0, iterator = 0;

    7 enum adevar { DA, NU } pozitiv = DA;

    8

    9 /*---

    10 testarea limitelor CELSIUS:

    11 ---*/

    12 i f (( celsius < CELSIUS_MIN)

    13 || (celsius > CELSIUS_MAX)){

    25

  • 14 pr int f s ("Date de intrare "

    15 "incorecte...");

    16 return NULL;

    17 }

    18

    19 i f ((sir = (char *)malloc(

    20 LUNGIME * s i z eo f (char)

    21 )) == NULL){

    22 pr int f s ("Eroare la alocare ...");

    23 return NULL;

    24 }

    25

    26 /*---

    27 testarea valorilor negative pentru CELSIUS:

    28 ---*/

    29 i f (celsius < 0){

    30 celsius = -celsius;

    31 sir[contor ++] = simbol (10);

    32 /* afisam "-" */

    33 pozitiv = NU;

    34 }

    35

    36 /*---

    37 depistam cifra zecilor in CELSIUS:

    38 ---*/

    39 for (iterator = 10; iterator = 0)

    41 && (celsius - iterator < 0)){

    42 sir[contor++] = simbol(( iterator - 10) /10);

    43 celsius += - iterator + 10;

    44 }

    45 }

    46

    47 /*---

    48 depistam cifra unitatilor in CELSIUS:

    49 ---*/

    50 for (iterator = 1; iterator = 0)

    52 && (celsius - iterator < 0)){

    53 sir[contor++] = simbol(iterator - 1);

    54 celsius += - iterator + 1;

    55 }

    56 }

    26

  • 57

    58 /*---

    59 afisam virgula:

    60 ---*/

    61 sir[contor ++] = simbol (11);

    62

    63 /*---

    64 depistam prima zecimala in CELSIUS:

    65 ---*/

    66 celsius *= 10;

    67 /*trecem zecimala in stanga virgulei */

    68 for (iterator = 1; iterator = 0)

    70 && (celsius - iterator < 0)){

    71 sir[contor++] = simbol(iterator - 1);

    72 }

    73 }

    74

    75 /*---

    76 afisam " C" la sfarsitul sirului:

    77 ---*/

    78 sir[contor ++] = ’ ’;

    79 sir[contor ++] = ’C’;

    80

    81 /*---

    82 numere pozitive : compensam lipsa lui "-"

    83 cu un spatiu gol la final...

    84 ---*/

    85 i f (pozitiv == DA){

    86 sir[contor++] = ’ ’;

    87 }

    88

    89 /*---

    90 sirul se termina in null...

    91 ---*/

    92 sir[contor] = ’\0’;

    93

    94 /*---

    95 comparam valoarea contorului cu LUNGIME:

    96 ---*/

    97 i f (contor > LUNGIME){

    98 f ree ((void *)sir);

    99 sir = NULL;

    27

  • 100 pr int f s ("Probleme cu "

    101 "lungimea sirului ...");

    102 return NULL;

    103 }

    104

    105 /*---

    106 dezactivare DEBUG:

    107 #undef MODUL_DEBUG

    108 ---*/

    109

    110 #i f defined ( MODUL_DEBUG )

    111 pr int f ("\n\n++++\n%d\n++++\n",contor);

    112 #endif

    113 return sir;

    114 }

    “Inversa” funcţiei populare, şi anume “(şir de caractere)−→(număr re-al)” este atof din . O implementare a sa se găseşte ı̂n [20, p.71].

    3 Alte programe5 ı̂n C

    Lista funcţiilor CRT (librăria run-time a limbajului C) se găseşte la adresa[12] pe platforma MSDN.

    Când pornim un program scris ı̂n limbajul C, vezi [20, pag. 161], sistemulde operare va deschide trei fişiere — intitulate intrarea standard , ieşirea stan-dard , respectiv eroarea standard — şi ı̂i va transmite programului pointeri(date de tipul FILE *) la acestea: stdin, stdout şi stderr. Pointerii ı̂n cau-ză sunt declaraţi ı̂n . În mod obişnuit, stdin se referă la tastatură,iar stdout şi stderr la ecranului calculatorului. Intrările şi/sau ieşirile potfi ı̂nsă redirecţionate6.

    Program:> Aşa cum ştim, datele introduse de la tastatură sunt caractere ASCII, vezi[18, p. 137, Secţ. 161; p. 515, Secţ. 679]. Ceea ce ı̂nseamnă că programul C“vede” intrările noastre drept şiruri de caractere. Următorul program preiacinci caractere de la tastatură7 şi le afişează pe ecran.

    Citeşte cinci caractere: caract_1.c

    1 /* ---

    2 citeste cinci caractere de la tastatura

    5O recapitulare. . . pe sărite.6În limba engleză, pipe.7Fără taste speciale sau combinaţii de taste (d.ex., CTRL + C).

    28

  • 3 si apoi le afiseaza : o parola

    4 ---*/

    5

    6 #include "headerulnostru.h"

    7 /* ---

    8 : pentru _getch , _putch

    9 : pentru system

    10 ---*/

    11 #undef TESTARE

    12 #define TESTARE 1

    13

    14 int main(void){

    15 int litera ,

    16 contor = 1;

    17 #i fd e f TESTARE

    18 char * tipar();

    19 #endif

    20

    21 system("cls");

    22 pr int f s ("\nTastati parola:\n");

    23 for (; contor++

  • ficarea listei acestora, cf. [20, p. 33]. Compilatorul din Visual Studio poateemite un avertisment (Warning: too many arguments in function call), da-

    că folosim argumentele 9, respectiv 10,"test" ı̂n apelul funcţiei tipar.

    Program:> Funcţia tipar din proiectul anterior ignoră parametrii daţi de noi. Înprogramul de mai jos, vom ilustra o situaţie aflată “la polul opus”, şi anumefuncţia sumare, care ţine seama de un număr variabil de parametri. În de-claraţia sa, folosim obligatoriu cel puţin un argument obişnuit iar la finalelipsa8, “. . . ”, pentru a ne referi la argumentele ı̂n număr variabil, vezi [20,p. 155]. Pentru a implementa funcţia sumare — care returnează suma unuinumăr variabil de numere, respectând formatul acestora (int, double) —,folosim tipul de date va_list — adică, char * — definit ı̂n ,respectiv macrourile va_start, va_arg şi va_end din .

    Ilustrarea elipsei: elli0.c

    1 #include "headerulnostru.h"

    2 #include

    3 /* ---

    4 pt. va_start , va_arg , va_end;

    5 in , inclus , se gaseste va_list

    6 ---*/

    7 /* ---

    8 pre -ANSI: , actual "deprecated".

    9 Acest header este folosit inca pentru compatibilitate

    10 cu sistemele UNIX V, vezi:

    11 http:// msdn.microsoft.com/en-us/library/kb57fad8 .aspx

    12 http:// msdn.microsoft.com/en-us/library/we9107a3 .aspx

    13 ---*/

    14

    15

    16 #undef DEBUG

    17 #define DEBUG 1

    18 #undef ERORI

    19 #define ERORI(texta ,textb ,textc) \

    20 pr int f s ("\nEroare de format!\n" \

    21 "Grupuri corecte: %d\n", \

    22 texta); \

    23 pr int f s ("Suma este , pana aici: %f\n", \

    24 textb); \

    25 pr int f s (textc);

    26

    27

    8În limba engleză, ellipsis .

    30

  • 28 typedef enum valori {NUMAR , EROARE} controlul_erorii;

    29

    30 int main(){

    31 controlul_erorii sumare(char *, ...);

    32

    33 /*---

    34 sumam primele patru numere din lista de intrari ,

    35 conform formatului lor:

    36 "%d" --- numar intreg ,

    37 "%f" --- numar cu virgula (double)

    38 ---*/

    39 sumare("%f%d%d%d" ,23.0,2,-100,4,"altceva" , -400.67);

    40

    41 /*---

    42 recomandare MSDN:

    43 folosirea operatorilor de cast pentru un format corect

    44 ---*/

    45 sumare("%d%f",( int )23.67, -0.5);

    46

    47 LA_REVEDERE

    48 return 0;

    49 }

    50

    51 controlul_erorii sumare(char *format , ...){

    52 char *sir = format;

    53 /*---

    54 date pentru controlul formatului

    55 ---*/

    56 int contor_procent = 0,

    57 contor_intreg = 0,

    58 contor_real = 0,

    59 contor_grup = 0;

    60 double suma = 0.0;

    61

    62 /*---

    63 introducem un pointer (char *)

    64 la sirul argumentelor in numar variabil ,

    65 si il pozitionam la primul dintre acestea

    66 ---*/

    67 va l i s t argumente_fara_nume;

    68 va start (argumente_fara_nume ,format);

    69

    70 /*---

    31

  • 71 analiza formatului

    72 ---*/

    73 for (;*sir != ’\0’;){

    74 i f (*sir++ != ’%’){

    75 #i fd e f DEBUG

    76 ERORI(contor_grup ,suma ,

    77 "Grupul nu incepe cu \"%%\"...")

    78 #endif

    79 /*---

    80 eliberam pointerul la sirul argumentelor

    81 ---*/

    82 va end(argumente_fara_nume);

    83 return EROARE;

    84 }

    85 i f (*sir == ’d’){

    86 contor_intreg++;

    87 suma += va arg(argumente_fara_nume , int );

    88 }

    89 i f (*sir++ == ’f’){

    90 contor_real++;

    91 suma += va arg(argumente_fara_nume ,double);

    92 }

    93 contor_grup++;

    94

    95 /* ---

    96 daca apare alta litera dupa %

    97 ---*/

    98 i f (

    99 contor_grup != (contor_intreg + contor_real)

    100 ){

    101 #i fd e f DEBUG

    102 ERORI(contor_grup -1,suma ,

    103 "Grupul nu contine: d, f ...")

    104 #endif

    105 va end(argumente_fara_nume);

    106 return EROARE;

    107 }

    108 }

    109 #i fd e f DEBUG

    110 pr int f s ("\nStatistici:\n"

    111 "grupuri \"%%d\" %d\n"

    112 "grupuri \"%%f\" %d\n",

    113 contor_intreg ,contor_real);

    32

  • 114 #endif

    115 pr int f s ("\nSuma este: %f\n",suma);

    116 va end(argumente_fara_nume);

    117 return NUMAR;

    118 }

    Program:> Următorul program manipulează diferenţiat caracterele scrise ı̂n consolă:dacă ı̂ntâlneşte litera “z”, programul va trece pe rândul următor, iar dacăapăsăm ENTER execuţia se opreşte. Vezi [18, p. 226; Secţ. 294].

    Citire diferenţiată: caract_2.c

    1 /* ---

    2 citeste caracterele de la tastatura ,

    3 daca intalneste "z"-ul, trece pe un rand nou

    4 iar daca apasam ENTER se opreste

    5 ---*/

    6 #include "headerulnostru.h"

    7

    8 int main(void)

    9 {

    10 int litera;

    11 system("cls");

    12 do{

    13 litera = getch();

    14 i f (litera != ’z’)

    15 putch(litera);

    16 e l se

    17 pr int f s ("\n");

    18 }

    19 while (litera != ’\r’);

    20 LA_REVEDERE

    21 return 0;

    22 }

    Program:> Afişarea caracterelor “speciale” se face ı̂n limbajul C cu ajutorul carac-terului escape “\”. Programul care urmează conţine caracterele: “\n” – linienouă, “\t” – tabulator orizontal, “\r” – returnare de car, “\"” – apostrof,“\\” – backslash, “\?” – semnul ı̂ntrebării. Vezi şi [18, p. 75; Secţ. 74].

    Caractere cu escape: caract_3.c

    1 /* ---

    2 caractere speciale in C (cu escape)

    3 ---*/

    4

    33

  • 5 #include "headerulnostru.h"

    6

    7 int main(void){

    8 int numar = pr int f s ("as\nft\tfds\t\\\ns\nd\?\"sss"

    9 "ss\nwerfggggu\ryyy\n");

    10 pr int f s ("\nSirul are %d caractere.",numar);

    11 LA_REVEDERE

    12 return 0;

    13 }

    Program:> Importanţa caracterului escape este relevată de un program care realizeazăurmătoarele sarcini: (i) crează directorul C:\Diverse Programe ı̂n sistemulde fişiere; (ii) crează/verifică dacă există fişierul incercare.txt ı̂n folderulC:\ProiecteleMele_Cpp\nume_proiect\nume_proiect; (iii) copiază acestfişier ı̂n noul director; (iv) introduce ı̂n copie litera “D”. De asemeni, pen-tru un mai bun control vizual al erorilor, am utilizat funcţia GetACP din. Aceasta ne dă informaţii despre setul de caractere specialedisponibil ı̂n calculator.

    Introducerea unui fişier ı̂n sistem: man_fis00.c

    1 #define UNICODE

    2 #define _UNICODE

    3

    4 #include "headerulnostru.h"

    5

    6 /* ---

    7 macrouri de eroare , avertizare:

    8 ---*/

    9 #undef EROARE

    10 #define EROARE(text ,cod) \

    11 MessageBox(NULL, \

    12 TEXT(text), \

    13 TEXT("Mesaj de eroare:"), \

    14 MBOK); \

    15 exit (cod);

    16 #undef MESAJ

    17 #define MESAJ(text) \

    18 MessageBox(NULL, \

    19 TEXT(text), \

    20 TEXT("Cutie de dialog"), \

    21 MBOK);

    22

    23 /* ---

    24 versiunea OS:

    34

  • 25 WX: Windows XP SP3 (Windows -1252 code page)

    26 W7: Windows 7 SP1 (Windows -1250 code page)

    27 ---*/

    28 #undef WX

    29 #define WX 1

    30

    31 #undef W7

    32

    33 int main(void)

    34 {

    35 FILE *fisier = NULL;

    36

    37 /*---

    38 construiesc directorul

    39 ---*/

    40 system("cls & "

    41 "mkdir \"C:\\ Diverse Programe \"");

    42 #i fd e f WX

    43 MESAJ("F\u00E3cut!")

    44 #endif

    45 #i fd e f W7

    46 MESAJ("F\u0103cut!")

    47 #endif

    48 {

    49 /*---

    50 Atentie la codurile de pagina Windows (pt. caractere):

    51 http:// msdn.microsoft.com/en-us/library/dd317752 .aspx

    52 ---*/

    53 # include

    54 pr int f s ("\n\nCodul paginii este: %d\n\n",

    55 ( int ) GetACP());

    56 }

    57

    58 /*---

    59 testez fisierul "incercare.txt"

    60 ---*/

    61 i f ( fopen s (&fisier ,"incercare.txt","a+") != 0){

    62 EROARE("Eroare la deschidere \" incercare.txt\"!\n",

    63 EXIT FAILURE)

    64 }

    65 i f ( f c l o s e (fisier) != 0){

    66 EROARE("Eroare la inchidere \" incercare.txt\"!",

    67 EXIT FAILURE)

    35

  • 68 }

    69

    70 /*---

    71 copiez fisierul

    72 ---*/

    73 system(

    74 "copy incercare.txt /A \"C:\\ Diverse Programe \" /A"

    75 );

    76

    77 /*---

    78 inserez caracterul "D"

    79 ---*/

    80 i f ( fopen s (&fisier ,

    81 "C:\\ Diverse Programe \\ incercare.txt","a+") != 0){

    82 EROARE("Eroare la creare/deschidere!\n",

    83 EXIT FAILURE)

    84 }

    85 fputc(’D’,fisier);

    86 i f ( f c l o s e (fisier) != 0){

    87 EROARE("Eroare la inchidere!",EXIT FAILURE)

    88 }

    89

    90 LA_REVEDERE

    91 return 0;

    92 }

    Să presupunem că avem deja câteva programe scrise ı̂n limbajul C. Înmulte cazuri, dorim să rulăm aceste programe din afara consolei . Reamintescfaptul că, tastând grupul de comenzi ALT + ENTER, consola activă se va ı̂ntinde

    ı̂n 1-2 secunde la ı̂ntreg ecranul calculatorului. Consola va reveni la dimensiunile

    obişnuite dacă repetăm grupul de comenzi.

    Program:> În programul următor, folosim câteva funcţii Windows dedicate consolei,cf. [10], pentru a interacţiona cu aceasta. În sistemele de operare Windows,consola reprezintă numai un proces, adică o instanţă a unui program ı̂n execuţie

    formată dintr-un obiect-nucleu şi un spaţiu de adrese, vezi [35, p. 88, Chap. 4].

    Schimbarea titlului consolei: consola00.c

    1 /* ---

    2 Copyright: Octavian , 2011 - -2014

    3 ---*/

    4

    5 #include "headerulnostru.h"

    6

    36

  • 7 /* ---

    8 lungimea unui sir de caractere

    9 ---*/

    10 #undef MARIME

    11 #define MARIME 300

    12

    13 /* ---

    14 macrouri de eroare , memorie:

    15 ---*/

    16 #undef EROARE

    17 #define EROARE(text) \

    18 pr int f s (text); \

    19 LA_REVEDERE \

    20 exit (EXIT FAILURE);

    21 #undef LIBER

    22 #define LIBER(nume) \

    23 f ree ((void *)nume); \

    24 nume = NULL;

    25

    26 int main(){

    27 int litere ,

    28 contor = 0;

    29 char *titlu_vechi = NULL,

    30 *titlu_nou = "Consola de lucru";

    31 /* ---

    32 date de tip Windows

    33 ---*/

    34 DWORD cat_am_scris = 10000L;

    35 HANDLE maner = NULL;

    36

    37 /*---

    38 aloc spatiu pentru citit titlul consolei

    39 ---*/

    40 i f (

    41 (titlu_vechi =

    42 (char *) malloc(MARIME * s i z eo f (char))) == NULL

    43 ){

    44 EROARE("Probleme de alocare ...")

    45 }

    46

    47 /*---

    48 caut consola in registru ...

    49 ---*/

    37

  • 50 i f (

    51 ((maner = GetStdHandle(STDOUTPUTHANDLE))

    52 == INVALIDHANDLEVALUE)

    53 /* --- functie din ---*/

    54 || (maner == NULL)

    55 ){

    56 LIBER(titlu_vechi)

    57 EROARE("Probleme de maner...")

    58 }

    59

    60 system("cls");

    61 /*---

    62 citesc , modific titlul consolei

    63 cu functii din

    64 ---*/

    65 i f (!GetConsoleTitleA ((LPSTR) titlu_vechi ,

    66 (DWORD) MARIME * s i z eo f (char) -1)

    67 ){

    68 LIBER(titlu_vechi)

    69 EROARE("Probleme de citit titlul ...")

    70 }

    71 pr int f s ("\n\nVechiul titlu al consolei este:\n"

    72 "\"%s\""

    73 "\n\nNoul titlu al consolei este:\n",

    74 titlu_vechi);

    75 i f (!SetConsoleTitleA(titlu_nou)){

    76 LIBER(titlu_vechi)

    77 EROARE("Probleme de resetare a titlului ...")

    78 }

    79

    80 /*---

    81 scriu in consola cu o functie Windows

    82 ---*/

    83 i f (!WriteConsoleA(maner ,

    84 (const void *)titlu_nou ,

    85 (DWORD) countof ("Consola de lucru"),

    86 &cat_am_scris ,

    87 NULL)

    88 ){

    89 LIBER(titlu_vechi)

    90 EROARE("Probleme de scriere ...")

    91 }

    92

    38

  • 93 pr int f s ("\n\n+++++++\ n"

    94 "Adaugati trei litere:\n\n");

    95 for (;

    96 contor++ O metodă simplă de rulare, indepedent de consolă, a unor programe ex-ecutabile — nume_program.exe — constă ı̂n utilizarea unor fişiere batch(de comenzi), cf. [4], — comenzi.bat —. Presupunând că, ı̂n directorulC:\Proiectele Mele_Cpp, aducem fişierul caract_3.exe, vezi pagina 33,extras din subdirectorul Debug al proiectului VS respectiv, scriptul batch demai jos — salvat temporar pe ecranul calculatorului, C:\Documents and Settings\Octavian\Desktop — ı̂i comandă execuţia.

    Controlul execuţiei: nume_program.bat

    1 @echo o f f

    2 set cale_fisiere=C:\ProiecteleMele_Cpp

    3 cd %cale_fisiere%

    4 nume_program.exe

    5 :: inlocuim "nume_program" cu "caract_3 "

    6 :: avem si comanda alternativa:

    7 :: start /wait /b nume_program.exe

    8 :: vezi http://ss64.com/nt/start.html

    9 ca l l cmd

    10 :: ramane consola deschisa

    11 ::se tasteaza "exit" pt. iesire

    Program:> Rezultatul execuţiei programului caract_3.exe poate fi redirectat cătreun fişier, d.ex. rezultat_caract_3.txt, din acelaşi director, folosind oper-atorul “>”. Vezi [20, p. 152].

    Redirectarea rezultatului: caract_31.bat

    1 @echo o f f

    2 set cale_fisiere=C:\ProiecteleMele_Cpp

    3 cd %cale_fisiere%

    4 caract_3.exe > rezultat_caract_3.txt

    5 notepad rezultat_caract_3.txt

    39

  • 6 ca l l cmd

    7 ::se tasteaza "exit" pt. iesire

    Program:> Un exemplu mai elaborat este scriptul batch prin intermediul căruia putemutiliza programul Microsoft Visual C++ 2010 Express (VC++) — gratuit,distribuit independent de VS, cf. [49] —

    Codul sursă pentru batch-ul VC++

    1 @echo o f f

    2 :: variabile pentru VC++ si cmd

    3 set cale_principala=C:\Program Files

    4 set versiune =\ Microsoft Visual Studio 10.0

    5 set drum_exec=\ Common7\IDE

    6 set cale_vis=%cale_principala%%versiune%%drum_exec%

    7 set help_vis_cont=/en-us/library/60k1461a.aspx

    8 set help_vis=http://msdn.microsoft.com%help_vis_cont%

    9 set cale_browser=C:\Program Files\Mozilla Firefox

    10 set consola=C:\WINDOWS\system32

    11 :: sfarsit variabile

    12 :: folderul de proiecte

    13 echo.

    14 set cale_fisiere=C:\ProiecteleMele_Cpp

    15 set treaba=mkdir %cale_fisiere%

    16 set mesaj=Creat folderul de proiecte "ց

    (cont.) ProiecteleMele_Cpp"!

    17 i f not exist %cale_fisiere% (%treaba% & echo %mesaj%)

    18 :: sfarsit operatii folderul de proiecte

    19 chdir %cale_fisiere%

    20 start explorer %cale_fisiere%

    21 path=%path%;%consola%;%cale_vis%;%cale_browser%

    22 echo.

    23 echo Pentru Visual C++ Express , tastati: VCExpress

    24 echo.

    25 echo Pentrul "aplicatiile de consola", folositi ց

    (cont.) comanda:

    26 echo "cd.\ NumeleProiectului\Debug", dati "Enter" si ց

    (cont.) apoi

    27 echo tastati: "NumeleProiectului.exe". Pentru a reveni

    28 echo la folderul de proiecte , tastati:

    29 echo "cd.. & cd..".

    30 echo.

    31 echo Succes!

    32 start firefox %help_vis%

    33 echo. & ca l l cmd

    40

  • Program:> Putem rula fişierul caract_31.bat, vezi pagina 39, şi dintr-un proiect VS.Astfel, presupunând că avem proiectul gol octombrie_31_2011 ı̂n directorulde lucru, introducem ı̂n subdirectorul cu acelaşi nume fişierele caract_31.bat şi caract_3.exe — calea completă până la fişiere trebuie să fie C:\ProiecteleMele_Cpp\octombrie_31_2011\octombrie_31_2011 — . Codul ı̂nlimbajul C de care avem nevoie este listat ı̂n continuare.

    Fişiere de comenzi: consola01.c

    1 #include "headerulnostru.h"

    2

    3 int main(void){

    4 system("caract_31.bat");

    5 LA_REVEDERE

    6 return 0;

    7 }

    Motivaţia proiectului anterior este următoarea: atunci când dorim intrarea ı̂n

    execuţie, ı̂ntr-o ordine prestabilă, a mai multor fişiere executabile, putem folosi

    această cale mixtă pentru a evita complicaţiile procese-părinte – procese-copil ori

    introducerea mai multor fire de execuţie, vezi [35], [18, p. 561].

    Program:> Funcţia system din transmite, aşadar, linia de comandă aunui proces către interpretorul cmd.exe, cf. [8]. Aici, trebuie să avem grijăla modul cum sunt procesate caracterele “speciale” — parsarea argumentelorunei comenzi, tokenizarea lor —. În programul următor, folosim secvenţele“\"”, respectiv “^&” pentru o transmitere corectă a acestor argumente.

    Linia de comandă: consola02.c

    1 #include "headerulnostru.h"

    2

    3 int main(void){

    4 pr int f s ("\nDe dimineata...\n"

    5 "Ziare locale si nationale ,\n"

    6 "schimb valutar ...\n");

    7 system("\"C:\\ Program Files\\Mozilla Firefox"

    8 "\\ firefox.exe\""

    9 " http://www.gds.ro"

    10 " http://www.romanialibera.ro"

    11 " http://www.xe.com/currencycharts/"

    12 "?from=EUR^&to=USD^&view=1D");

    13

    14 LA_REVEDERE

    15 return 0;

    16 }

    41

  • Program:> Funcţia Windows GetCommandLineW din ı̂ntoarce un pointerla bufferul ce conţine ı̂ntreaga linie de comandă, cf. [35, p. 97; Chap. 4].Vezi codul C următor.

    Linia de comandă: consola03.c

    1 #define UNICODE

    2 #define _UNICODE

    3 #include "headerulnostru.h"

    4

    5 int main(void){

    6 PWSTR linia_de_comanda = GetCommandLineW();

    7 /*---

    8 din

    9 ---*/

    10 MessageBox(NULL,linia_de_comanda ,

    11 TEXT("Rezultat :"),MBOK);

    12 LA_REVEDERE

    13 return 0;

    14 }

    Program:> Următorul proiect se ocupă de căutarea unor cuvinte ı̂ntr-un dicţionar on-line al limbii române. Acestea sunt precizate ı̂n linia de comandă, cu careprogramul interacţionează prin intermediul funcţiei main, cf. [20, p. 114],[18, p. 510; Secţ. 669]. Rutinele din program pot fi realizate şi cu funcţii din, d.ex. strcat_s, strncat_s.

    Linia de comandă: consola04.c

    1 /* ---

    2 Un program primitiv de cautare

    3 in dictionarul on-line al limbii romane:

    4 http:// dexonline.ro

    5 -------------------

    6 sintaxa:

    7 consola04 [cuvant]

    8 -------------------

    9 Termenul [cuvant] este optional .

    10 Cuvantul cautat poate avea

  • 18 #define SPATII_GOALE 40

    19

    20 /* ---

    21 macrouri debugging:

    22 ---*/

    23 #undef DEBUG

    24 #define DEBUG 1

    25 /* #undef DEBUG */

    26 #undef EROARE_A

    27 #define EROARE_A (text) \

    28 pr int f s (text); \

    29 exit (EXIT FAILURE);

    30 #undef EROARE

    31 #define EROARE(text ,pointer) \

    32 pr int f s (text); \

    33 f ree ((void *) pointer); \

    34 pointer = NULL; \

    35 exit (EXIT FAILURE);

    36 #undef SUCCES

    37 #define SUCCES(pointer) \

    38 LA_REVEDERE \

    39 f ree ((void *) pointer); \

    40 pointer = NULL; \

    41 exit (EXIT SUCCESS);

    42

    43 #include "headerulnostru.h"

    44

    45 void main( int argc , char *argv[])

    46 {

    47 char *comanda_baza = "\"C:\\ Program Files\\ Mozilla ց

    (cont.) Firefox \\firefox.exe\" http:// dexonline.ro/",

    48 *supliment = "definitie/",

    49 *buffer = NULL,

    50 *citirea_cuvantului = "standard ";

    51 int contor = 0,

    52 iterator = 0;

    53

    54 i f (

    55 COMANDA_MAXIMA

  • 60 EROARE_A(" ")

    61 #endif

    62 }

    63

    64 /*---

    65 rezervam memorie pentru linia de comanda "buffer":

    66 ---*/

    67 i f (

    68 (buffer = (char *) ca l l oc (COMANDA_MAXIMA , s i z eo f (char)))

    69 == NULL

    70 ){

    71 #i fd e f DEBUG

    72 EROARE_A("\nEroare memorie!")

    73 #else

    74 EROARE_A(" ")

    75 #endif

    76 }

    77

    78 /*---

    79 organizarea liniei de comanda:

    80 ---*/

    81 for (;* comanda_baza != ’\0’;){

    82 buffer[contor++] = *comanda_baza++;

    83 }

    84 #i fd e f DEBUG

    85 pr int f s ("contor 1: %d\n",contor);

    86 #endif

    87

    88 for (;* supliment != ’\0’;){

    89 buffer[contor++] = *supliment++;

    90 }

    91 #i fd e f DEBUG

    92 pr int f s ("contor 2: %d |%c|\n",

    93 contor ,buffer[contor -1]);

    94 #endif

    95 i f (COMANDA_REZERVA != contor){

    96 #i fd e f DEBUG

    97 EROARE("\nProbleme de iterare ...",buffer)

    98 #else

    99 EROARE(" ",buffer)

    100 #endif

    101 }

    102

    44

  • 103 /*---

    104 adaugam SPATII_GOALE spatii goale...

    105 aici va fi copiat cuvantul ce trebuie

    106 cautat in dictionar

    107 ---*/

    108 for (; iterator

  • 146 buffer[COMANDA_REZERVA + contor ++]

    147 = *citirea_cuvantului++;

    148 }

    149 i f ( pr int f s ("\nAdresa :\n%s\n",buffer) < 0){

    150 #i fd e f DEBUG

    151 EROARE("\nNu pot afisa adresa ...",buffer)

    152 #else

    153 EROARE(" ",buffer)

    154 #endif

    155 }

    156 system(buffer);

    157 SUCCES(buffer)

    158 }

    Program:> Tratarea erorilor 9 este o parte importantă a oricărui proiect VS, [20, p.164]. Lăsând la o parte chestiunea dificilă a ı̂ntreruperilor hardware care potsurveni pe parcursul execuţiei codului C, vezi [37], ı̂n programul de mai josfolosim funcţiile signal şi raise din pentru a organiza ieşireadin ı̂ntrerupere, reluarea execuţiei. Aici, vom activa valoarea SIGILL, [20, p.255], a semnalului de ı̂ntrerupere emis de sistemul de operare — neutilizatăde Windows — pentru a ı̂ncălca recomandarea MSDN [38] de a nu folosifuncţii de tip printf atunci când nu cunoaştem starea10 operaţiei run-time.

    Întreruperi: eh00.c

    1 #include

    2 #include

    3 #include

    4 #include /* semnalarea erorii*/

    5

    6 void main(){

    7 int numar = SIGILL,

    8 /*---

    9 codul erorii: instructiune ilegala

    10 ---*/

    11 caracter = 0;

    12 void actiune( int );

    13 /*---

    14 handlerul erorii;

    15 va fi apelat in cazul producerii erorii ...

    16 ---*/

    17

    9În limba engleză, error handling.10Cf. [20, p. 244], intrucţiunea printf(...) este echivalentă cu fprintf(stdout,...).

    46

  • 18 pr int f s ("\nSalut!\n"

    19 "Pentru a incheia , tastati ’x ’:\t");

    20 while(( caracter = getch()) != ’x’){

    21 s igna l (numar ,actiune);

    22 /*---

    23 semnalarea erorii:

    24 daca se produce , atunci va fi apelat handlerul;

    25 acestuia i se va transmite parametrul numar...

    26 ---*/

    27 ra i se (numar); /* producerea erorii */

    28 pr int f s ("\nReluati operatia !\n"

    29 "Pentru a incheia , tastati ’x ’:\t");

    30 }

    31 exit (EXIT SUCCESS);

    32 }

    33 void actiune( int cod){

    34 f p r in t f s ( stderr ,

    35 "\nEroare ...\n"

    36 "Codul erorii: %d\n"

    37 "Cauza: nu ati tastat ’x ’...\n",

    38 cod);

    39 }

    Program:> În proiectul VS de la pagina 34, am utilizat funcţia fputc din ca să introducem un caracter ı̂ntr-un fişier. Pentru a ne asigura că “fluxulde date”11 (fişier deschis) exista, apelasem anterior funcţia fopen_s. În cazcontrar, funcţia fputc ar fi invocat un handler (o funcţie) pentru eroarea de“parametru invalid”. Acest “hamal” (handler) — reprezentat printr-un han-dle, adică un pointer la funcţie, [20, p. 118] — fie repară eroarea şi continuăexecuţia, fie va ı̂ncheia execuţia programului, [35, p. 41; Chap. 1]. CodulC dat ı̂n continuare prezintă un asemenea handler, care afişează un mesaj şiopreşte execuţia. Pentru a-l vedea “la lucru”, folosiţi — ca până acum —opţiunea Empty Project la iniţializarea noului proiect VS. Apoi, construiţisoluţia via Build\Batch Build...12 şi selectaţi ı̂n fereastra Batch Build,la rubrica Solution Config, varianta Release|Win32. Vezi şi tehnica VEH,cf. [35, p. 751; Chap. 25].

    Întreruperi: eh01.c

    1 #define UNICODE

    2 #define _UNICODE

    11 În limba engleză, stream, cf. [9, p. 81]. Vezi şi [20, p. 241].12Cu opţiunea Debug, veţi vedea un Watson crash report (fereastră de depanare stan-

    dard).

    47

  • 3 #include

    4 #include

    5 #include

    6 #include

    7

    8 void main(void){

    9 FILE *fisier = NULL;

    10 void handler_parametru_invalid(

    11 const wchar t *,

    12 const wchar t *,

    13 const wchar t *,

    14 unsigned int ,

    15 uintptr t );

    16 {

    17 set invalid parameter handler (

    18 handler_parametru_invalid

    19 );

    20 i f ( fputc(’D’,fisier))

    21 exit (EXIT SUCCESS);

    22 }

    23 }

    24

    25 void handler_parametru_invalid(

    26 const wchar t *expresia_care_produce_eroare ,

    27 const wchar t *functie ,

    28 const wchar t *fisier ,

    29 unsigned int linie_de_cod ,

    30 uintptr t rezervat ){

    31 fwprintf s ( stderr ,

    32 L"\nParametru invalid detectat la "

    33 L"apelul functiei \" fputc\".\n"

    34 L"Programul se incheie aici!\n");

    35 abort();

    36 }

    Reamintesc că, fiind ı̂ntr-un sistem de operare Windows (unde resurselesunt virtualizate), apelul nereuşit al funcţiei fputc va declanşa, concomitentcu afişarea ı̂ntr-o consolă a mesajului din partea handlerului, o fereastrăde dialog a JIT-ului (Just-In-Time Debugger) de la Visual Studio. . . Pre-supunând că VS-ul este instalat pe calculatorul cu care testăm programul.Altfel, ı̂n Windows XP13, ı̂n afara mesajului de consolă, va apărea o fereastră

    13 Înainte de a apăsa de două ori pe imaginea executabilului Nume_program.exe, inseraţiı̂n C:\WINDOWS\system32 fişierul msvcr100.dll, copiat din calculatorul ı̂n care aţi “con-

    48

  • cu textul Nume_program.exe has encountered a problem and needs toclose..., ı̂n timp ce ı̂n Windows 7 textul afişat ı̂n fereastră va fi Nume_pro-gram.exe has stopped working... În schimb, dacă rulaţi programul eh01.exe din consolă, răspunsul handlerului va apărea ı̂n (aceeaşi) consolă.

    Program:> Este util adesea să dispunem de un program care să introducă ı̂ntr-unfişier o informaţie exprimată printr-un şir de caractere, d.ex. un număr detelefon mobil ori un mesaj scurt (SMS), ı̂mpreună cu o minimă ordonare(formatare), respectiv cu adăugarea timpului curent şi a unei parole (chei).Acesta ar fi cel mai simplu model de bază de date, vezi [6, pg. 19, 24]. În modevident, rutinele din program pot fi realizate cu ajutorul funcţiei scanf_s din. Proiectul VS care urmează este alcătuit din fişierele program.c,headerulnostru.h, macrouri.h şi handlere.c.

    Bază de date txt, cu timestamp şi parolă: program.c

    1 /* ---

    2 sintaxa: nume_program.exe xx.txt [parola]

    3 aici , [] desemneaza un argument optional

    4 ---*/

    5

    6 /* ---

    7 Formatul bazei de date:

    8 ===============================

    9 ----inceput inregistrare ----

    10 NMC | NCCE | continut

    11 ----inceput preluare ----

    12 Parola este: P/FP

    13 ----sfarsit preluare ----

    14 Info timp: TS

    15 ----sfarsit inregistrare ----

    16 ===============================

    17 Aici ,

    18 NMC: caracterul dat de hash -ul

    19 (int)(nr. maxim de caractere * 0.01) + ’0’

    20 NCCE: (int)(nr. de car. citite efectiv * 0.1) +’0’

    21 P/FP: parola/Fara parola!

    22 TS: timestamp

    23 ---*/

    24

    25 /* ---

    26 compilare cu optiunea Release;

    27 altfel , nu uitati ca trebuie:

    struit” — Batch Build — executabilul.

    49

  • 28 1) definit _DEBUG

    29 2) inserat

    30 _CrtSetReportMode(_CRT_ASSERT , 0);

    31

    32 Vezi:

    33 http:// msdn.microsoft.com/en-us/library /1 y71x448.aspx

    34 ---*/

    35

    36 /* ---

    37 limitari :

    38 + cand argc = 2:

    39 - nu se testeaza daca introducem numele fisierului

    40 sau parola;

    41 - nu se parseaza nici numele fisierului nici parola;

    42 - nu se aloca/elibereaza memorie pentru parola ,

    43 presupunand ca este extrem de scurta;

    44 + cand argc >= 3 ...

    45 ---*/

    46

    47 #define UNICODE

    48 #define _UNICODE

    49

    50 #undef LUNGIME_LINIE

    51 #define LUNGIME_LINIE 500

    52 #undef LUNGIME_MESAJ

    53 #define LUNGIME_MESAJ 100

    54 #undef FORMATE_MESAJ

    55 #define FORMATE_MESAJ 4

    56 #undef DATE_TIMP

    57 #define DATE_TIMP 70

    58

    59 #include "headerulnostru.h"

    60 #include "macrouri.h"

    61 #include

    62

    63 void main( int argc , char *argv[]){

    64 /*---

    65 handlere de eroare:

    66 ---*/

    67 extern void handler_pentru__cgets_s(

    68 const wchar t *,

    69 const wchar t *,

    70 const wchar t *,

    50

  • 71 unsigned int ,

    72 uintptr t );

    73 extern void handler_pentru_ctime_s(

    74 const wchar t *,

    75 const wchar t *,

    76 const wchar t *,

    77 unsigned int ,

    78 uintptr t );

    79 extern void handler_pentru_fprintf_s(

    80 const wchar t *,

    81 const wchar t *,

    82 const wchar t *,

    83 unsigned int ,

    84 uintptr t );

    85 extern void handler_pentru_fputs(

    86 const wchar t *,

    87 const wchar t *,

    88 const wchar t *,

    89 unsigned int ,

    90 uintptr t );

    91 extern void handler_pentru_fclose(

    92 const wchar t *,

    93 const wchar t *,

    94 const wchar t *,

    95 unsigned int ,

    96 uintptr t );

    97 extern void handler_pentru_fopen_s(

    98 const wchar t *,

    99 const wchar t *,

    100 const wchar t *,

    101 unsigned int ,

    102 uintptr t );

    103

    104 /*---

    105 stream -ul de lucru:

    106 ---*/

    107 FILE *fisier = NULL;

    108 /*---

    109 linie: bufferul inregistrarii (continut )

    110 mesaj: bufferul mesajului (P/FP)

    111 contor_parola: cu/fara cheie

    112 alt_contor: iterator

    113 ---*/

    51

  • 114 char *linie = NULL,

    115 *mesaj = NULL;

    116 int contor_parola = 0,

    117 alt_contor = 0;

    118

    119 /*---

    120 datele functiilor "_s":

    121 ---*/

    122 s i z e t numar_standard = LUNGIME_MESAJ;

    123 s i z e t *numar_caractere_citite = &numar_standard;

    124 time t timp_curent = ( int64 ) 0;

    125 char *buffer_timp = NULL;

    126

    127 i f (

    128 (LUNGIME_LINIE

  • 157 (buffer_timp = (char *) ca l l oc (DATE_TIMP , s i z eo f (char)))

    158 == NULL

    159 ){

    160 #i fd e f DEBUG

    161 EROARE("\nEroare memorie timp!",linie)

    162 #else

    163 EROARE(" ",linie)

    164 #endif

    165 }

    166

    167 /*---

    168 analizam linia de comanda:

    169 ---*/

    170

    171 i f (argc == 1){

    172 #i fd e f DEBUG

    173 EROARE("\nLipsesc fisierul si parola!\n",linie)

    174 EROARE(" ",buffer_timp)

    175 #else

    176 EROARE(" ",linie)

    177 EROARE(" ",buffer_timp)

    178 #endif

    179 }

    180 i f (argc == 2){

    181 #i fd e f DEBUG

    182 pr int f s ("\nLipseste parola!\n");

    183 #endif

    184 mesaj = "Fara parola!";

    185 contor_parola = 1;

    186 }

    187

    188 /*---

    189 ne conectam la baza:

    190 ---*/

    191 {/* incep bloc instructiuni "fopen_s ":

    192 doar aici instalez handler -ul

    193 de eroare pt. fopen_s ...

    194 */

    195 set invalid parameter handler (

    196 handler_pentru_fopen_s

    197 );

    198 i f (

    199 fopen s (&fisier ,argv[1],"a+") != 0

    53

  • 200 ){

    201 /* ---

    202 daca am ajuns aici , am revenit din eroare;

    203 aceasta pt. ca handler -ul doar a afisat

    204 un mesaj...

    205 o valoare nenula returnata de fopen_s este

    206 un cod de eroare;

    207 ---*/

    208 #i fd e f DEBUG

    209 EROARE("Eroare la deschiderea fisierului!",

    210 linie)

    211 EROARE(" ",buffer_timp)

    212 #else

    213 EROARE(" ",linie)

    214 EROARE(" ",buffer_timp)

    215 #endif

    216 }

    217 }/* final bloc instructiuni "fopen_s" */

    218

    219 pr int f s ("\nTastati n

  • 243 }

    244

    245 {/*incep bloc intructiuni "ctime_s" */

    246 set invalid parameter handler (

    247 handler_pentru_ctime_s

    248 );

    249 i f (

    250 ctime s(buffer_timp ,DATE_TIMP * s i z eo f (char),

    251 &timp_curent) != 0

    252 ){

    253 #i fd e f DEBUG

    254 EROARE("Eroare la structurarea timpului!",

    255 linie)

    256 EROARE(" ",buffer_timp)

    257 #else

    258 EROARE(" ",linie)

    259 EROARE(" ",buffer_timp)

    260 #endif

    261 }

    262 }/*final bloc intructiuni "ctime_s" */

    263

    264 /*---

    265 formatam linia:

    266 1) mutam textul la dreapta cu patru pozitii

    267 2) inseram "NMC|NCCE|"

    268 ---*/

    269

    270 for (alt_contor = ( int ) (* numar_caractere_citite) - 1;

    271 alt_contor >= 0;

    272 linie[alt_contor + 4] = linie[alt_contor --]

    273 );

    274

    275 /*---hash -uri:---*/

    276 linie[0] = (char) (( int )(LUNGIME_LINIE * 0.01) + ’0’);

    277 linie[1] = ’|’;

    278 linie[2] = (char) (( int )(( int ) (* numar_caractere_cititeց

    (cont.) ) * 0.1) + ’0’);

    279 linie[3] = ’|’;

    280

    281 /*---

    282 incarcam inregistrarea:

    283 ---*/

    284

    55

  • 285 {/*inceput bloc instructiuni cu "fprintf_s" */

    286 set invalid parameter handler (

    287 handler_pentru_fprintf_s

    288 );

    289 i f (

    290 f p r in t f s (fisier ,

    291 "\n----inceput inregistrare ----\n") < 0

    292 ){

    293 #i fd e f DEBUG

    294 EROARE("Eroare la inserarea "

    295 "antetului inregistrarii!",

    296 linie)

    297 EROARE(" ",buffer_timp)

    298 #else

    299 EROARE(" ",linie)

    300 EROARE(" ",buffer_timp)

    301 #endif

    302 }

    303

    304 }/* final bloc instructiuni cu "fprintf_s" */

    305

    306 { /* aplicam "fputs" pentru linie: */

    307 set invalid parameter handler (handler_pentru_fputs);

    308 i f ( fputs (linie ,fisier) == EOF){

    309 #i fd e f DEBUG

    310 EROARE("Eroare la inserarea liniei!",

    311 linie)

    312 EROARE(" ",buffer_timp)

    313 #else

    314 EROARE(" ",linie)

    315 EROARE(" ",buffer_timp)

    316 #endif

    317 }

    318 } /* final "fputs" */

    319

    320 /* aplicam "fflush": */

    321 i f ( f f lu sh (fisier) == EOF){

    322 #i fd e f DEBUG

    323 EROARE("Eroare la flush -ul liniei!",

    324 linie)

    325 EROARE(" ",buffer_timp)

    326 #else

    327 EROARE(" ",linie)

    56

  • 328 EROARE(" ",buffer_timp)

    329 #endif

    330 }/* final "fflush" */

    331

    332 { /*inceput bloc instructiuni cu "fprintf_s" */

    333 set invalid parameter handler (

    334 handler_pentru_fprintf_s

    335 );

    336 i f (

    337 f p r in t f s (fisier ,"\n----inceput preluare ----\n") < 0

    338 ){

    339 #i fd e f DEBUG

    340 EROARE("Eroare la inserarea "

    341 "antetului preluarii!",

    342 linie)

    343 EROARE(" ",buffer_timp)

    344 #else

    345 EROARE(" ",linie)

    346 EROARE(" ",buffer_timp)

    347 #endif

    348 }

    349 }/* final bloc instructiuni cu "fprintf_s" */

    350

    351 i f (contor_parola == 0){

    352 { /*inceput bloc instructiuni cu "fprintf_s" */

    353 set invalid parameter handler (

    354 handler_pentru_fprintf_s

    355 );

    356 i f (

    357 f p r in t f s (fisier ,"Parola este:\t") < 0

    358 ){

    359 #i fd e f DEBUG

    360 EROARE("Eroare la inserarea "

    361 "mesajului parolei!",

    362 linie)

    363 EROARE(" ",buffer_timp)

    364 #else

    365 EROARE(" ",linie)

    366 EROARE(" ",buffer_timp)

    367 #endif

    368 }

    369 }/* final bloc instructiuni cu "fprintf_s" */

    370

    57

  • 371 { /* aplicam "fputs" pentru parola: */

    372 set invalid parameter handler (handler_pentru_fputs);

    373 i f ( fputs (argv[2],fisier) == EOF){

    374 #i fd e f DEBUG

    375 EROARE("Eroare la inserarea parolei!",

    376 linie)

    377 EROARE(" ",buffer_timp)

    378 #else

    379 EROARE(" ",linie)

    380 EROARE(" ",buffer_timp)

    381 #endif

    382 }

    383 }/* final "fputs" */

    384

    385 /* aplicam "fflush": */

    386 i f ( f f lu sh (fisier) == EOF){

    387 #i fd e f DEBUG

    388 EROARE("Eroare la flush -ul parolei!",

    389 linie)

    390 EROARE(" ",buffer_timp)

    391 #else

    392 EROARE(" ",linie)

    393 EROARE(" ",buffer_timp)

    394 #endif

    395 }/* final "fflush" */

    396 }

    397 e l se {/* ---

    398 daca sunt aici ,

    399 nu am dat o parola...

    400 ---*/

    401 { /*inceput bloc instructiuni cu "fprintf_s" */

    402 set invalid parameter handler (

    403 handler_pentru_fprintf_s

    404 );

    405 i f ( f p r in t f s (fisier ,mesaj) < 0){

    406 #i fd e f DEBUG

    407 EROARE("Eroare la inserarea "

    408 "mesajului de lipsa "

    409 "a parolei!",

    410 linie)

    411 EROARE(" ",buffer_timp)

    412 #else

    413 EROARE(" ",linie)

    58

  • 414 EROARE(" ",buffer_timp)

    415 #endif

    416 }

    417 }/* final bloc instructiuni cu "fprintf_s" */

    418 } /* final bloc "else" */

    419

    420 { /*inceput bloc instructiuni cu "fprintf_s" */

    421 set invalid parameter handler (

    422 handler_pentru_fprintf_s

    423 );

    424 i f (

    425 f p r in t f s (fisier ,

    426 "\n----sfarsit preluare ----\n"

    427 "Info timp:\t") < 0

    428 ){

    429 #i fd e f DEBUG

    430 EROARE("Eroare la inserarea "

    431 "mesajului de final "

    432 "pentru preluare !",

    433 linie)

    434 EROARE(" ",buffer_timp)

    435 #else

    436 EROARE(" ",linie)

    437 EROARE(" ",buffer_timp)

    438 #endif

    439 }

    440 i f (

    441 f p r in t f s (fisier ,buffer_timp) < 0

    442 ){

    443 #i fd e f DEBUG

    444 EROARE("Eroare la inserarea timpului!",

    445 linie)

    446 EROARE(" ",buffer_timp)

    447 #else

    448 EROARE(" ",linie)

    449 EROARE(" ",buffer_timp)

    450 #endif

    451 }

    452 i f (

    453 f p r in t f s (fisier ,

    454 "----sfarsit inregistrare ----\n\n") < 0

    455 ){

    456 #i fd e f DEBUG

    59

  • 457 EROARE("Eroare la inserarea "

    458 "mesajului de final "

    459 "pentru inregistrare!",

    460 linie)

    461 EROARE(" ",buffer_timp)

    462 #else

    463 EROARE(" ",linie)

    464 EROARE(" ",buffer_timp)

    465 #endif

    466 }

    467 }/*sfarsit bloc instructiuni cu "fprintf_s" */

    468

    469 /*---

    470 deconectam baza:

    471 ----*/

    472

    473 {/*inceput bloc instructiuni cu "fclose" */

    474 set invalid parameter handler (

    475 handler_pentru_fclose

    476 );

    477 i f ( f c l o s e (fisier) == EOF){

    478 #i fd e f DEBUG

    479 EROARE("Eroare la inchiderea streamului...!",

    480 linie)

    481 EROARE(" ",buffer_timp)

    482 #else

    483 EROARE(" ",linie)

    484 EROARE(" ",buffer_timp)

    485 #endif

    486 }

    487 }/*sfarsit bloc instructiuni cu "fclose" */

    488

    489 SUCCES(linie ,buffer_timp)

    490 }

    Bază de date txt, cu timestamp şi parolă: macrouri.h

    1 #i f !defined ( MACROURI )

    2 #define MACROURI

    3 /* ---------------------*/

    4

    5 /* ---

    6 macrouri debugging:

    7 ---*/

    60

  • 8 #undef DEBUG

    9 #define DEBUG 1

    10 /* #undef DEBUG */

    11 #undef EROARE_A

    12 #define EROARE_A (text) \

    13 pr int f s (text); \

    14 exit (EXIT FAILURE);

    15 #undef EROARE

    16 #define EROARE(text ,pointer) \

    17 pr int f s (text); \

    18 f ree ((void *) pointer); \

    19 pointer = NULL; \

    20 exit (EXIT FAILURE);

    21 #undef SUCCES

    22 #define SUCCES(pointer_a ,pointer_b) \

    23 LA_REVEDERE \

    24 f ree ((void *) pointer_a); \

    25 pointer_a = NULL; \

    26 f ree ((void *) pointer_b); \

    27 pointer_b = NULL; \

    28 exit (EXIT SUCCESS);

    29

    30 /* ---------------------*/

    31 #endif

    Bază de date txt, cu timestamp şi parolă: handlere.c

    1 #include "headerulnostru.h"

    2

    3 void handler_pentru__cgets_s(

    4 const wchar t *expresia_care_produce_eroare ,

    5 const wchar t *functie ,

    6 const wchar t *fisier ,

    7 unsigned int linie_de_cod ,

    8 uintptr t rezervat ){

    9 fwprintf s ( stderr ,

    10 L"\nParametru invalid detectat la "

    11 L"apelul functiei \"_cgets_s \".\n");

    12 }

    13 void handler_pentru_ctime_s(

    14 const wchar t *expresia_care_produce_eroare ,

    15 const wchar t *functie ,

    16 const wchar t *fisier ,

    17 unsigned int linie_de_cod ,

    61

  • 18 uintptr t rezervat ){

    19 fwprintf s ( stderr ,

    20 L"\nParametru invalid detectat la "

    21 L"apelul functiei \"ctime_s \".\n");

    22 }

    23 void handler_pentru_fprintf_s(

    24 const wchar t *expresia_care_produce_eroare ,

    25 const wchar t *functie ,

    26 const wchar t *fisier ,

    27 unsigned int linie_de_cod ,

    28 uintptr t rezervat ){

    29 fwprintf s ( stderr ,

    30 L"\nParametru invalid detectat la "

    31 L"apelul functiei \" fprintf_s\".\n");

    32 }

    33 void handler_pentru_fputs(

    34 const wchar t *expresia_care_produce_eroare ,

    35 const wchar t *functie ,

    36 const wchar t *fisier ,

    37 unsigned int linie_de_cod ,

    38 uintptr t rezervat ){

    39 fwprintf s ( stderr ,

    40 L"\nParametru invalid detectat la "

    41 L"apelul functiei \"fputs\".\n");

    42 }

    43 void handler_pentru_fclose(

    44 const wchar t *expresia_care_produce_eroare ,

    45 const wchar t *functie ,

    46 const wchar t *fisier ,

    47 unsigned int linie_de_cod ,

    48 uintptr t rezervat ){

    49 fwprintf s ( stderr ,

    50 L"\nParametru invalid detectat la "

    51 L"apelul functiei \"fclose \".\n");

    52 }

    53 void handler_pentru_fopen_s(

    54 const wchar t *expresia_care_produce_eroare ,

    55 const wchar t *functie ,

    56 const wchar t *fisier ,

    57 unsigned int linie_de_cod ,

    58 uintptr t rezervat ){

    59 fwprintf s ( stderr ,

    60 L"\nParametru invalid detectat la "

    62

  • 61 L"apelul functiei \"fopen_s \".\n");

    62 }

    Program:> Următorul program studiază apariţiile unui caracter ı̂ntr-un şir de carac-tere, folosind aritmetica pointerilor (adreselor), vezi [20, p. 100]. Ar puteafi utilizat la parsarea numelor de fişiere din proiectul anterior — căutămcaracterul “.” din şirul “nume_fisier.txt” —.

    Numărător de caractere: caract0x.c

    1 #include "headerulnostru.h"

    2 #include

    3

    4 #undef LUNGIME

    5 #define LUNGIME 100

    6

    7 void main(void){

    8 int pozitie = 1,

    9 contor = 0;

    10 s i z e t inregistrare = 0;

    11 char caracter = ’e’,

    12 *pointerul /* adresele caracterelor*/,

    13 sirul[] = "E acesta un sir feeric cu date , ei?";

    14

    15 pointerul = sirul;

    16 pr int f s ("\nIncepe scanarea ...\n");

    17 for (;* pointerul != ’\0’;pozitie ++)

    18 i f (* pointerul++ == caracter ){

    19 contor ++;

    20 pr int f s ("Pozitia: %d\n",pozitie);

    21 }

    22

    23 inregistrare = strn len s (sirul ,LUNGIME);

    24

    25 pr int f s ("Scanare terminata.\n"

    26 "Nr. de aparitii : %d\n"

    27 "Lungimea sirului: %d\n",

    28 contor ,

    29 inregistrare

    30 = (inregistrare == LUNGIME) ? -1 : inregistrare

    31 );

    32

    33 LA_REVEDERE

    34 exit (EXIT SUCCESS);

    35 }

    63

  • 4 Programare ı̂n C++

    Limbajul C++ a fost inventat de profesorul Bjarne Stroustrup de la Uni-versitatea A&M Texas şi este descris ı̂n cartea [41]. Limbajul a fost denumitla ı̂nceput şi C cu clase, vezi [40], [41, p. 10].

    Un draft al standardului pentru limbajul C++ se găseşte la adresa [39].Program:> Primul program scris ı̂n C++ trebuie, fireşte, să salute lumea. Cum limbajul

    C++ extinde limbajul C, suntem, practic, acasă. De aceea, vom putea folosiı̂n cadrul său funcţia printf din biblioteca C standard . Într-un proiect VS gol, introducem fişierele centru.cpp, headerulnostru.h şiajutor.cpp de mai jos.

    “Salut, prieteni!”: centru.cpp

    1 #include "headerulnostru.h"

    2

    3 int main(){

    4

    5 std:: pr int f ("\nSalut , prieteni !\n");

    6 afisare("Suntem la laboratorul: %d\n" ,2);

    7 afisare("Maine , venim la laboratorul: %d\n" ,3);

    8

    9 incheiere();

    10 return 0;

    11 }

    “Salut, prieteni!”: headerulnostru.h

    1 #ifndef _HEADERULNOSTRU_

    2 #define _HEADERULNOSTRU_

    3 /* ------------------*/

    4

    5 // headere C++:

    6 #include

    7 #include

    8

    9 // headere C:

    10 #include

    11

    12 int afisare(const char*, int );

    13 int incheiere();

    14

    15 /* ------------------*/

    16 #endif

    64

  • “Salut, prieteni!”: ajutor.cpp

    1 #include "headerulnostru.h"

    2 #include

    3

    4 int afisare(const char *mesaj , int numar){

    5 s t a t i c int lungime = 200;

    6 i f (

    7 std:: str len (mesaj) >= s ta t i c cas t < s i ze t >(lungime)

    8 ){

    9 std:: pr int f ("\nMesaj prea lung...\n");

    10 return -1;

    11 }

    12 return std:: pr int f (mesaj ,numar /*+ (lungime ++)*/);

    13 }

    14

    15 int incheiere(){

    16 std:: pr int f ("\nTastati o litera pentru a incheia: ");

    17 return getch();

    18 }

    Observăm prefixul std al funcţiei printf. Pentru a-l explica, menţionezcă biblioteca C++ standard preia fişierele ale bibliotecii C standardsub forma , cf. [41, p. 202]. În aceste fişiere se foloseşte un mecanismC++ denumit nume de spaţiu14, [41, pg. 167, 176], pentru a evita conflictelede nume15 care apar atunci când, fără să ştie, programatori diferiţi folosescacelaşi nume pentru a desemna mărimi diferite. Precizând — prin numele despaţiu — spaţiul (zona din program16) unde numele mărimii respective (vari-abilă, funcţie) este valabil, problema se rezolvă eficient. În fişierul ,numele de spaţiu ı̂n care se găseşte funcţia C printf este std (standard).Pentru a atesta apartenenţa unui nume la un nume de spaţiu se foloşte oper-atorul de spaţiu17 “::”, vezi [41, p. 82]. Expresiile nume_de_spatiu::numeconstituie nume complete18 ale mărimilor.

    Cuvântul cheie static, [41, pg. 145, 200, 819], trebuie folosit doar ı̂ncodul de implementare al funcţiilor19, e.g., afisare. El cere ca variabila ı̂ncauză să fie iniţializată o singură dată — la primul apel al funcţiei —, indifer-

    14 În limba engleză, namespace, cf. [18, p. 867].15 În limba engleză, name clashes .16 În limba engleză, scope, vezi [41, p. 168]. Se foloseşte şi sintagma domeniu de valabi-

    litate, adică zona din program ı̂n care mărimea este activă, cf. [23, pg. 48, 49].17 În limba engleză, scope resolution operator .18 În limba engleză, fully qualified names , cf. [42, p. 291].19Şi al claselor. . . Vezi şi [41, p. 819, Section B.2.3].

    65

  • ent de câte ori va fi apelată aceasta. Dacă activaţi expresia + (lungime++)din codul funcţiei afisare, veţi observa că programul “ţine minte” valoarealungime ı̂ntre apeluri consecutive.

    Mai departe, remarcăm că funcţia strlen returnează valori de tip size_t,adică unsigned int. Pentru a face comparaţia cu mărimea lungime, trebuierealizată o conversie explicită de tip (cast). Codul C (size_t) lungime estereorganizat ı̂n C++ via operatorul static_cast, cf. [41, p. 130].

    La pornirea unui program C++, sistemul de operare ı̂i va ataşa o seriede fluxuri de date, intitulate std::cout, std::cin, std::cerr, std::clog,etc20. Elementele (funcţii, date) necesare utilizării acestora se găsesc ı̂n fi-şierele antet şi — sau , cf. [18, p. 718, Secţ. 980] —. Lucrând ı̂n consolă, sunt mai uşor de reţinuturmătoarele “traduceri” ale denumirilor acestor fluxuri de intrare–ieşire: cin(console–in, citire), cout (console–out21, scriere), cerr (console–error, erori,fără buffer) şi clog (console–log, erori, cu buffer), vezi şi [18, p. 598, Secţ.817]. Practic, reamintindu-ne fluxurile din limbajul C, vezi pagina 28, coutse referă la stdout, cin la stdin, iar cerr şi clog la stderr, vezi [41, p.637].

    Program:> Putem lucra cu fluxurile de intrare–ieşiere la fel ca ı̂ntr-un program C,utilizând omoloage ale funcţiilor din librăria standard getchar şi puts, cf.[20, p. 247].

    Afişând un caracter. . . : ajutor.cpp

    1 #include

    2 #include

    3 #include

    4

    5 using namespace std;

    6 // evitam scrierea prefixului "std::"

    7

    8 int main(){

    9 char litera = ’\n’;

    10 litera = cin.get();

    11 cout.put(litera);

    12 getch();

    13 return 0;

    14 }

    20Lor li se adaugă stream-urile pentru caractere multi-byte, vezi [41, p. 609].21 În realitate, prof. Stroustrup abreviază cu cout expresia “character output stream”,

    cf. [42, p. 45, Secţ. 2.2].

    66

  • Limbajul C++ oferă ı̂nsă o alternativă performantă a comunicării I/O prinfuncţii via noţiunea de operatori , ca e.g., ı̂n următoarea situaţie familiară:

    a+ b ı̂nseamnă + (a, b)

    Program:> Operatorul pentru fluxurile–de–ieşire cout, cerr şi