În C, operațiile de intrare/ieșire nu fac parte din limbaj: nu există instrucțiuni dedicate, ci doar funcții adăugate prin biblioteca standard. Această separare oferă flexibilitate, dar mută pe umerii programatorului responsabilitatea de a preciza corect formatul datelor.
1Obiectivele lucrării
- Înțelegerea conceptului de stream și a celor cinci dispozitive logice predefinite
- Folosirea funcțiilor de citire/scriere la nivel de caracter
- Citirea și afișarea șirurilor de caractere
- Utilizarea corectă a specificatorilor de format în
printfșiscanf - Recunoașterea și evitarea capcanelor clasice ale funcției
scanf
2Streamuri standard
Transferurile cu dispozitivele fizice se fac prin dispozitive logice numite stream (flux). Există două categorii: streamuri de tip text, care transferă caractere organizate pe linii, și streamuri binare, care transferă octeți fără nicio structură impusă.
| Stream | Tip | Asociat cu | Poate fi redirectat? |
|---|---|---|---|
stdin | text | tastatura - intrarea standard | da |
stdout | text | monitorul - ieșirea standard | da |
stderr | text | monitorul - ieșirea pentru erori | da |
stdprn | binar | imprimanta (dispozitiv DOS PRN) | nu |
stdaux | binar | intrare/ieșire auxiliară (DOS AUX) | nu |
program > rezultat.txt) erorile să apară
în continuare pe ecran, nu să fie ascunse în fișier.3Operații la nivel de caracter
| Funcție | Rol | Observații |
|---|---|---|
int getchar(void) | citește un caracter din stdin | așteaptă Enter; returnează EOF la sfârșit de fișier |
int getch(void) | citește un caracter fără ecou | nu așteaptă Enter; specific conio.h, neportabil |
int getche(void) | citește un caracter cu ecou pe ecran | nu așteaptă Enter; neportabil |
int putchar(int c) | scrie un caracter în stdout | returnează caracterul scris |
getchar() trebuie să poată semnala
sfârșitul fluxului prin valoarea EOF (de regulă −1), care nu încape în domeniul
unsigned char. Dacă rezultatul este stocat într-un char, testul
c != EOF poate să nu funcționeze niciodată.4Operații cu șiruri de caractere
| Funcție | Rol | Risc |
|---|---|---|
gets(s) | citește o linie întreagă, inclusiv spațiile | periculoasă - nu limitează lungimea; eliminată din standard |
fgets(s, n, stdin) | citește cel mult n−1 caractere | sigură; păstrează caracterul '\n' la final |
puts(s) | afișează un șir și adaugă linie nouă | - |
scanf("%s", s) | citește un cuvânt (se oprește la spațiu) | nu poate citi propoziții cu spații |
fgets în locul lui
gets. Pentru a elimina caracterul de linie nouă rămas:
s[strcspn(s, "\n")] = '\0';5Intrare/ieșire cu format
Structura unui specificator
%[flag][latime][.precizie][modificator]tip %-8.3f │││ │ └── tip: f = real ││└─┴──── precizie: 3 zecimale │└─────── latime minima: 8 caractere └──────── flag: - = aliniere la stanga
| Specificator | Tip de date | Exemplu de afișare |
|---|---|---|
%d, %i | int | -42 |
%u | unsigned int | 4294967254 |
%f | float / double | 3.141593 |
%.2f | real cu 2 zecimale | 3.14 |
%e | notație științifică | 3.141593e+00 |
%c | char | A |
%s | șir de caractere | text |
%x, %X | hexazecimal | ff / FF |
%o | octal | 377 |
%p | adresă (pointer) | 0x7ffd3a2c |
%% | caracterul procent literal | % |
6Explorator de specificatori
Alegeți un specificator și o valoare, apoi urmăriți exact ce afișează
printf. Încercați combinații nepotrivite - de exemplu %c cu valoarea 65 -
pentru a înțelege de ce compilatorul nu vă avertizează.
7Capcane la citire
scanf("%d", n); în loc de scanf("%d", &n); transmite valoarea variabilei
în loc de adresa ei. Programul se compilează, dar se oprește brutal la execuție.scanf("%d", &n);, tasta Enter rămâne necitită în stdin.
Un scanf("%c", &c); imediat următor va prelua acel '\n', nu caracterul dorit.
Soluție: scanf(" %c", &c); - spațiul din format sare peste caracterele albe.printf("%d", 3.14); nu produce eroare de compilare, dar afișează o valoare fără sens,
pentru că interpretează biții unui double ca pe un int.scanf returnează 0 și lasă
textul în buffer, ceea ce poate duce la buclă infinită. Verificați întotdeauna valoarea returnată:
if (scanf("%d", &n) != 1) { ... }8Cod sursă
#include <stdio.h>
int main(void)
{
int c; // int, NU char, pentru a putea compara cu EOF
int litere = 0, cifre = 0, spatii = 0, altele = 0;
printf("Introduceti text (Ctrl+Z / Ctrl+D pentru final):\n");
while ((c = getchar()) != EOF) {
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) litere++;
else if (c >= '0' && c <= '9') cifre++;
else if (c == ' ' || c == '\t' || c == '\n') spatii++;
else altele++;
}
printf("\nLitere: %d Cifre: %d Spatii: %d Altele: %d\n",
litere, cifre, spatii, altele);
return 0;
}
#include <stdio.h>
#include <string.h>
int main(void)
{
char nume[50];
int varsta;
printf("Numele complet: ");
fgets(nume, sizeof(nume), stdin); // sigur: limiteaza lungimea
nume[strcspn(nume, "\n")] = '\0'; // elimina linia noua
printf("Varsta: ");
while (scanf("%d", &varsta) != 1) { // verifica reusita citirii
printf("Valoare invalida. Reincercati: ");
while (getchar() != '\n'); // goleste bufferul
}
printf("\n%-20s %3d ani\n", nume, varsta);
return 0;
}
#include <stdio.h>
int main(void)
{
printf("%-12s %8s %10s\n", "Produs", "Bucati", "Pret");
printf("--------------------------------\n");
printf("%-12s %8d %10.2f\n", "Rezistor", 120, 0.15);
printf("%-12s %8d %10.2f\n", "Condensator", 45, 0.80);
printf("%-12s %8d %10.2f\n", "Microcontroler", 8, 24.50);
// acelasi numar, in baze diferite
int v = 255;
printf("\n%d in zecimal = %o in octal = %X in hexa\n", v, v, v);
// afisarea unui procent literal
printf("Progres: %d%%\n", 75);
return 0;
}
9Atelier de cod
Formatarea afișării se învață experimentând. Schimbați numerele din specificatori (%8.3f, %-12s) și priviți cum se mișcă coloanele.
scanf, în ordine. Într-un program real, utilizatorul le-ar tasta pe rând.10Sarcini de lucru
- Scrieți un program care citește caractere până la EOF și numără literele, cifrele și spațiile.
- Citiți un nume complet (cu spații) folosind
fgetsși afișați-l cuputs. - Reproduceți capcana cu Enter rămas în buffer, apoi corectați-o cu
" %c". - Afișați numărul 255 în zecimal, octal și hexazecimal, într-un singur
printf. - Construiți un tabel aliniat cu trei coloane, folosind lățimi și alinieri explicite.
- Implementați citirea robustă a unui întreg, cu reîncercare la date nevalide.
- Testați ce afișează
printf("%d", 3.14)și explicați rezultatul.
11Aplicație de aprofundare
stdio.h și ctype.h.