Diferență între revizuiri ale paginii „PC Laborator 11”
Cbira (discuție | contribuții) |
|||
(Nu s-au afișat 23 de versiuni intermediare efectuate de alți 2 utilizatori) | |||
Linia 22: | Linia 22: | ||
<span style="color: red; font-weight: bold">Atenție</span>: Definiția unei structuri nu implică automat și existența unei variabile de tipul respectiv, așa cum definirea tipului de date <code>int</code> nu implică existența unei varibile de tip <code>int</code>. | <span style="color: red; font-weight: bold">Atenție</span>: Definiția unei structuri nu implică automat și existența unei variabile de tipul respectiv, așa cum definirea tipului de date <code>int</code> nu implică existența unei varibile de tip <code>int</code>. | ||
− | Declararea unei variabile de tipul ''Masina'' se face exact ca declararea oricărei alte | + | Declararea unei variabile de tipul ''Masina'' se face exact ca declararea oricărei alte variabile, sub forma: <tip_data> <nume_variabila>, cu observația că tipul de dată va conține și cuvântul cheie <code>struct</code>, deci acesta va fi <code>struct Masina</code>: |
<syntaxhighlight lang="c"> | <syntaxhighlight lang="c"> | ||
Linia 53: | Linia 53: | ||
int main() { | int main() { | ||
− | struct Masina | + | struct Masina masina_mea; |
printf("Care este marca masinii? "); | printf("Care este marca masinii? "); | ||
− | fgets( | + | fgets(masina_mea.marca, 100, stdin); |
printf("Care este modelul masinii? "); | printf("Care este modelul masinii? "); | ||
− | fgets( | + | fgets(masina_mea.model, 50, stdin); |
printf("Care este numarul de inmatriculare al masinii? "); | printf("Care este numarul de inmatriculare al masinii? "); | ||
− | fgets( | + | fgets(masina_mea.numarInmatriculare, 8, stdin); |
printf("Care este culoarea masinii? "); | printf("Care este culoarea masinii? "); | ||
− | fgets( | + | fgets(masina_mea.culoare, 10, stdin); |
printf("Care este anul de fabricatie a masinii? "); | printf("Care este anul de fabricatie a masinii? "); | ||
− | scanf("%hu", & | + | scanf("%hu", &masina_mea.anFabricatie); |
return 0; | return 0; | ||
Linia 85: | Linia 85: | ||
struct Masina citesteMasina() { | struct Masina citesteMasina() { | ||
− | struct Masina | + | struct Masina masina_mea; |
printf("Care este marca masinii? "); | printf("Care este marca masinii? "); | ||
− | fgets( | + | fgets(masina_mea.marca, 100, stdin); |
printf("Care este modelul masinii? "); | printf("Care este modelul masinii? "); | ||
− | fgets( | + | fgets(masina_mea.model, 50, stdin); |
printf("Care este numarul de inmatriculare al masinii? "); | printf("Care este numarul de inmatriculare al masinii? "); | ||
− | fgets( | + | fgets(masina_mea.numarInmatriculare, 8, stdin); |
printf("Care este culoarea masinii? "); | printf("Care este culoarea masinii? "); | ||
− | fgets( | + | fgets(masina_mea.culoare, 10, stdin); |
printf("Care este anul de fabricatie a masinii? "); | printf("Care este anul de fabricatie a masinii? "); | ||
− | scanf("%hu", & | + | scanf("%hu", &masina_mea.anFabricatie); |
− | return | + | return masina_mea; |
} | } | ||
Linia 118: | Linia 118: | ||
= Tipurile de date <code>union</code> = | = Tipurile de date <code>union</code> = | ||
− | + | Tipurile de tip <code>union</code> sunt identice ca sintaxă cu cele de tip <code>struct</code>, dar se comportă diferit. Spre deosebire de tipurile <code>struct</code>, unde câmpurile unei varibile ocupă zone diferite de memorie, câmpurile dintr-un <code>union</code> sunt suprapuse și ocupă aceeași zonă de memorie. Astfel, dacă se scrie într-un câmp, citirea celorlalte câmpuri va dovedi că valoarea acestora s-a modificat: | |
<syntaxhighlight lang="c"> | <syntaxhighlight lang="c"> | ||
Linia 127: | Linia 127: | ||
int value; | int value; | ||
char string[4]; | char string[4]; | ||
+ | short shorts[2]; | ||
}; | }; | ||
Linia 134: | Linia 135: | ||
* Codurile ascii pentru c, a, si l, in baza 16 sunt: | * Codurile ascii pentru c, a, si l, in baza 16 sunt: | ||
* c = 0x63 a = 0x61 l = 0x6c iar terminatorul de string este 0x00. | * c = 0x63 a = 0x61 l = 0x6c iar terminatorul de string este 0x00. | ||
− | * Ne asteptam ca value sa fie deci 0x006c6163 | + | * Ne asteptam ca value sa fie deci 0x006c6163 iar |
+ | * shorts[0] = 0x6163 (primii doi bytes in ordine inversa) | ||
+ | * shorts[1] = 0x006c (ultimii doi bytes in ordine inversa). | ||
*/ | */ | ||
strcpy(var.string, "cal"); | strcpy(var.string, "cal"); | ||
printf("var.value = 0x%08x\n", var.value); | printf("var.value = 0x%08x\n", var.value); | ||
+ | printf("var.shorts[0] = 0x%04x\n", var.shorts[0]); | ||
+ | printf("var.shorts[1] = 0x%04x\n", var.shorts[1]); | ||
return 0; | return 0; | ||
} | } | ||
+ | </syntaxhighlight> | ||
+ | * https://en.wikipedia.org/wiki/Endianness#Little-endian | ||
+ | |||
+ | = Tipurile de date <code>enum</code> = | ||
+ | |||
+ | Tipurile de date <code>enum</code> sunt utilizate pentru a defini constante (de cele mai multe ori cu valori consecutive, dar nu obligatoriu) care sunt implicit de tipul definit de <code>enum</code>. Se definesc apoi variabile de tipul <code>enum</code> respectiv, iar aceste variabile nu pot lua ca valori decât constantele definite în cadrul <code>enum</code>-ului: | ||
+ | |||
+ | <syntaxhighlight lang="c"> | ||
+ | #include <stdio.h> | ||
+ | enum Culoare { | ||
+ | NEGRU, | ||
+ | BEJ, | ||
+ | ALB, | ||
+ | VERDE, | ||
+ | ALBASTRU, | ||
+ | ROSU | ||
+ | }; | ||
+ | |||
+ | struct Masina { | ||
+ | char marca[100]; | ||
+ | char model[50]; | ||
+ | unsigned short anFabricatie; | ||
+ | char numarInmatriculare[8]; | ||
+ | enum Culoare color; | ||
+ | }; | ||
+ | |||
+ | struct Masina citesteMasina() { | ||
+ | struct Masina masina; | ||
+ | printf("Care este marca masinii? "); | ||
+ | fgets(masina.marca, 100, stdin); | ||
+ | printf("Care este modelul masinii? "); | ||
+ | fgets(masina.model, 50, stdin); | ||
+ | printf("Care este numarul de inmatriculare al masinii? "); | ||
+ | fgets(masina.numarInmatriculare, 8, stdin); | ||
+ | |||
+ | masina.color = ROSU; | ||
+ | |||
+ | printf("Care este anul de fabricatie a masinii? "); | ||
+ | scanf("%hu", &masina.anFabricatie); | ||
+ | return masina; | ||
+ | } | ||
+ | |||
+ | void afiseazaMasina(struct Masina masina){ | ||
+ | printf("Masina marca %s si modelul %s are numarul de inmatriculare " | ||
+ | "%s, culoarea %d si a fost fabricata in anul %hu!\n", | ||
+ | masina.marca, masina.model, masina.numarInmatriculare, | ||
+ | masina.color, masina.anFabricatie); | ||
+ | } | ||
+ | |||
+ | int main() { | ||
+ | struct Masina parcAuto[10]; | ||
+ | parcAuto[0] = citesteMasina(); | ||
+ | |||
+ | afiseazaMasina(parcAuto[0]); | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Tipurile de dată <code>enum</code> sunt la bază numere întregi. Când se definesc constantele dintr-un enum, dacă nu se specifică explicit valori, atunci prima constantă este implicit 0. Fiecare constantă căreia nu i se atribuie explicit o valoare, va avea implicit valoarea anterioară incrementată cu unu. Astfel, codul de mai sus rulat va afișa pentru culoare, valoarea 5. Este posibil ca două constante dintr-un <code>enum</code> să aibă aceeași valoare: | ||
+ | |||
+ | <syntaxhighlight lang="c"> | ||
+ | enum Culoare { | ||
+ | NEGRU, | ||
+ | BEJ, | ||
+ | ALB = 0, | ||
+ | VERDE, | ||
+ | ALBASTRU, | ||
+ | ROSU | ||
+ | }; | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | În exemplul de mai sus, NEGRU este 0 (implicit), BEJ este 1, ALB este 0, VERDE este 1, ALBASTRU este 2 și ROSU este 3. | ||
+ | |||
+ | O constantă definită într-un <code>enum</code>, ca și o variabilă de tip <code>enum</code> se pot converti implicit la un tip de date întreg (char, int, long, etc). Conversia inversă (de la întreg la <code>enum</code>) este permisă în C dar nu și în C++, unde este obligatoriu un operator de conversie (cast): | ||
+ | <syntaxhighlight lang="c"> | ||
+ | #include <stdio.h> | ||
+ | |||
+ | enum Culoare { | ||
+ | NEGRU, | ||
+ | BEJ, | ||
+ | ALB, | ||
+ | VERDE, | ||
+ | ALBASTRU, | ||
+ | ROSU | ||
+ | }; | ||
+ | |||
+ | int main() { | ||
+ | int valoare = NEGRU; | ||
+ | printf("%d\n", valoare); | ||
+ | |||
+ | enum Culoare color = 5; | ||
+ | printf("%d\n", color); | ||
+ | return 0; | ||
+ | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | |||
= Exerciții = | = Exerciții = | ||
+ | |||
+ | <ol> | ||
+ | <li>Definiți un <code>enum</code> numit '''CatBreed''' în care să definiți minim 5 constante de rase de pisici (dacă nu știți pe de rost, căutați pe Internet). Scrieți apoi o funcție care să ia ca argument o variabilă de tip <code>enum CatBreed</code> și să întoarcă un șir de caractere care să reprezinte numele rasei. Testați această funcție apelând-o în <code>int main</code> cu toate constantele definite din <code>enum</code> și afisând rezultatul.</li> | ||
+ | <li>Definiți o structură numită '''Cat''' ce trebuie să conțină următoarele informații: | ||
+ | <ul> | ||
+ | <li> nume </li> | ||
+ | <li> rasă (folosiți enum-ul de mai sus) </li> | ||
+ | <li> vârstă </li> | ||
+ | <li> culoare </li> | ||
+ | </ul> | ||
+ | Realizați apoi o funcție care să citească date de la tastatură și să întoarcă o variabilă de tip <code>struct Cat</code> și o altă funcție care să ia ca argument un <code>struct Cat</code> și să afișeze informațiile pe ecran. Rasa se va citi ca un număr (utilizatorul trebuie informat ce reprezintă fiecare număr). Nu uitați că după un apel de '''scanf''', în stream-ul standard de intrare va rămâne întotdeauna un caracter newline ('\n'). Dacă după un apel de '''scanf''' doriți să citiți un șir de caractere cu '''fgets''', va trebui ca înainte de acest apel să apelați o dată '''getchar()''' care va citi și elimina din stream caracterul ('\n'). | ||
+ | </li> | ||
+ | <li>Definiți o variabilă globală, de tip vector de <code>struct Cat</code> numită '''gCrazyCatLady''', de 10 pisici. În funcția '''main''', citiți apoi un număr de pisici și apoi citiți informații legate de respectivele pisici, folosind funcția de mai sus, și apoi stocând informațiile in vector. Dacă toate pisicile au culoarea "black", atunci se va afișa "The crazy cat lady is a witch!"</li> | ||
+ | <li>Pornind de la <code>union</code>-ul din exemplu, definiți o variabilă de tip <code>union CharAndInt</code> și scrieți valoarea corespunzătoare în câmpul '''value''' astfel încât afișând câmpul '''string''' ca șir de caractere să obțineți "cat".</li> | ||
+ | </ol> |
Versiunea curentă din 17 decembrie 2015 07:27
Obiective
La sfârșitul acestui laborator studenții vor fi capabili:
- să definească tipuri de date noi, de tip
struct
,union
șienum
; - să declare și să utilizele variabile de aceste tipuri în programe
Tipurile de date struct
Tipurile de date struct
sunt utilizate pentru a agrega mai multe multe varibile care au sens împreună. De exemplu, dorim să stocăm informații despre o mașină, prin urmare avem nevoie să stocăm marca, modelul, anul de fabricație, numărul de înmatriculare, culoarea, etc. Putem în acest caz să definim o structură numită Masina care să stocheze aceste valori. Variabilele care aparțin unei structuri se numesc câmpuri ale structurii. Un exemplu:
struct Masina {
char marca[100];
char model[50];
unsigned short anFabricatie;
char numarInmatriculare[8];
char culoare[10];
};
Câmpurile structurii Masina sunt: marca, model, anFabricatie, numarInmatriculare și culoare.
Atenție: Definiția unei structuri nu implică automat și existența unei variabile de tipul respectiv, așa cum definirea tipului de dateint
nu implică existența unei varibile de tipint
.
Declararea unei variabile de tipul Masina se face exact ca declararea oricărei alte variabile, sub forma: <tip_data> <nume_variabila>, cu observația că tipul de dată va conține și cuvântul cheie struct
, deci acesta va fi struct Masina
:
struct Masina {
char marca[100];
char model[50];
unsigned short anFabricatie;
char numarInmatriculare[8];
char culoare[10];
};
int main() {
struct Masina masina;
return 0;
}
Odată definită o variabilă de tip struct
, operatorul folosit pentru a accesa câmpurile structurii este .
:
#include <stdio.h>
struct Masina {
char marca[100];
char model[50];
unsigned short anFabricatie;
char numarInmatriculare[8];
char culoare[10];
};
int main() {
struct Masina masina_mea;
printf("Care este marca masinii? ");
fgets(masina_mea.marca, 100, stdin);
printf("Care este modelul masinii? ");
fgets(masina_mea.model, 50, stdin);
printf("Care este numarul de inmatriculare al masinii? ");
fgets(masina_mea.numarInmatriculare, 8, stdin);
printf("Care este culoarea masinii? ");
fgets(masina_mea.culoare, 10, stdin);
printf("Care este anul de fabricatie a masinii? ");
scanf("%hu", &masina_mea.anFabricatie);
return 0;
}
Observație: O structură poate avea câmpuri de orice tip, inclusiv de tipul altor structuri.
Un tip de dată de tip structură poate fi folosit ca orice alt tip de dată, spre exemplu pentru a crea vectori de acel tip, dar și pentru a defini funcții care au argumente sau întorc valori de acel tip:
#include <stdio.h>
struct Masina {
char marca[100];
char model[50];
unsigned short anFabricatie;
char numarInmatriculare[8];
char culoare[10];
};
struct Masina citesteMasina() {
struct Masina masina_mea;
printf("Care este marca masinii? ");
fgets(masina_mea.marca, 100, stdin);
printf("Care este modelul masinii? ");
fgets(masina_mea.model, 50, stdin);
printf("Care este numarul de inmatriculare al masinii? ");
fgets(masina_mea.numarInmatriculare, 8, stdin);
printf("Care este culoarea masinii? ");
fgets(masina_mea.culoare, 10, stdin);
printf("Care este anul de fabricatie a masinii? ");
scanf("%hu", &masina_mea.anFabricatie);
return masina_mea;
}
void afiseazaMasina(struct Masina masina){
printf("Masina marca %s si modelul %s are numarul de inmatriculare "
"%s, culoarea %s si a fost fabricata in anul %hu!\n",
masina.marca, masina.model, masina.numarInmatriculare,
masina.culoare, masina.anFabricatie);
}
int main() {
struct Masina parcAuto[10];
parcAuto[0] = citesteMasina();
afiseazaMasina(parcAuto[0]);
return 0;
}
Tipurile de date union
Tipurile de tip union
sunt identice ca sintaxă cu cele de tip struct
, dar se comportă diferit. Spre deosebire de tipurile struct
, unde câmpurile unei varibile ocupă zone diferite de memorie, câmpurile dintr-un union
sunt suprapuse și ocupă aceeași zonă de memorie. Astfel, dacă se scrie într-un câmp, citirea celorlalte câmpuri va dovedi că valoarea acestora s-a modificat:
#include <stdio.h>
#include <string.h>
union CharAndInt {
int value;
char string[4];
short shorts[2];
};
int main() {
union CharAndInt var;
/*
* Codurile ascii pentru c, a, si l, in baza 16 sunt:
* c = 0x63 a = 0x61 l = 0x6c iar terminatorul de string este 0x00.
* Ne asteptam ca value sa fie deci 0x006c6163 iar
* shorts[0] = 0x6163 (primii doi bytes in ordine inversa)
* shorts[1] = 0x006c (ultimii doi bytes in ordine inversa).
*/
strcpy(var.string, "cal");
printf("var.value = 0x%08x\n", var.value);
printf("var.shorts[0] = 0x%04x\n", var.shorts[0]);
printf("var.shorts[1] = 0x%04x\n", var.shorts[1]);
return 0;
}
Tipurile de date enum
Tipurile de date enum
sunt utilizate pentru a defini constante (de cele mai multe ori cu valori consecutive, dar nu obligatoriu) care sunt implicit de tipul definit de enum
. Se definesc apoi variabile de tipul enum
respectiv, iar aceste variabile nu pot lua ca valori decât constantele definite în cadrul enum
-ului:
#include <stdio.h>
enum Culoare {
NEGRU,
BEJ,
ALB,
VERDE,
ALBASTRU,
ROSU
};
struct Masina {
char marca[100];
char model[50];
unsigned short anFabricatie;
char numarInmatriculare[8];
enum Culoare color;
};
struct Masina citesteMasina() {
struct Masina masina;
printf("Care este marca masinii? ");
fgets(masina.marca, 100, stdin);
printf("Care este modelul masinii? ");
fgets(masina.model, 50, stdin);
printf("Care este numarul de inmatriculare al masinii? ");
fgets(masina.numarInmatriculare, 8, stdin);
masina.color = ROSU;
printf("Care este anul de fabricatie a masinii? ");
scanf("%hu", &masina.anFabricatie);
return masina;
}
void afiseazaMasina(struct Masina masina){
printf("Masina marca %s si modelul %s are numarul de inmatriculare "
"%s, culoarea %d si a fost fabricata in anul %hu!\n",
masina.marca, masina.model, masina.numarInmatriculare,
masina.color, masina.anFabricatie);
}
int main() {
struct Masina parcAuto[10];
parcAuto[0] = citesteMasina();
afiseazaMasina(parcAuto[0]);
return 0;
}
Tipurile de dată enum
sunt la bază numere întregi. Când se definesc constantele dintr-un enum, dacă nu se specifică explicit valori, atunci prima constantă este implicit 0. Fiecare constantă căreia nu i se atribuie explicit o valoare, va avea implicit valoarea anterioară incrementată cu unu. Astfel, codul de mai sus rulat va afișa pentru culoare, valoarea 5. Este posibil ca două constante dintr-un enum
să aibă aceeași valoare:
enum Culoare {
NEGRU,
BEJ,
ALB = 0,
VERDE,
ALBASTRU,
ROSU
};
În exemplul de mai sus, NEGRU este 0 (implicit), BEJ este 1, ALB este 0, VERDE este 1, ALBASTRU este 2 și ROSU este 3.
O constantă definită într-un enum
, ca și o variabilă de tip enum
se pot converti implicit la un tip de date întreg (char, int, long, etc). Conversia inversă (de la întreg la enum
) este permisă în C dar nu și în C++, unde este obligatoriu un operator de conversie (cast):
#include <stdio.h>
enum Culoare {
NEGRU,
BEJ,
ALB,
VERDE,
ALBASTRU,
ROSU
};
int main() {
int valoare = NEGRU;
printf("%d\n", valoare);
enum Culoare color = 5;
printf("%d\n", color);
return 0;
}
Exerciții
- Definiți un
enum
numit CatBreed în care să definiți minim 5 constante de rase de pisici (dacă nu știți pe de rost, căutați pe Internet). Scrieți apoi o funcție care să ia ca argument o variabilă de tipenum CatBreed
și să întoarcă un șir de caractere care să reprezinte numele rasei. Testați această funcție apelând-o înint main
cu toate constantele definite dinenum
și afisând rezultatul. - Definiți o structură numită Cat ce trebuie să conțină următoarele informații:
- nume
- rasă (folosiți enum-ul de mai sus)
- vârstă
- culoare
Realizați apoi o funcție care să citească date de la tastatură și să întoarcă o variabilă de tip
struct Cat
și o altă funcție care să ia ca argument unstruct Cat
și să afișeze informațiile pe ecran. Rasa se va citi ca un număr (utilizatorul trebuie informat ce reprezintă fiecare număr). Nu uitați că după un apel de scanf, în stream-ul standard de intrare va rămâne întotdeauna un caracter newline ('\n'). Dacă după un apel de scanf doriți să citiți un șir de caractere cu fgets, va trebui ca înainte de acest apel să apelați o dată getchar() care va citi și elimina din stream caracterul ('\n'). - Definiți o variabilă globală, de tip vector de
struct Cat
numită gCrazyCatLady, de 10 pisici. În funcția main, citiți apoi un număr de pisici și apoi citiți informații legate de respectivele pisici, folosind funcția de mai sus, și apoi stocând informațiile in vector. Dacă toate pisicile au culoarea "black", atunci se va afișa "The crazy cat lady is a witch!" - Pornind de la
union
-ul din exemplu, definiți o variabilă de tipunion CharAndInt
și scrieți valoarea corespunzătoare în câmpul value astfel încât afișând câmpul string ca șir de caractere să obțineți "cat".