Programarea Calculatoarelor: Laborator 9
Recapitulare
Operatori pe biți
Pentru a efectua prelucrările dorite, trebuie sa alegem operația potrivită și valoarea cu care facem acea operație (cu 1 și 0 pe pozițiile potrivite). Exemple (toate cu n> întreg, și biții numărați cu exponentul lui 2 corespunzător poziției în număr):
- aflăm dacă n are bitul 5 sau bitul 2 pe 1: alegem ca operand numărul care are doar biții respectiv 1, și ceilalți biți 0: 0...00100100 (25+22 = 32 + 4 = 36, sau în baza 16: 0010 = 2, 0100 = 4, deci 0x24). Dacă efectuăm & între n și numărul găsit (0x24), rezultatul poate avea biți nenuli cel mult pe pozițiile 5 sau 2 (pe celelalte poziții, se face ȘI cu 0 din 0x24, și se obține 0). Deci n & 0x24 e nenul dacă și numai dacă cel puțin unul din biții de pe pozițiile 5 sau 2 din n e nenul.
- punem pe 0 biții 1, 3, 5 și 7 din n. Trebuie să facem tot operația ȘI cu un număr care face rezultatul 0 pe pozițiile dorite, și nu le schimbă pe celelalte. Deci operandul căutat are 0 pe pozițiile 1, 3, 5 și 7, și 1 peste tot în rest: 11...101010101. Deoarece numărul total de biți depinde de reprezentarea lui n (8 * sizeof(n)) e mai simplu să calculăm numărul care are valorile opuse ale biților (1 pe pozițiile 1, 3, 5, 7 și 0 în rest), și să facem complementul. Cum 1010 in binar e 10 adică 0xA, 10101010 în binar e 0xAA. Deci operația căutată e n = n & ~0xAA (e necesară atribuirea pentru ca n să se modifice si să ia valoarea expresiei din partea dreaptă).
- construim un număr (tipar de biți) din mai multe părți componente. Pentru aceasta formăm fragmentele cu tiparele de biți dorite (și 0 în rest) și le combinăm cu SAU. De exemplu, pornind de la număr dat construim valoarea care are ultimele două cifre hexazecimale schimbate (de ex. 0x17A4 devine 0x174A), deci biții 0-3 sunt interschimbați cu biții 4-7.
Construim numărul din 3 părți: un fragment cu biții de la 8 în sus neschimbați, și restul 0, și două fragmente cu biții 0-3 respectiv 4-7 deplasați pe pozițiile 4-7 (respectiv 0-3), și 0 în rest. Prin ȘI cu valoarea 0xFF (biții 0-7 pe 1) obținem ultimii 8 biți din număr: n & 0xFF, iar cu complementul ~0xFF obținem bitii de la 8 în sus: n & ~0xFF. Fragmentul de 8 biți îl deplasăm la dreapta (biții 4-7 ajung pe pozițiile 0-3, iar biții 0-3 dispar). Deplasând pe n 4 poziții la stânga, biții 0-3 ajung pe pozițiile 4-7; prin ȘI cu valoarea 0xF0 "ștergem" toți ceilalți biți din rezultat.
Valoarea dorită este deci: (n & ~0xFF) | (n << 4) & 0xFF | (n >> 4) & 0xF.
Dacă numărul are doar 8 biți: unsigned char c putem scrie mai simplu: (c << 4) | (c >> 4)
- vezi și alte exemple în cursul 6 (p. 10).
Tablouri și șiruri de caractere
Pentru a rezolva probleme cu tablouri, trebuie să știm să declarăm:
- tablouri unidimensionale, de exemplu double a[10];
- tablouri multidimensionale, de exemplu o matrice de reali: int m[12][10];
- tablouri de caractere, eventual inițializate: char sir[8] = "cuvant";
Definim funcții care lucrează cu tablouri, ca de exemplu:
- int f(double t[], int lung) { /* f calculeaza si returneaza un intreg */ }
(parametru: tablou unidimensional de reali; nu se specifică lungimea între paranteze [] dar se transmite ca parametru separat)
void g(int mat[][10], int linii)
{
for (int i = 0; i < linii; ++i)
for (int j = 0; j < 10; ++j) {
// prelucrează mat[i][j]
}
}
(parametru: tablou bidimensional: se specifică dimensiunea a 2-a, dimensiunea 1 se transmite ca parametru separat)
- int h(char *s) { /* ... */ } sau int h(char s[]) { /* ... */ }
pentru șiruri de caractere nu trebuie transmisă lungimea; aceasta se află parcurgând șirul, care se termină cu caracterul nul '\0':
for (int i = 0; s[i]; ++i) {
// prelucreaza s[i]
}
Funcțiile se apelează cu tablouri (numele acestora) de tip și dimensiune potrivită:
int val = f(a, 10); // pentru ca double a[10] e declarat de 10 elemente
g(m, 12); // apel cu matricea declarata anterior int m[12][10];
int n = h(sir); // apel cu tabloul char sir[8] declarat anterior
Funcții de intrare-ieșire
La folosirea funcțiilor de citire trebuie verificat dacă citirea s-a efectuat corect. Multe probleme necesită prelucrarea cât timp intrarea corespunde unui anumit format, sau până la sfârșitul intrării, după tiparul:
cât timp citirea s-a făcut corect
prelucrează obiectul citit
Prelucrarea caracter cu caracter pănă la sfârșitul intrării:
int c;
while ((c = getchar()) != EOF) {
// prelucreaza caracterul c
}
Citirea și prelucrarea linie cu linie a unui text:
char b[81];
while (fgets(b, 81, stdin)) {
// prelucreaza linia citita in tabloul b
}
Citirea și prelucrarea unui șir de numere reale separate prin spații albe:
double x;
while (scanf("%lf", &x) == 1) {
// prelucreaza pe x
}
Citirea unui text format de cuvinte separate prin spații albe, până la sfârșitul intrării:
char cuv[21];
while (scanf("%20s", cuv) == 1) {
// prelucreaza cuvantul
}
Marius Minea
Last modified: Sat Apr 5 17:38:25 EET 2008