Cum programezi cu vectori si matrici in C
Vectori. Sau tablouri, sau arrays — cum vrei sa le zici. Am mai vorbit despre ei in lectia despre vectori si matrici. Deci n-au treaba cu fizica sau cu matematica. Sunt doar grupari de variabile anonime.
Caci un element dintr-un vector nu are nume. E doar un numar.
Hai sa ne imaginam un pic catalogul de la scoala ca pe un vector numit elev. Inseamna ca profesorul (adica programul) nu se va adresa elevului Avram Gigel printr-o formulare de genul “Elev Avram Gigel, qu’est-ce que vous avez prepare pour aujourd’hui?“, ci va zice “elev[0] sa isi prezinte tema“.
Rece, impersonal. Suna mai mult a penitenciar decat a scoala.
Dar asa stau lucrurile. Programele de calculator nu sunt foarte politicoase si nici nu exceleaza in materie de empatie.
Pai atunci…
De ce vectori?
Ca sa poti face cautari. (Gen “toti elevii care au 10 la info“. (In binar, 🙂 hi-hi.))
Ca sa poti face sortari. (Cum ar fi sa ordonezi in ordine descrescatoare a inaltimii elevii la ora de sport doar dandu-le instructiuni de genul “elev[i] sa schimbe locul cu elev[j]“.)
Ca sa poti sa aplici un acelasi tratament unui numar mare (si poate variabil) de obiecte similare.
(Nu mai insist. Vectorii sunt esentiali in programare. Ei sunt baza structurilor de date, asa cum ti-am aratat in Abecedar.)
Hai sa vedem cum e cu vectorii in C.
Vectorii din C
Despre variabile si tipuri de date in C am vorbit in lectia asta. Iar despre vectori in programare am mai vorbit aici.
Asa ca hai sa vedem cum arata un vector in limbajul de programare C.
O variabila simpla o poti defini asa:
int x;
Clar, e vorba de o variabila numita x in care poti pune valori de tip numar intreg (intre anumite limite, asa cum am mai discutat).
Dar daca ai vrea ca x sa fie un vector cu 5 elemente de tip numar intreg? Ar trebui sa il definesti pe x asa:
int x[5];
Destul de intuitiv, asa-i? (Iti amintesti, cred, ca parantezele alea drepte le-ai mai folosit ca sa accesezi elementele vectorilor.)
Evident, daca voiai ca in vectorul x sa ai nu 5 elemente, ci 50, atunci ar fi trebuit doar sa modifici numarul dintre parantezele drepte din dreapta lui x:
int x[50];
Si la fel de evident cred ca ar trebui sa iti fie modul in care poti accesa elementele vectorului x.
Daca vrei sa te referi la primul element din vector, scrii x[0]; iar daca vrei sa te referi la ultimul element din vector, scrii x[49].
Ma refer aici la vectorul x definit prin ultima definitie de mai sus — caci daca x ar fi fost definit ca un vector cu 5 elemente si as scrie in program x[49], atunci as comite o eroare grava in C. (Alte limbaje de programare sunt mai “grijulii” si m-ar atentiona ca am facut o gafa, dar compilatorul de C ma trateaza ca pe un programator major si ma lasa sa fac tot ce vreau.)
Sa vedem si un exemplu de utilizare a unui vector intr-un program C:
#include <stdio.h>
void main()
{
int nota[5];
int nr;
int suma_note;
// Intai citesc cele 5 note:
printf("Ce note ai la fiecare dintre cele 5 materii?\n");
for (nr=0; nr<5; nr++) // nr++ inseamna nr=nr+1
{
printf("Nota la materia numarul %d = ", nr);
scanf("%d", ¬a[nr]);
}
// Si apoi calculez media:
suma_note = 0;
for (nr=0; nr<5; nr++)
suma_note += nota[nr];
// adica: suma_note = suma_note+nota[nr];
printf("Media notelor este %.2f.\n", suma_note/5.0);
}
Il poti compila si rula asa cum ai vazut in lectia despre CodeBlocks. Sau, daca esti pe Linux si nu ai o relatie de tip it’s complicated cu terminalul de comenzi, poti scrie acolo asa (dupa ce te-ai dus (cu instructiuni cd) in dosarul unde ai salvat programul):
gcc prog.c -oprog
./prog
In prima instructiune apelezi compilatorul de C din Linux (gcc) si ii zici sa iti compileze programul (pe care il gaseste in dosarul curent intr-un fisier text numit prog.c) si sa iti denumeasca fisierul rezultat ca iesire (adica “output”, adica optiunea “-o“) prog.
Iar cu a doua instructiune rulezi programul rezultat. Partea de dinaintea numelui (adica “./“) ii spune sa il caute in dosarul curent, si nu in locurile unde se gasesc in mod normal programele pe Linux.
Sau poti face (tot despre Linux ((L)Ubuntu) vorbesc) toate astea intr-un editor foarte simpatic numit Geany:
Wow, merge super, asa-i?
Dar cred ca e, totusi, nevoie sa explic unele lucruri pe care le-am facut pe acolo prin program…
In primul rand, cred ca ai observat comentariile care explica ce inseamna operatorii ++ si +=. Daca da, atunci cred ca ar trebui sa iti fie clar ca nr++ inseamna nr += 1.
Apoi… ce e cu ¬a[nr]? Ti-am mai zis ca functia scanf are nevoie de adresa unde sa scrie in memorie valoarea citita. Si ti-am mai zis si ca adresa unei variabile o poti obtine cu operatorul & scris inaintea numelui variabilei. Asta inseamna ca ¬a[nr] din programul nostru de mai sus inseamna & ( nota[nr] ) adica “adresa variabilei nota[nr] (care inseamna elementul de pe pozitia nr din vectorul nota (sau al (nr+1)-lea element din vectorul nota))“.
Pe langa astea, cred ca ai observat si ca dupa al doilea for nu am folosit acoladele — caci blocul lui de instructiuni contine o singura instructiune, caz in care folosirea acoladelor e optionala.
Si ce e cu expresia suma_note/5.0 din apelul functiei printf? Ce e cu 5.0, mai exact? Nu puteam sa scriu doar 5 in loc de 5.0?
Ia incearca. Scrie acolo 5, salveaza programul, compileaza-l din nou (cu gcc…) si ruleaza-l. Introdu aceleasi note ca in poza si vezi ce medie iti afiseaza…
Gata? Ai vazut ca la compilare iti da avertisment (warning) ca asteapta valoare de tip real, in vreme ce tu i-ai dat valoare de tip intreg?
Pai cum asa? Adica rezultatul impartirii lui suma_note la 5.0 e numar real, iar rezultatul impartirii lui suma_note la 5 e numar intreg?
Da. In limbajul C operatorul de impartire, /, functioneaza diferit in functie de tipul operanzilor sai. Daca ambii operanzi sunt numere de tip intreg (gen: char, int, long), atunci el calculeaza doar catul impartirii (deci rezultatul va fi tot un numar intreg). Iar daca cel putin unul dintre operanzi e numar real (gen: float, double), atunci el calculeaza rezultatul impartirii cu virgula (rezultand, deci, un numar real (adica rational, to be politically correct din punct de vedere matematic (care e singurul caz de political corectness care-mi place))).
Constanta numerica 5.0 (nu stiu daca ti-am mai spus) e de tip real, si nu intreg. (Chiar daca tu stii foarte bine ca numerele 5 si 5.0 exprima in realitate aceeasi valoare, in programare ele sunt reprezentate diferit in memoria calculatorului si operatiile care se pot face cu ele sunt diferite.)
In afara de treburile astea, cred ca programelul n-ar trebui sa iti puna probleme. Si cred ca n-ar trebui sa-ti fie greu sa il modifici incat sa faci diverse experimente cu vectori…
Apoi hai sa vedem cum e cu matricile in limbajul de programare C.
Matricile din C
Matricea din C nu e mai mult decat un vector de vectori. Matricea e ca un tabel — format din linii si coloane — in care fiecare linie este de fapt un vector. (De cazul matricilor de doua dimensiuni vorbesc aici. Pentru matricile cu 3 sau mai multe dimensiuni lucrurile stau similar, doar ca tabelele cu 3 sau mai multe dimensiuni sunt mai greu de vizualizat mental.)
Hai sa exindem exemplul anterior si sa calculam mediile nu doar pentru un elev, ci pentru mai multi (vreo 3, sa zicem).
Asa ca vom introduce in program o matrice, nota_elev, in care pentru fiecare elev dintre cel 3 vom avea cate 5 note:
int nota_elev[3][5];
Am definit astfel o matrice numita nota_elev, cu 3 linii si 5 coloane, in care fiecare element e de tip int. O poti vizualiza mental ca pe un tabel cu 3 linii si 5 coloane. Pe prima linie ai, de la stanga la dreapta, notele primul elev la fiecare dintre cele 5 materii. Pe a doua linie la fel, dar pentru cel de-al doilea elev. Si la fel pe a treia linie, pentru ultimul elev (adica elevul al treilea (sau elevul cu indexul 2)).
Iata cum ar putea arata un program care citeste direct toate cele 5 note pentru fiecare elev in parte, dupa care le calculeaza si afiseaza mediile:
#include <stdio.h>
void main() {
int nota_elev[3][5];
int nr;
int suma_note;
// Intai citesc cele 5 note pentru fiecare elev:
for (nr=0; nr<3; nr++) {
printf("Notele lui elev[%d] la fiecare dintre cele 5 materii:",
nr);
scanf("%d %d %d %d %d", ¬a_elev[nr][0], ¬a_elev[nr][1],
¬a_elev[nr][2], ¬a_elev[nr][3], ¬a_elev[nr][4]);
}
// Si apoi calculez media pentru fiecare elev:
for (nr=0; nr<3; nr++) {
suma_note = nota_elev[nr][0]+nota_elev[nr][1]+nota_elev[nr][2]+
nota_elev[nr][3]+nota_elev[nr][4];
printf("Media notelor elevului nr. %d este %.2f.\n", nr,
suma_note/5.0);
}
}
Adica asa (in Geany):
Hai sa iti pui un pic creierul la treaba acuma cu o mica tema de gandire: Cum ai modifica programul anterior astfel incat sa aduni notele fiecarui elev folosind o instructiune for (cum am facut la programul de la vectori, mai sus)?
Gata lectia asta! Voi reveni la vectori si matrici in lectia despre pointeri in C.
Pentru moment… antrenament! 🙂 (Caci asa se invata programarea, nu doar privind si citind.)
Alatura-te celor peste 7900 de oameni din armata noastra de creiere cu muschi si vei primi testul care iti va spune daca ai sau nu minte de programator.
In plus, vei fi mereu la curent cu tot ce pun la cale.
Cu drag,