Sari la conținut

NOT a MERCEDES

Members
  • Număr conținut

    81
  • Înregistrat

  • Ultima Vizită

  • Country

    Romania
  • Points

    0 [ Donate ]

Orice postat de NOT a MERCEDES

  1. ** Obiective ** Construim o structura de Utilizatori LGCS cu campuri precum : ID , Nume , Adresa de Mail , Parola , NrPosturi , isBanned dar si rolurile din care face parte ; Constituim o lista inlantuita (generica) cu toate componentele acestuia (POINTER DE REFERINTA SI INFORMATIE) Inseram date dintr-un fisier text (pe care l voi pune in atasament) . Completam lista cu toate datele din fisier ; Afisam & Eliberam Toata Lista . NOTA ** : Vom folosi proiectul din tutorialele trecute de Structuri . (Cu Roluri) ** Declarare Structura Utilizatori LGCS ** // User.h typedef struct User { // INFORMATIE UTILIZATOR unsigned id; // ID UTILIZATOR char* username; // NUME UTILIZATOR char* email; // ADRESA MAIL UTILIZATOR char* password; // PAROLA UTILIZATOR unsigned nrPosts; // NUMAR POSTURI unsigned isBanned; // NU AVEM VALOARE BOOLEANA IN C (bool) ==> "1" E TRUE && "0" E FALSE Role* roles; // Colectie de grupuri din care face parte utilizatorul }User; ** Declarare Lista Inlantuita ** // Lists.h ----> FISIER NOU typedef struct Linked_List{ // LISTA INLANTUITA GENERICA (O PUTEM FOLOSI CU ORICE TIP DE DATE FARA SA DECLARAM MAI MULTE STRUCTURI) void* Data; // Pastram informatia pentru elementul curent Linked_List* nextElement; // Ne corelam cu urmatorul element }LinkedList; // Asta reprezinta o eticheta pentru structura ==> Scriem "LinkedList" inloc de "struct Linked_List" NOTA ** : "void*" REPREZINTA un caz particular in C , o modalitatea de a substitui mai multe tipuri de date pentru a EVITA declararea Listei pentru fiecare tip de date . De exemplu , daca doresc ca lista sa fie folosita apoi , pentru structura "studenti" sau "masini" sau altceva , o putem refolosi fara sa facem lista pentru fiecare tip de structura . (tip de date) ** Preluare Utilizator din Fisier ** Declaram o functie pentru incarcarea datelor din fisier in vederea initializarii structuri : // User.h /// Structura & Restu Codului #include "roles.h" // Avem nevoie pentru tipul de date Role #define FILENAME_USER_INPUT "dateIntrareUtilizatoriLeagueCS.txt" // Definim un nume pentru intrare User* fetchUsersFromTxtFile(FILE* inputTxt,Role* roles); // Incarcam o colectie de utilizatori din fisier Ne asiguram ca putem stoca suficient spatiu pentru fiecare linie : // stringHandling.h // Restu Codului #define MAX_STRING_LINE 256 // Alocam maxim 256 de caractere pentru linii Trecem la implementarea codului pentru incarcarea utilizatorului din fisier !! // user.c #include "User.h" // legam cu fisierul asociat acestuia (de unde vin declaratiile) User* fetchUsersFromTxtFile(FILE* inputTxt, Role* roles) // Implementam functia de inserare a datelor { // Implementare } Verificam daca fisierul este eligibil pentru inserare : // user.c User* fetchUsersFromTxtFile(FILE* inputTxt, Role* roles) // Implementam functia de inserare a datelor { if (!checkFile(inputTxt)) return NULL; // Fisier Invalid + Returnam o valoare NULA Colectiei } Daca totul e ok , declaram o colectie de utilizatori dar si un contor pentru indexare : // user.c User* fetchUsersFromTxtFile(FILE* inputTxt, Role* roles) // Implementam functia de inserare a datelor { if (!checkFile(inputTxt)) return NULL; // Fisier Invalid + Returnam o valoare NULA Colectiei unsigned i = 1; // Pentru accesarea elementelor curente va fi (i-1) User* newUser = (User*)malloc(sizeof(User)); // Alocam pentru un utilizator (MOMENTAN) } Adaugam o colectie de caractere , ca intermediar , pentru preluare a linie cu linie din fisier : // user.c User* fetchUsersFromTxtFile(FILE* inputTxt, Role* roles) // Implementam functia de inserare a datelor { if (!checkFile(inputTxt)) return NULL; // Fisier Invalid + Returnam o valoare NULA Colectiei unsigned i = 1; // Pentru accesarea elementelor curente va fi (i-1) User* newUser = (User*)malloc(sizeof(User)); // Alocam pentru un utilizator (MOMENTAN) char bufferLine[MAX_STRING_LINE]; // Cu spatiu alocat explicit mai sus } Citim linie cu linie din fisier cu "fgets" (pana la finalul fisierului) iar continutul (toata linia) o oferim colectiei declarate mai sus : // user.c User* fetchUsersFromTxtFile(FILE* inputTxt, Role* roles) // Implementam functia de inserare a datelor { if (!checkFile(inputTxt)) return NULL; // Fisier Invalid + Returnam o valoare NULA Colectiei unsigned i = 1; // Pentru accesarea elementelor curente va fi (i-1) User* newUser = (User*)malloc(sizeof(User)); // Alocam pentru un utilizator (MOMENTAN) char bufferLine[MAX_STRING_LINE]; // Cu spatiu alocat explicit mai sus while ((fgets(bufferLine, MAX_STRING_LINE, inputTxt)) != NULL) // Citim Linie cu Linie din Fisier { // Implementare } } Citim si inseram in colectia de Utilizatori , informatiile despre ID , NUME , EMAIL , PAROLA , NUMAR POSTURI SI DACA E BANAT : // user.c User* fetchUsersFromTxtFile(FILE* inputTxt, Role* roles) // Implementam functia de inserare a datelor { if (!checkFile(inputTxt)) return NULL; // Fisier Invalid + Returnam o valoare NULA Colectiei unsigned i = 1; // Pentru accesarea elementelor curente va fi (i-1) User* newUser = (User*)malloc(sizeof(User)); // Alocam pentru un utilizator (MOMENTAN) char bufferLine[MAX_STRING_LINE]; // Cu spatiu alocat explicit mai sus while ((fgets(bufferLine, MAX_STRING_LINE, inputTxt)) != NULL) // Citim Linie cu Linie din Fisier { char*Token, *nextToken; // Prima va retine informatia curenta iar cealalta referinta la cea mai ramas din linie // Inseram Date /// ID Token = strtok_s(bufferLine,DELIMITATER,&nextToken); // Preluam ID-ul din linie in format de STRING newUser[i-1].id = atoi(Token); // Convertim din string in intreg + Il Incarcam in Structura // NUME Token = strtok_s(NULL, DELIMITATER, &nextToken); // Preluam NUMELE din linie in format de STRING allocAndFetchString(&newUser[i-1].username,Token); // Il Incarcam in Structura // Adresa de Mail Token = strtok_s(NULL, DELIMITATER, &nextToken); // Preluam EMAIL din linie in format de STRING allocAndFetchString(&newUser[i-1].email, Token); // Il Incarcam in Structura // Parola Token = strtok_s(NULL, DELIMITATER, &nextToken); // Preluam EMAIL din linie in format de STRING allocAndFetchString(&newUser[i-1].password, Token); // Il Incarcam in Structura // NrPosts Token = strtok_s(NULL, DELIMITATER, &nextToken); // Preluam NUMARUL DE POSTURI DIN STRUCTURA newUser[i-1].nrPosts = atoi(Token); // CONVERTIM DIN STRING IN INTREG SI IL INCARCAM // e Banat Token = strtok_s(NULL, DELIMITATER, &nextToken); // IDEM newUser[i-1].isBanned = atoi(Token); } } Acum , traversam toate rolurile inserate din tutorialul anterior iar apoi le vom asocia cu id-urile rolurilor din care face parte utilizatorul curent : // user.c User* fetchUsersFromTxtFile(FILE* inputTxt, Role* roles) // Implementam functia de inserare a datelor { if (!checkFile(inputTxt)) return NULL; // Fisier Invalid + Returnam o valoare NULA Colectiei unsigned i = 1; // Pentru accesarea elementelor curente va fi (i-1) User* newUser = (User*)malloc(sizeof(User)); // Alocam pentru un utilizator (MOMENTAN) char bufferLine[MAX_STRING_LINE]; // Cu spatiu alocat explicit mai sus while ((fgets(bufferLine, MAX_STRING_LINE, inputTxt)) != NULL) // Citim Linie cu Linie din Fisier { char*Token, *nextToken; // Prima va retine informatia curenta iar cealalta referinta la cea mai ramas din linie // Inseram Date /// ID Token = strtok_s(bufferLine,DELIMITATER,&nextToken); // Preluam ID-ul din linie in format de STRING newUser[i-1].id = atoi(Token); // Convertim din string in intreg + Il Incarcam in Structura // NUME Token = strtok_s(NULL, DELIMITATER, &nextToken); // Preluam NUMELE din linie in format de STRING allocAndFetchString(&newUser[i-1].username,Token); // Il Incarcam in Structura // Adresa de Mail Token = strtok_s(NULL, DELIMITATER, &nextToken); // Preluam EMAIL din linie in format de STRING allocAndFetchString(&newUser[i-1].email, Token); // Il Incarcam in Structura // Parola Token = strtok_s(NULL, DELIMITATER, &nextToken); // Preluam EMAIL din linie in format de STRING allocAndFetchString(&newUser[i-1].password, Token); // Il Incarcam in Structura // NrPosts Token = strtok_s(NULL, DELIMITATER, &nextToken); // Preluam NUMARUL DE POSTURI DIN STRUCTURA newUser[i-1].nrPosts = atoi(Token); // CONVERTIM DIN STRING IN INTREG SI IL INCARCAM // e Banat Token = strtok_s(NULL, DELIMITATER, &nextToken); // IDEM newUser[i-1].isBanned = atoi(Token); // Grupurile din care face parte unsigned j = 1; // (Accesul la itemul curent se va face la (j-1)) while ((Token = strtok_s(NULL, DELIMITATER, &nextToken)) != NULL) // Preluam ID cu ID { unsigned targetIdRole, k = 0; targetIdRole = atoi(Token); // Convertim ID-ul din string in intreg do { if (targetIdRole == roles[k].id) // DACA AM REGASIT ID-UL IN COLECTIE DE ROLURI { newUser[i-1].roles = j == 1 ? (Role*)malloc(sizeof(Role)) // DACA SUNTEM LA PRIMA ITERATIE : (Role*)realloc(newUser[i-1].roles, sizeof(Role) * j); // DACA SUNTEM LA J ITERATIE // Preluam Referintele (ODATA ELIBERATE ROLURILE SI ELE ISI VOR PIERDE INFORMATIA ) newUser[i-1].roles[j-1].id = roles[k].id; newUser[i-1].roles[j-1].nameRole = roles[k].nameRole; newUser[i-1].roles[j-1].isLastRole = 0; // NU ESTE ULTIMUL ELEMENT DIN LISTA break; // NU ARE ROST SA PARCURGEM TOATA STRUCTURA } k++; // Incrementam cu un pas } while(!roles[k-1].isLastRole); // Parcurgem toate rolurile PANA AJUNGEM LA ULTIMUL j++; // Marim colectia cu un element } newUser[i-1].roles[j-2].isLastRole = 1; // ESTE ULTIMUL ELEMENT DIN LISTA } } Verificam daca mai avem continut in fisier . Daca da , vom realoca un nou utilizatori (in functie de cati utilizatori sunt introdusi in fisier) . Daca nu , se opreste iteratia si se returneaza ce am adaugat : // user.c User* fetchUsersFromTxtFile(FILE* inputTxt, Role* roles) // Implementam functia de inserare a datelor { if (!checkFile(inputTxt)) return NULL; // Fisier Invalid + Returnam o valoare NULA Colectiei unsigned i = 1; // Pentru accesarea elementelor curente va fi (i-1) User* newUser = (User*)malloc(sizeof(User)); // Alocam pentru un utilizator (MOMENTAN) char bufferLine[MAX_STRING_LINE]; // Cu spatiu alocat explicit mai sus while ((fgets(bufferLine, MAX_STRING_LINE, inputTxt)) != NULL) // Citim Linie cu Linie din Fisier { char*Token, *nextToken; // Prima va retine informatia curenta iar cealalta referinta la cea mai ramas din linie // Inseram Date /// ID Token = strtok_s(bufferLine,DELIMITATER,&nextToken); // Preluam ID-ul din linie in format de STRING newUser[i-1].id = atoi(Token); // Convertim din string in intreg + Il Incarcam in Structura // NUME Token = strtok_s(NULL, DELIMITATER, &nextToken); // Preluam NUMELE din linie in format de STRING allocAndFetchString(&newUser[i-1].username,Token); // Il Incarcam in Structura // Adresa de Mail Token = strtok_s(NULL, DELIMITATER, &nextToken); // Preluam EMAIL din linie in format de STRING allocAndFetchString(&newUser[i-1].email, Token); // Il Incarcam in Structura // Parola Token = strtok_s(NULL, DELIMITATER, &nextToken); // Preluam EMAIL din linie in format de STRING allocAndFetchString(&newUser[i-1].password, Token); // Il Incarcam in Structura // NrPosts Token = strtok_s(NULL, DELIMITATER, &nextToken); // Preluam NUMARUL DE POSTURI DIN STRUCTURA newUser[i-1].nrPosts = atoi(Token); // CONVERTIM DIN STRING IN INTREG SI IL INCARCAM // e Banat Token = strtok_s(NULL, DELIMITATER, &nextToken); // IDEM newUser[i-1].isBanned = atoi(Token); // Grupurile din care face parte unsigned j = 1; // (Accesul la itemul curent se va face la (j-1)) while ((Token = strtok_s(NULL, DELIMITATER, &nextToken)) != NULL) // Preluam ID cu ID { unsigned targetIdRole, k = 0; targetIdRole = atoi(Token); // Convertim ID-ul din string in intreg do { if (targetIdRole == roles[k].id) // DACA AM REGASIT ID-UL IN COLECTIE DE ROLURI { newUser[i-1].roles = j == 1 ? (Role*)malloc(sizeof(Role)) // DACA SUNTEM LA PRIMA ITERATIE : (Role*)realloc(newUser[i-1].roles, sizeof(Role) * j); // DACA SUNTEM LA J ITERATIE // Preluam Referintele (ODATA ELIBERATE ROLURILE SI ELE ISI VOR PIERDE INFORMATIA ) newUser[i-1].roles[j-1].id = roles[k].id; newUser[i-1].roles[j-1].nameRole = roles[k].nameRole; newUser[i-1].roles[j-1].isLastRole = 0; // NU ESTE ULTIMUL ELEMENT DIN LISTA break; // NU ARE ROST SA PARCURGEM TOATA STRUCTURA } k++; // Incrementam cu un pas } while(!roles[k-1].isLastRole); // Parcurgem toate rolurile PANA AJUNGEM LA ULTIMUL j++; // Marim colectia cu un element } newUser[i-1].roles[j-2].isLastRole = 1; // ESTE ULTIMUL ELEMENT DIN LISTA if (!feof(inputTxt)) // Daca mai sunt date in fisier newUser = realloc(newUser, sizeof(User) * (++i)); // Mai alocam un utilizator } return newUser; // Returnam colectia } IN TUTORIALUL ACESTA NU VOI INTRODUCE IN LISTE , UTILIZATORI DAR VOM AFISA CONTINUTUL SI LE VOM STERGE (SUB FORMA DE ARRAY) (ASA CA BONUS ) Declaram functiile de afisare si stergere : // User.h // Restu codului void printUser(User user); void freeUser(User user); Le implementam : /// User.c // Restu Codului void printUser(User user) { static unsigned i = 0; // Retinem i pe toate apelurile printf_s("User %d : { \n",i); printf_s("\tID UTILIZATOR: %d ,\n",user.id); printf_s("\tNUME UTILIZATOR: %s ,\n",user.username); printf_s("\tADRESA MAIL UTILIZATOR: %s ,\n",user.email); printf_s("\tPAROLA : %s ,\n",user.password); printf_s("\tNUMAR POSTURI : %d ,\n", user.nrPosts); printf_s("\tESTE BANAT : %s ,\n", user.isBanned ? "DA" : "NU"); printf_s("\t\tROLURI DETINUTE : {\n"); unsigned j = 0; do { printf_s("\n\tID ROL : %d | NUME ROL :%s",user.roles[j].id,user.roles[j].nameRole); j++; } while(!user.roles[j-1].isLastRole); printf_s("\n}\n}"); i++; } void freeUser(User user) { //Stergem sirurile de caractere free(user.username); free(user.email); free(user.password); // ROLURILE VOR FI STERSE SEPARATE in functia freeRoles() } Acum , afisam in functia principala utilizatorii iar pe urma , ii stergem : // entryPoint.c /* Legam toate entry point toate headerele dependente */ #include "../StructuriDate/roles.h" #include "../StructuriDate/fileHandling.h" #include "../StructuriDate/User.h" #include "../StructuriDate//Lists.h" // stringHandling.h nu este dependent de entry point // // CONSTANTELE MACRO SUNT UTILE CA LE PUTEM UTILIZA LA NIVEL GLOBAL (PE TOT FISIERUL) // NOTA** : E O PRACTICA BUNA DE A FOLOSI MACRO SPRE DEOSEBIRE DE CONSTANTE "MAGICE" (NUMERE PRIN COD) #define NR_FILES 2 // STABILIM UN NUMAR DE FISIERE int main() { FILE** file = NULL; file = (FILE**)malloc(sizeof(FILE*)*NR_FILES); // DECLARAM O COLECTIE DE FISIERE file[0] = openFile(FILENAME_INPUT_ROLES, READMODE_TXT); // CITIM ROLURILE DINTR-UN FISIER TEXT file[1] = openFile(FILENAME_USER_INPUT, READMODE_TXT); // CITIM UTILIZATORI DINTR-UN FISIER TEXT // dateIntrareLeagueCS.txt && dateIntrareRoluriLeagueCS.txt TREBUIE SA EXISTE IN DIRECTOR (ALTFEL VA ESUA) Role* roles = fetchRoles(file[0]); // Am primit lista cu rolurile User* users = fetchUsersFromTxtFile(file[1],roles); // Am primit informatia despre utilizatori for (int i = 0; i < 6; i++) { // CUNOASTEM CA SUNT SASE ENTITATI printUser(users[i]); // Accesul prin index (Array) --> AFISAM UTILIZATORUL CURENT freeUser(users[i]); // STERGEM UTILIZATORUL CURENT } // ELIBERAM RESURSELE freeRoles(&roles); // Eliberam resursele ocupate de entitate free(users); // Stergem colectia closeFiles(&file,NR_FILES); // Eliberam resursele ocupate de fisiere if (file == NULL) printf("COLECTIA DE FISIERE A FOST ELIBERATA CU SUCCES !! "); return 0; } Si primim ca output : **FISIERUL dateIntrareRoluriLeagueCS.txt S-A DESCHIS CU SUCCES !** **FISIERUL dateIntrareUtilizatoriLeagueCS.txt S-A DESCHIS CU SUCCES !** User 0 : { ID UTILIZATOR: 0 , NUME UTILIZATOR: Alin , ADRESA MAIL UTILIZATOR: [email protected] , PAROLA : dsdasdadsadadc , NUMAR POSTURI : 100 , ESTE BANAT : NU , ROLURI DETINUTE : { ID ROL : 0 | NUME ROL : Membru ID ROL : 3 | NUME ROL : Super Moderator ID ROL : 4 | NUME ROL : Administrator ID ROL : 1 | NUME ROL : Utilizator Premium } }User 1 : { ID UTILIZATOR: 1 , NUME UTILIZATOR: Alinds , ADRESA MAIL UTILIZATOR: [email protected] , PAROLA : dsavvcvdc , NUMAR POSTURI : 50 , ESTE BANAT : NU , ROLURI DETINUTE : { ID ROL : 0 | NUME ROL : Membru ID ROL : 1 | NUME ROL : Utilizator Premium } }User 2 : { ID UTILIZATOR: 2 , NUME UTILIZATOR: Alivcxvxcn , ADRESA MAIL UTILIZATOR: [email protected] , PAROLA : dsewqqewqadc , NUMAR POSTURI : 550 , ESTE BANAT : NU , ROLURI DETINUTE : { ID ROL : 3 | NUME ROL : Super Moderator ID ROL : 1 | NUME ROL : Utilizator Premium } }User 3 : { ID UTILIZATOR: 3 , NUME UTILIZATOR: Alifdsfn , ADRESA MAIL UTILIZATOR: [email protected] , PAROLA : dsfdsfsdfsadc , NUMAR POSTURI : 3300 , ESTE BANAT : NU , ROLURI DETINUTE : { ID ROL : 0 | NUME ROL : Membru ID ROL : 1 | NUME ROL : Utilizator Premium ID ROL : 2 | NUME ROL : Moderator ID ROL : 3 | NUME ROL : Super Moderator ID ROL : 4 | NUME ROL : Administrator } }User 4 : { ID UTILIZATOR: 4 , NUME UTILIZATOR: Alie2qweqn , ADRESA MAIL UTILIZATOR: [email protected] , PAROLA : dsvcvvvvadc , NUMAR POSTURI : 11100 , ESTE BANAT : NU , ROLURI DETINUTE : { ID ROL : 0 | NUME ROL : Membru } }User 5 : { ID UTILIZATOR: 5 , NUME UTILIZATOR: Alidasdadan , ADRESA MAIL UTILIZATOR: [email protected] , PAROLA : dsvvvvvvvvradc , NUMAR POSTURI : 134300 , ESTE BANAT : NU , ROLURI DETINUTE : { ID ROL : 0 | NUME ROL : Membru ID ROL : 2 | NUME ROL : Moderator ID ROL : 1 | NUME ROL : Utilizator Premium ID ROL : 3 | NUME ROL : Super Moderator } }COLECTIA DE FISIERE A FOST ELIBERATA CU SUCCES !! NOTA ** : PENTRU A FUNCTIONA ALGORITMUL , SE POT ADAUGA UTILIZATORI LA DISCRETIA VOASTRA DOAR SA PASTREZE MODELUL : id | nume | email | parola | nrPosturi | banat(1/0) | (AICI SE ADAUGA ID-URILE ROLURILOR DIN CARE FACE PARTE DESPARTITE DE "|") ==> LINIE .... .... ... AVETI SABLONUL IN ATASAMENT dateIntrareUtilizatoriLeagueCS.txt
  2. ** Obiectiv ** Prezentare Generala A Listelor (ca structura de date) ; Afisare , printr-o diagrama , conexiunea dintre elementele listei ; Prezentare Avantaje si Dezavantaje spre deosebire de tablourile de dimensiune (arrays) . ** Listele ** Listele Inlantuite sunt structuri de date complexe , care pot inregistra , citi , modifica sau sterge anumite informatii , pe mai multe segmente(elemente) , referitor la un obiect . De exemplu , pe o lista putem stoca informatii pentru fiecare utilizator al structurii create . Mai mult , FIECARE SEGMENT ESTE LEGAT DE VECINII LUI (In functie de tipul de lista) . De regula , fiecare segment este alcatuit din doua lucruri : INFORMATIE (De exemplu , numele de utilizator , adresa de mail , parole , id etc.) POINTERUL CU REFERINTA SPRE URMATORUL ELEMENT (ELEMENTUL DE LEGATURA CU URMATORUL) ** Avantaje && Dezavantaje ** Pare a fi o structura similara cu tablourile de dimensiune (arrays) dar exista DIFERENTE : Din punct de vedere al memoriei alocate , pentru fiecare element al listei se cere o alocare atat elementului in sine cat si informatiei stocate (daca avem siruri de caractere sau colectii) spre deosebire de "arrays" , unde alocam doar tabloul in sine . (in functie de numarul de elemente * la spatiul ocupat de fiecare element) . Pe de alta parte , in liste alocam DOAR ELEMENTELE pe care le folosim spre deosebire de tablouri , unde trebuie sa aloci toate elementele , INDIFERENT DACA LE FOLOSESTI SAU NU !! . Din punct de vedere al operatiunilor de stergere & inserare , listele prezinta o eficacitate detasata . Din punct de vedere al accesul elementelor , "arrays-urile" ne permit accesul aleatoriu la un element spre deosebire de liste , unde trebuie sa parcurgem element cu element . (secvential ) PE SCURT , RECOMAND SA FOLOSIM LISTE CAND NU DORIM SA RISIPIM MEMORIE SI DORIM SA MANIPULAM DATE (INSERTII , STERGERI , MODIFICARI) . Pe de alta parte , daca dorim sa accesam mai repede anumite elemente , alegem tablourile . NOTA ** : In tutorialul urmator , vom incepe sa efectuam operatiuni cu liste inlantuite !!
  3. ** OBIECTIV ** Prin aceasta postare , dorim sa explicam si sa implementam , folosind codul de POO , conceptul de COPIERE(CLONARE) SUPERFICIALA (aka "Shallow Copy") a unui obiect !! ** Clonarea Unui Obiect ** CLONAREA/COPIEREA UNUI OBIECT reprezinta procedeul de COPIERE a informatiei (membrii clasei) dintr-un obiect (instanta) EXISTENT intr-un obiect NOU (REPLICA) . Acum , ne intrebam de ce sa clonam un obiect , in ce circumstante avem nevoie de acest concept , cu ce ne ajuta ? Pe scurt , ne sprijina prin comoditate . Ne furnizeaza o copie a unui obiect fara sa afectam obiectul original ("COPII DEFENSIVE") . Clonarea unui Obiect se poate efectua , valabil in toate limbajele de programare POO (Java,Python,JavaScript,C# etc.) , sub forma de copie : "Superficiala" sau "Shallow Copy" , se initiaza membrii clasei din obiectul clona , cu REFERINTELE din obiectul original . Pe scurt , orice modificare care survine asupra obiectului clona , VA AFECTA si OBIECTUL ORIGINAL !! (SUNT DEPENDENTE UNA DE CEALALTA) "Adanca" sau "Deep Copy" , se initiaza membrii clasei din obiectul clona , cu VALORILE din obiectul original FARA SA FIE DEPENDENTE UNA DE CEALALTA . Pe scurt , orice modificare a obiectului clona , NU VA AFECTA OBIECTUL ORIGINAL !! (SUNT INDEPENDENTE UNA DE CEALALTA) ** Constructor de Copiere ** Constructorul de copiere reprezinta al treilea tip de constructori , pe langa cel cu parametrii si implicit , si modalitatea de construire a clonelor . Aici se initializeaza membrii obiectului clona cu referintele/valorile membriilor clasei . // CONSTRUCTOR DE COPIERE -- FORMAT constructor_copiere(const NUME_CLASA& obiect_original) // Primim ca parametru , REFERINTA OBIECTULUI ORIGINAL { // AICI SE EFECTUEAZA CLONAREA OBIECTULUI ORIGINAL } NOTA** : DE ASEMENEA , IN CONSTRUCTORUL DE COPIERE PUTEM FOLOSI LISTA DE INITIALIZARE A MEMBRIILOR !!! ** IMPLEMENTARE CLONA SUPERFICIALA ** Adaugam un constructor de copiere , in cadrul clasei "Utilizator" : // user.h class User{ /// RESTU CODULUI User(const User& otherUser); // PREIA REFERINTA OBIECTULUI ORIGINAL (DECLARARE CONSTRUCTOR DE COPIERE) }; + Implementare : // User.cpp User::User(const User& originalObject) // CONSTRUCTOR DE COPIERE (COPIERE SUPERFICIALA ) : id{ originalObject.id }, nrPosts{ originalObject.nrPosts }, isBanned{originalObject.isBanned}, username{ originalObject.username }, email{ originalObject.email }, password{originalObject.password}, stringHandling{originalObject.stringHandling} { //**** OBIECTE ISI IMPART REFERINTELE (POINTERI ISI IMPART REFERINTELE) /* OBIECT ORIGINAL OBIECT CLONA username 0xda34133 --> username 0xda34133 (ISI IMPART ACEEASI ZONA DE MEMORIE) "IONEL" "IONEL" (AUTOMAT , ACEEEASI VALOARE) ==> DACA NUMELE DE UTILIZATOR(EMAIL,STRINGHANDLER,PASSWORD) SE SCHIMBA IN OBIECTUL CLONA , ATUNCI VOR APAREA MODIFICARI SI IN CEL ORIGINAL */ } In programul principal , vom initializa patru obiecte cu tipuri diferite de constructori (cu parametrii , implicit si 2 de copiere) si le vom afisa : // entrypoint.cpp #include "User.h" // Includem Clasa de Utilizatori int main() { User *user3, *user4; { User user1, user2("Vasile", "[email protected]", "vasileparola"); // Declaram doua instante (una cu constructoru implicit + constructor cu parametrii ) user1.setUsername("IONEL"); // PRODUCEM 2 CLONE user3 = new User(user1); // Clonam Obiectul 1 user4 = new User(user2); // Clonam Obiectul 2 // VIZUALIZAM OBIECTELE ATUNCI CAND OBIECTELE ORIGINALE SUNT IN CONTEXT user1.objectToString(); user2.objectToString(); std::cout << " AFISAM CLONE IN INTERIOURUL CONTEXTULUI : \n"; user3->objectToString(); // Clona Utilizatorului 1 user4->objectToString(); // Clona Utilizatorului 2 std::cout << std::endl; // DINSTANTIEM CU O LINIE CELE DOUA VIZUALIZARI } // AFISAM CLONELE ATUNCI CAND OBIECTELE ORIGINALE AU IESIT DIN CONTEXT (S-A APELAT DESTRUCTORUL) std::cout << " AFISAM CLONE IN AFARA CONTEXTULUI (CAND OBIECTUL ORIGINAL A IESIT DIN CONTEXT) : \n"; user3->objectToString(); // Clona Utilizatorului 1 user4->objectToString(); // Clona Utilizatorului 2 return 0; } Si primim ca rezultat : { ID Utilizator : 0 , Nume Utilizator : IONEL , Adresa Mail : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Parola Utilizator : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } { ID Utilizator : 1 , Nume Utilizator : Vasile , Adresa Mail : [email protected] , Parola Utilizator : vasileparola , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } AFISAM CLONE IN INTERIOURUL CONTEXTULUI : { ID Utilizator : 0 , Nume Utilizator : IONEL , Adresa Mail : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Parola Utilizator : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } { ID Utilizator : 1 , Nume Utilizator : Vasile , Adresa Mail : [email protected] , Parola Utilizator : vasileparola , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } AFISAM CLONE IN AFARA CONTEXTULUI (CAND OBIECTUL ORIGINAL A IESIT DIN CONTEXT) : { ID Utilizator : 0 , Nume Utilizator : ŢŢŢŢŢŢŢŢŢŢ , // ZONA INVALIDA DE MEMORIE Adresa Mail : ŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢ , // ZONA INVALIDA DE MEMORIE Parola Utilizator : ŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢ , // ZONA INVALIDA DE MEMORIE Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } { ID Utilizator : 1 , Nume Utilizator : ŢŢŢŢŢŢŢŢŢŢŢ , // ZONA INVALIDA DE MEMORIE Adresa Mail : ŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢ , // ZONA INVALIDA DE MEMORIE Parola Utilizator : ŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢŢ , // ZONA INVALIDA DE MEMORIE Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } NOTA* : TOTUSI , EXISTA O PROBLEMA CU ACEST PROCEDEU DE CONSTRUCTIE A CLONEI . De ce ? Daca se impart aceleasi zone de memorie , riscam sa accesam adrese invalide , astfel daca apelam destructorul pentru obiectele clone : // entryPoint.cpp int main() { // Restu Codului delete user3, user4; // AICI VOM PRIMI EROARE PENTRU CA ELIBERAM ZONE INEXISTENTE DE MEMORIE } DIN ACEASTA CAUZA , SE PREFERA CELALALT TIP DE CONSTRUCTIE , PE CARE L VOM DISCUTA IN TUTORIALUL URMATOR !!
  4. ** OBIECTIV ** Prin aceasta postare , dorim sa explicam si sa implementam , folosind codul de POO , conceptul de COPIERE(CLONARE) ADANCITA (aka "Deep Copy") a unui obiect !! Clonarea , din aceasta perspectiva , se va efectua FARA a creea dependente intre obiecte . In sensul ca , va prelua valorile din obiectele originale DAR se vor construi NOI zone de memorie !!! ** IMPLEMENTARE CLONA ADANCITA ** Adaugam un constructor de copiere , in cadrul clasei "Utilizator" (SIMILAR CU CEL SUPERFICIAL , LA DECLARATIE) : // user.h class User{ /// RESTU CODULUI User(const User& otherUser); // PREIA REFERINTA OBIECTULUI ORIGINAL (DECLARARE CONSTRUCTOR DE COPIERE) }; + Implementare : // User.cpp User::User(const User& originalObject) // CONSTRUCTOR DE COPIERE (COPIERE ADANCITA) : id{ originalObject.id }, nrPosts{ originalObject.nrPosts }, isBanned{originalObject.isBanned}, stringHandling{new StringLGCS(originalObject.username)} { //**** POINTERI ISI IMPART VALORILE , NU REFERINTELE /* OBIECT ORIGINAL OBIECT CLONA username 0xda34133 --> username 0xdc999 (ZONE SEPARATE DE MEMORIE ) "IONEL" "IONEL" (VALORI SIMILARE) */ StringLGCS::allocAndFetchString(&this->username, stringHandling->getString()); // Setam Numele de Utilizator stringHandling->setString(originalObject.email); // Schimbam sirul cu urmatoarea informatie StringLGCS::allocAndFetchString(&this->email, stringHandling->getString()); // Setam Adresa De Mail stringHandling->setString(originalObject.password); StringLGCS::allocAndFetchString(&this->password, stringHandling->getString()); // Setam Parola } In programul principal , vom initializa patru obiecte cu tipuri diferite de constructori (cu parametrii , implicit si 2 de copiere) si le vom afisa : // entryPoint.cpp #include "User.h" // Includem Clasa de Utilizatori int main() { User *user3, *user4; { User user1, user2("Vasile", "[email protected]", "vasileparola"); // Declaram doua instante (una cu constructoru implicit + constructor cu parametrii ) user1.setUsername("IONEL"); // PRODUCEM 2 CLONE user3 = new User(user1); // Clonam Obiectul 1 user4 = new User(user2); // Clonam Obiectul 2 // VIZUALIZAM OBIECTELE ATUNCI CAND OBIECTELE ORIGINALE SUNT IN CONTEXT user1.objectToString(); user2.objectToString(); std::cout << " AFISAM CLONE IN INTERIOURUL CONTEXTULUI : \n"; user3->objectToString(); // Clona Utilizatorului 1 user4->objectToString(); // Clona Utilizatorului 2 std::cout << std::endl; // DINSTANTIEM CU O LINIE CELE DOUA VIZUALIZARI } // AFISAM CLONELE ATUNCI CAND OBIECTELE ORIGINALE AU IESIT DIN CONTEXT (S-A APELAT DESTRUCTORUL) std::cout << " AFISAM CLONE IN AFARA CONTEXTULUI (CAND OBIECTUL ORIGINAL A IESIT DIN CONTEXT) : \n"; user3->objectToString(); // Clona Utilizatorului 1 user4->objectToString(); // Clona Utilizatorului 2 delete user3, user4; // TOTUL ESTE OK , SUNT ZONE SEPARATE DE MEMORIE return 0; } Si primim ca rezultat : { ID Utilizator : 0 , Nume Utilizator : IONEL , Adresa Mail : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Parola Utilizator : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } { ID Utilizator : 1 , Nume Utilizator : Vasile , Adresa Mail : [email protected] , Parola Utilizator : vasileparola , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } AFISAM CLONE IN INTERIOURUL CONTEXTULUI : { ID Utilizator : 0 , Nume Utilizator : IONEL , Adresa Mail : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Parola Utilizator : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } { ID Utilizator : 1 , Nume Utilizator : Vasile , Adresa Mail : [email protected] , Parola Utilizator : vasileparola , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } AFISAM CLONE IN AFARA CONTEXTULUI (CAND OBIECTUL ORIGINAL A IESIT DIN CONTEXT) : { ID Utilizator : 0 , Nume Utilizator : IONEL , Adresa Mail : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Parola Utilizator : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } { ID Utilizator : 1 , Nume Utilizator : Vasile , Adresa Mail : [email protected] , Parola Utilizator : vasileparola , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } NOTA * : IN CONCLUZIE , in aceasta abordare , spre deosebire de cealalta ("superficiala") , sunt construite zone de memorie NOI (DOAR VALOAREA ESTE PRELUATA DIN OBIECTELE ORIGINALE) ASTFEL DEVENIND OBIECTE INDEPENDENTE UNA DE CEALALTA , IN CIUDA CA SI IMPART ACELEASI VALORI !! TOTODATA , VOI RECOMANDA ACEASTA MODALITATE PENTRU EVITAREA ERORILOR !!
  5. Multumesc pentru feedback si sutinere . Pe zi ce trece , imi dau silinta sa aduc tutoriale la standarde cat mai bune dar si interpretabile pentru persoanele care sunt la inceput sau progreseaza . Toate bune !
  6. ** Obiectiv ** In tutorialul acesta , vom prezenta o alternativa , mult mai corecta , pentru initializarea membriilor unei clase , in semnatura constructorului . NOTA ** : Codul va fi preluat din proiectul de la tutorialele trecute de POO . (Cu mici modificari evidentiate ) ** Model ** constructor(x,y,z,...,c) : m_x{x},m_y{y},m_z{z},......,m_c{c} { // Continut Constructor } // m_x --> membru al clasei && x = parametru(variabila cu stocare locala) ** Initializarea variabilelor & Pointerilor ** // User.cpp //** Implementarea Constructorilor **// User::User() : id{ 0 }, nrPosts{ 0 }, isBanned{ false } , stringHandling{ new StringLGCS()} // Lista Constructor Membrii de Initializat { // Constructor Fara Parametrii // Alocam si Initializam date cu informatii IMPLICITE (DEFAULT ) /// FUNCTIILE STATICE SE INVOCA FOLOSIND "::" !!! StringLGCS::allocAndFetchString(&this->username, stringHandling->getString()); StringLGCS::allocAndFetchString(&this->email, stringHandling->getString()); StringLGCS::allocAndFetchString(&this->password, stringHandling->getString()); } // Idem User::User(unsigned id, const char* username, const char* email, const char* password) : id{ id }, nrPosts{ 0 }, isBanned{ false },stringHandling{new StringLGCS(username)} // IDEM { StringLGCS::allocAndFetchString(&this->username, stringHandling->getString()); // Setam Numele de Utilizator stringHandling->setString(email); // Schimbam sirul cu urmatoarea informatie StringLGCS::allocAndFetchString(&this->email , stringHandling->getString()); // Setam Adresa De Mail stringHandling->setString(password); StringLGCS::allocAndFetchString(&this->password, stringHandling->getString()); // Setam Parola } NOTA 1 ** : ACEASTA ABORDARE SE APLICA DOAR CONSTRUCTORILOR , IN SEMNATURA ACESTORA ; NOTA 2** : IN CADRUL ACESTEIA , NU ESTE NECESAR DIFERENTIEREA DINTRE MEMBRII CLASEI (Declaratia din AFARA ACOLADEI) SI CEI LOCALI (Partea din ACOLADA) NOTA 3** : PUTEM APELA , DE ASEMENEA , FUNCTII IN INTERIORUL ACOLODELOR , CONDITIA E SA RETURNEZE TIPUL DE DATE CORESPONDENT MEMBRULUI . ** Initializare Constante & Valori Statice ** O utilitate foarte importanta a acestei forme de initializare , e faptul ca ne permite sa initializam CONSTANTE !!! Pe aceasta cale , ii vom atribui id-ului fiecarui utilizator , o valoare constanta si incrementat la fiecare instantiere printr-o variabila statica . // user.h class User{ const unsigned id; // COD UNIC DE IDENTIFICARE UTILIZATOR CONSTANT --> II APLICAM ID-UL UN ATRIBUT CONSTANT (EL NU SE SCHIMBA) static inline unsigned s_id; // VALOARE STATICA INTERMEDIARA --> ADAUGAM O VALOARE STATICA PENTRU A RETINE NUMARUL DE INSTANTIERI User(const char* username, const char* email, const char* password); // --> MODIFICAM CONSTRUCTORUL , NU AVEM NEVOIE DE PARAMETRUL ID !! // Restul de declaratii }; Noua Implementare a constructorilor : /// user.cpp //** Implementarea Constructorilor **// User::User() : id{s_id++}, nrPosts{ 0 }, isBanned{ false }, // lui id ii se atribuie valoarea lui s_id iar apoi s_id se incrementeaza cu o unitate stringHandling{ new StringLGCS()} // Lista Constructor Membrii de Initializat { // Constructor Fara Parametrii // Alocam si Initializam date cu informatii IMPLICITE (DEFAULT ) /// FUNCTIILE STATICE SE INVOCA FOLOSIND "::" !!! StringLGCS::allocAndFetchString(&this->username, stringHandling->getString()); StringLGCS::allocAndFetchString(&this->email, stringHandling->getString()); StringLGCS::allocAndFetchString(&this->password, stringHandling->getString()); } // Idem User::User(const char* username, const char* email, const char* password) : id{s_id++}, nrPosts{ 0 }, isBanned{ false }, stringHandling{new StringLGCS(username)} // IDEM { StringLGCS::allocAndFetchString(&this->username, stringHandling->getString()); // Setam Numele de Utilizator stringHandling->setString(email); // Schimbam sirul cu urmatoarea informatie StringLGCS::allocAndFetchString(&this->email , stringHandling->getString()); // Setam Adresa De Mail stringHandling->setString(password); StringLGCS::allocAndFetchString(&this->password, stringHandling->getString()); // Setam Parola } Revenim la functia principala , instantiem 5 obiecte de tip Utilizator si le afisam : #include "User.h" // Includem Clasa de Utilizatori int main() { User user1, user2("Vasile", "[email protected]", "vasileparola"), user3, user4, user5; // Declaram doua instante (una cu constructoru implicit + constructor cu parametrii ) // Vizualizam Instantele user1.setUsername("IONEL"); user5.setEmail("[email protected]"); user4.setPassword("psadxc"); user1.objectToString(); // Vizualizam Instanta 1 user2.objectToString(); // Vizualizam Instanta 2 user3.objectToString(); // Vizualizam Instanta 3 user4.objectToString(); // Vizualizam Instanta 4 user5.objectToString(); // Vizualizam Instanta 5 return 0; } Afisand Obiecte , vom avea urmatorul rezultat : { ID Utilizator : 0 , Nume Utilizator : IONEL , Adresa Mail : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Parola Utilizator : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } { ID Utilizator : 1 , Nume Utilizator : Vasile , Adresa Mail : [email protected] , Parola Utilizator : vasileparola , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } { ID Utilizator : 2 , Nume Utilizator : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Adresa Mail : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Parola Utilizator : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } { ID Utilizator : 3 , Nume Utilizator : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Adresa Mail : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Parola Utilizator : psadxc , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } { ID Utilizator : 4 , Nume Utilizator : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Adresa Mail : [email protected] , Parola Utilizator : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } CONCLUZIE : PENTRU FIECARA INSTANTA , NI SE GENEREAZA UN COD UNIC DIFERIT , IN FUNCTIE DE ORDINEA INITIALIZARII !!!
  7. ** Obiectiv ** Prin acest tutorial , dorim , pe baza proiectul actual , sa printam rezultatele atat intr-un fisier text (inteles de utilizator) cat si binar (inteles de catre calculator) . ** Implementare ** 1. In Contextul "fileHandling" , definim doua CONSTANTE (Pentru Scriere in Binar si in Fisier Text) si doua functii pentru validarea unui fisier dar si pentru eliberarea colectiilor de fisiere (+ inchiderea fiecarui fisier care face parte) // fileHandling.h #include "stdlib.h" // pentru malloc/free #define WRITEMODE_TXT "w" // CONSTANTA SCRIERE IN FISIERE TEXT (IN)EXISTENTE IN DIRECTOR #define WRITEMODE_BINARY "wb" // CONSTANTA SCRIERE IN FISIERE BINARE (IN)EXISTENTE IN DIRECTOR int checkFile(FILE* file); // validam fisierul void closeFiles(FILE*** files, const unsigned nrFiles); // Preluam prin adresa colectia de fisiere + numarul acestora // ++ RESTU DE FISIER Implementarea Acestora : // fileHandling.c // Restu de fisier int checkFile(FILE* file) { return file ? 1 : 0; // VERIFICAM DACA FISIERUL EXISTA IN MEMORIE } void closeFiles(FILE*** files,const unsigned nrFiles) // Eliberam colectia de fisiere { for (int i = 0; i < nrFiles; i++) fclose((*files)[i]); // Eliberam fiecare fisier // Eliberam colectia de fisiere free(*files); *files = NULL; } 2. In Contextul "roles" , declaram numele fisierelor pe care dorim sa le operam (scriere) dar si functiile de afisare in fisiere a rolurilor : // roles.h // ++ restu de fisier #include "fileHandling.h" #define FILENAME_OUTPUT_ROLES "dateIesireRoluriLeagueCS.txt" #define FILENAME_OUTPUT_ROLES_BINARY "dateIesireRoluriLeagueCS.bin" // Functiile pentru afisare void showRolesOnFile(Role* roles, FILE* rolesOuputText); void writeRolesOnBinaryData(Role* roles, FILE* rolesOutputBinary); Si Implementarile acestora : //roles.c // ++ Restu de fisier void showRolesOnFile(Role* roles, FILE* rolesOuputText) { // fprintf_s --> este functia care ne permite sa scriem in fisiere if (!checkFile(rolesOuputText) || roles == NULL) // Avem un fisier invalid return; // NU CONTINUAM //Daca e ok unsigned i = 0; fprintf_s(rolesOuputText," Colectia de Roluri : { \n"); do { // Parcurgem colectia de roluri fprintf_s(rolesOuputText,"ID ROL : %d \t NUME ROL : %s\n", roles[i].id, roles[i].nameRole); i++; } while (!roles[i - 1].isLastRole); fprintf_s(rolesOuputText," } \n\n"); } void writeRolesOnBinaryData(Role* roles, FILE* rolesOutputBinary) { if (!checkFile(rolesOutputBinary) || roles == NULL) // FACEM O VALIDARE ATAT FISIERULUI CAT SI STRUCTURII return; // NU CONTINUAM // Daca e ok , transcriem structura in fisier : // fwrite() --> este functia pentru scrierea entitatilor in binar // unsigned i = 0; do { // Parcurgem colectia de roluri fwrite(&roles[i].id,sizeof(int),1,rolesOutputBinary); // Trecem in binar id-ul fwrite(roles[i].nameRole,sizeof(char),strlen(roles[i].nameRole), rolesOutputBinary); // Trecem numele rolului in binar i++; } while (!roles[i - 1].isLastRole); } ** Rezultate ** In functia principala , vom initializa colectia cu fisierele asociate , vom afisa rolurile atat in consola cat si in fisierele binare/text . La final , le vom elibera din memorie /* Legam toate entry point toate headerele dependente */ #include "../StructuriDate/roles.h" #include "../StructuriDate/fileHandling.h" // stringHandling.h nu este dependent de entry point // // CONSTANTELE MACRO SUNT UTILE CA LE PUTEM UTILIZA LA NIVEL GLOBAL (PE TOT FISIERUL) // NOTA** : E O PRACTICA BUNA DE A FOLOSI MACRO SPRE DEOSEBIRE DE CONSTANTE "MAGICE" (NUMERE PRIN COD) #define NR_FILES 3 // STABILIM UN NUMAR DE FISIERE int main() { FILE** file = NULL; file = (FILE**)malloc(sizeof(FILE*)*NR_FILES); // DECLARAM O COLECTIE DE FISIERE file[0] = openFile(FILENAME_INPUT_ROLES, READMODE_TXT); // CITIM ROLURILE DINTR-UN FISIER TEXT file[1] = openFile(FILENAME_OUTPUT_ROLES, WRITEMODE_TXT); // SCRIEM ROLURI INTR-UN FISIER TEXT file[2] = openFile(FILENAME_OUTPUT_ROLES_BINARY, WRITEMODE_BINARY); // SCRIEM ROLURI INTR-UN FISIER TEXT // dateIntrareLeagueCS.txt && dateIntrareRoluriLeagueCS.txt TREBUIE SA EXISTE IN DIRECTOR (ALTFEL VA ESUA) Role* roles = fetchRoles(file[0]); // Am primit lista cu rolurile showRoles(roles); // Afisam Rolurile showRolesOnFile(roles, file[1]); // Le afisam intr-un fisier text writeRolesOnBinaryData(roles,file[2]); // Le afisam intr-un fisier binar // ELIBERAM RESURSELE freeRoles(&roles); // Eliberam resursele ocupate de entitate closeFiles(&file,NR_FILES); // Eliberam resursele ocupate de fisiere if (file == NULL) printf("COLECTIA DE FISIERE A FOST ELIBERATA CU SUCCES !! "); return 0; } Rezultatul in consola : **FISIERUL dateIntrareRoluriLeagueCS.txt S-A DESCHIS CU SUCCES !** // Astea doua SUNT GENERATE DE PROGRAM !! **FISIERUL dateIesireRoluriLeagueCS.txt S-A DESCHIS CU SUCCES !** **FISIERUL dateIesireRoluriLeagueCS.bin S-A DESCHIS CU SUCCES !** Colectia de Roluri : { ID ROL : 0 NUME ROL : Membru ID ROL : 1 NUME ROL : Utilizator Premium ID ROL : 2 NUME ROL : Moderator ID ROL : 3 NUME ROL : Super Moderator ID ROL : 4 NUME ROL : Administrator } COLECTIA DE FISIERE A FOST ELIBERATA CU SUCCES !! NOTA 1 ** : In atasament , veti putea vizualiza rezultatele atat in fisier binar cat si text !! NOTA 2 ** : Fisierele careia li se aplica operatiunea de scriere , sunt GENERATE DE PROGRAM DACA NU EXISTA IN DIRECTOR !! NOTA 3 ** : ACESTE CODURI SUNT DOAR ADAUGIRI(ADAPTARI) DE LA CODUL REGASIT IN TUTORIALUL ANTERIOR DE STRUCTURI !! dateIesireRoluriLeagueCS.bin dateIesireRoluriLeagueCS.txt
  8. Nu particip la hall of fame deoarece am intrat cu activitate tarziu , pe aceasta comunitate.

    Din aceasta cauza , nu pot face o evaluare corecta , voi considera ca toata lumea din staff face o treaba corecta si sar in ajutor atunci cand e necesar.

    Totusi , va multumesc frumos pentru cei ce m au nominalizat si bineinteles , cel mai bun sa castige ! Toate Bune !

    1. PinkyQueen @ LCS

      PinkyQueen @ LCS

      Eu te am votat din cauza topicurilor tale frumos aranjate, îmi place munca ta de până acuma :) 

  9. ** Problema Reala ** Operatorii de incrementare ("++") si decrementare("--") , dupa cum cunoastem , pot fi situati atat inainte de variabila cat si dupa variabila . Prima poarta denumire de pre-(in/de)crementare iar cea de a doua , post-(in/de)crementare . Am trecut "in/de" deoarece desi , sunt operatiuni diametral opuse (una creste si cealalalta scade cu o unitate) , acestea au o problema comuna . Totusi , care-i problema ? Problema e constituita de DIFERENTA dintre post/pre . Astfel , ca intr-un anumit context , ele pot avea intelesuri diferite . ** Situatia 1 ** #include <stdio.h> int main() { // Sa presupunem doua variabile intregi int i = 0, j = 0; // In Situatia 1 : i++; // PostIncrementare cu o unitate ++j; // PreIncrementare cu o unitate printf("i : %d : \t j : %d \n", i,j); // Afisam // i = 0 ; j = 0 // Ambele se insumeaza cu o unitate // La fel si Decrementarea i--; // PostDecrementare cu o unitate --j; // PreDecrementare cu o unitate printf("i : %d : \t j : %d \n", i, j); // Afisam // i == 0 ; j == 0 return 0; } OBSERVATIE ** : IN ACEST CONTEXT , NU EXISTA DIFERENTE INTRE POST/PRE (IN/DE)CREMENTARE !! ** SITUATIE 2 ** : #include <stdio.h> int main() { // SITUATIE 2 // Sa presupunem ca adaugam inca o variabila int k = 0; //** **/ Si dorim efectuam o postincrementare k = i++; // i == 1 && k == 0 // K PREIA VALOAREA LUI I (0) INAINTE DE INCREMENTARE !!! printf("k : %d : \t i : %d \n", k, i); // Afisam j = i--; // j == 1 && i = 0 // J PREIA VALOAREA LUI I (1) INAINTE DE DECREMENTARE !!! printf("j : %d : \t i : %d \n", j, i); // Afisam // PRE-IN(DE)CREMENTARE k = ++i; /// k == 1 & i == 1 // LUI K II SE ATRIBUIE VALOAREA DEJA INCREMENTATA A LUI I !! printf("k : %d : \t i : %d \n", k, i); // Afisam j = --i; // j == 0 && i == 0 // LUI J II SE ATRIBUIE VALOAREA DEJA DECREMENTATA A LUI I !! printf("J : %d : \t i : %d \n", j, i); // Afisam return 0; } ** PE SCURT ** : PRE(IN)DECREMENTAREA PRIORITIZEAZA INCREMENTAREA IAR APOI , ATRIBUIREA !!! (POATE FI CEVA MAI RAPID DECAT A DOUA VARIANTA !) POST(IN)DECREMENTAREA PRIORITIZEAZA ATRIBUIREA IAR APOI , INCREMENTAREA !!!
  10. ** Organizarea Claselor ** Cu cat proiectul primeste mai multe implementari , spre exemplu : mai multe clase , mai multe functii samd. , cu atat acesta devine mai greu de citit . In acest context , a aparut necesitatea de a organiza clasele pe mai multe fisiere . Pentru fiecare clasa , se constituie doua fisiere : unu de tip antent sau "header" ce detine declaratiile clasei si a componentelor acestuia . unu de tip sursa ce detine implementarile(functionalitatile) declarate. NOTA ** : Aceasta abordare ne confera o LIZIBILITATE mai buna a codului . (O intelegere mai buna a codului prin redimensionarea liniilor de cod la fiecare fisier) . Practic , mai bine preferam 6 fisiere cu cate 50 de linii de cod decat un fisier cu 300 . ** Exemplu ** Sa presupunem ca avem proiectul nostru de POO (Programarea Orientata Pe Obiecte) , codul fiind incapsulat intr-un singur fisier . Scopul acestui tutorial , va fi de a impartii acele linii de cod pe mai multe fisiere . (Ne va ajuta in tutorialele urmatoare cand vom complica lucrurile !!) 1. Declaram o clasa ce manipuleaza siruri de caractere (pentru alocarea sirurilor de caractere) : // StringLGCS.h #pragma once #include "string.h" // Pentru strcpy /// MANIPULATOR DE SIRURI DE CARACTERE class StringLGCS { private: char* string; public: StringLGCS(); StringLGCS(const char* source); ~StringLGCS(); // Getteri char* const getString(); // Setteri void setString(const char* source); // Alte Functii static inline void allocAndFetchString(char** target, const char* source); // E INDEPENDENT DE INSTANTE }; Cu implementarea : // StringLGCS.cpp #include "StringLGCS.h" // Asociem cu fisierul antent // Implementari StringLGCS::StringLGCS() // Constructor Default { const char* defaultLGCSString = "BINE AI VENIT PE COMUNITATEA LEAGUECS!!!"; allocAndFetchString(&this->string,defaultLGCSString); } // Constructor cu Parametrii StringLGCS::StringLGCS(const char* source) { allocAndFetchString(&this->string,source); } // Destructor StringLGCS::~StringLGCS() { // Eliberam memoria ocupata de sir delete string; string = NULL; } // Getteri && Setteri char* const StringLGCS::getString() { return string; } void StringLGCS::setString(const char* source) { delete this->string; // Stergem allocAndFetchString(&string,source); // Realocam pentru alt sir de caractere } inline void StringLGCS::allocAndFetchString(char** target, const char* source) { size_t sizeTarget = strlen(source) + 1; *target = new char[sizeTarget]; // Alocam Spatiu pentru sir de caractere strcpy_s(*target, sizeTarget, source); } // Alte Functii 2. Adaugam Clasa de Utilizatori : #pragma once // User.h --> Fisier Antent #include "StringLGCS.h" #include <iostream> // CLASA CU DECLARATIA MEMBRIILOR class User { private: // Sector Privat // Campuri unsigned id; // NUMAR NATURAL char* username; // SIR DE CARACTERE char* email; // SIR DE CARACTERE char* password; // SIR DE CARACTERE unsigned nrPosts; // NUMAR NATURAL bool isBanned; // E BANAT StringLGCS* stringHandling; // Manipuleaza Siruri de Caractere . public: // Sector Public /* * CONSTRUCTORI */ User(); // Constructor fara parametrii User(unsigned id, const char* username, const char* email, const char* password); // Constructor cu toti parametrii /* DESTRUCTOR */ ~User(); /* GETTERI */ unsigned const getId(); const char* const getUsername(); const char* const getEmail(); const char* const getPassword(); unsigned const getnrPosts(); bool const getisBanned(); /* SETTERI */ void setNrPosts(const unsigned nrPosts); void setIsBanned(const bool isBanned); void setUsername(const char* username); void setEmail(const char* email); void setPassword(const char* password); // Alte Functii // Vizualizare Obiect void objectToString(); // Transferam obiectul prin referinta constanta }; Cu implementarea : #include "User.h" //** Implementarea Constructorilor **// User::User() { // Constructor Fara Parametrii // Alocam si Initializam date cu informatii IMPLICITE (DEFAULT ) // Variabile cu Alocare Statica id = 0; nrPosts = 0; isBanned = false; // Variabile cu Alocare Dinamica stringHandling = new StringLGCS(); // E initializat cu o valoare implicita (default) /// FUNCTIILE STATICE SE INVOCA FOLOSIND "::" !!! StringLGCS::allocAndFetchString(&this->username, stringHandling->getString()); StringLGCS::allocAndFetchString(&this->email, stringHandling->getString()); StringLGCS::allocAndFetchString(&this->password, stringHandling->getString()); } User::User(unsigned id, const char* username, const char* email, const char* password) { this->id = id; stringHandling = new StringLGCS(username); // Apelam constructorul cu parametrii StringLGCS::allocAndFetchString(&this->username, stringHandling->getString()); // Setam Numele de Utilizator stringHandling->setString(email); // Schimbam sirul cu urmatoarea informatie StringLGCS::allocAndFetchString(&this->email , stringHandling->getString()); // Setam Adresa De Mail stringHandling->setString(password); StringLGCS::allocAndFetchString(&this->password, stringHandling->getString()); // Setam Parola this->nrPosts = 0; // Implicit this->isBanned = false; // Implicit } User::~User() { // Eliberam Resursele ocupate de siruri delete username; username = nullptr; delete email; email = nullptr; delete password; password = nullptr; delete stringHandling; stringHandling = nullptr; } unsigned const User::getId() { return this->id; } const char* const User::getUsername() { return this->username; } const char* const User::getEmail() { return this->email; } const char* const User::getPassword() { return this->password; } unsigned const User::getnrPosts() { return this->nrPosts; } bool const User::getisBanned() { return this->isBanned; } void User::setNrPosts(const unsigned nrPosts) { this->nrPosts = nrPosts; } void User::setIsBanned(const bool isBanned) { this->isBanned = isBanned; } void User::setUsername(const char* username) { stringHandling->setString(username); StringLGCS::allocAndFetchString(&this->username, username); } void User::setEmail(const char* email) { stringHandling->setString(email); StringLGCS::allocAndFetchString(&this->email, email); } void User::setPassword(const char* password) { stringHandling->setString(password); StringLGCS::allocAndFetchString(&this->password, password); } void User::objectToString() { // DOAR AFISAM CAMPURILE OBIECTULUI std::cout << "\n{" << "\nID Utilizator : " << this->id << " ,\n" << "Nume Utilizator : " << this->username << " ,\n" << "Adresa Mail : " << this->email << " ,\n" << "Parola Utilizator : " << this->password << " ,\n" << "Numar Posturi : " << this->nrPosts << ", \n" << "STATUS BANAT : " << (this->isBanned ? "ESTE INTERZIS " : "NU ESTE INTERZIS") << " PE LEAGUECS!!, \n }"; } Si Functia Centrala care ne instantiaza si afiseaza obiectele : #include "User.h" // Includem Clasa de Utilizatori int main() { User user1, user2(1, "Vasile", "[email protected]", "vasileparola"); // Declaram doua instante (una cu constructoru implicit + constructor cu parametrii ) // Vizualizam Instantele user1.setUsername("IONEL"); user1.objectToString(); // Vizualizam Instanta 1 user2.objectToString(); // Vizualizam Instanta 2 return 0; } Rezultatul final fiind : { ID Utilizator : 0 , Nume Utilizator : IONEL , Adresa Mail : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Parola Utilizator : BINE AI VENIT PE COMUNITATEA LEAGUECS!!! , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, } { ID Utilizator : 1 , Nume Utilizator : Vasile , Adresa Mail : [email protected] , Parola Utilizator : vasileparola , Numar Posturi : 0, STATUS BANAT : NU ESTE INTERZIS PE LEAGUECS!!, }
  11. ** Fisiere ** Fisierele reprezinta o alta modalitate de a inregistra , de a prelucra si de a vizualiza date , pe langa cea de la tastatura . Limbajul C ne ofera capacitate de prelucrare a fiesierelor tip : fisiere text , unde putem observa caractere de tip ASCII (litere,numere,caractere speciale precum "\t" sau "\n" pentru spatiere samd.) . Poate fi inteles de catre utilizator . fisiere binare , unde observam o succesiune de biti , ce pot reprezenta informatii precum structuri de date , imagini , fisiere compresate , sunete samd. Informatia este structurata astfel incat sa fie interpretabila de catre sistem . In schimb , utilizatorul nu l poate descifra . NOTA 1 ** : Putem efectua atat operatiuni intrare(citire) cat si iesire(scriere), pentru fiecare tip de fisier . NOTA 2 ** : VOM EFECTUA ANUMITE SCHIMBARI PE PLAN DE ORGANIZARE A FUNCTIONALITATILOR . ASTFEL CA , VOM ORGANIZA TOATE FUNCTIILE IN FISIERE SEPARATE . PENTRU FIECARE CONTEXT , VOI IMPARTII DATELE IN DOUA : FISIERE HEADER SI SURSA ASOCIATA ACESTEIA . PRIMA CONTINE DECLARATIILE VARIABILELOR,CONSTANTELOR,STRUCTURILOR SAU A FUNCTIILOR IAR CEALALTA VA PREZENTA IMPLEMENTARILE ASOCIATE ACESTORA !! MAI BINE MAI MULTE FISIERE CU 50 100 LINII DE COD DECAT UNU SINGURU CU 10000 . PROBLEMA DIN ACEST TUTORIAL : Vom introduce cateva roluri dintr-un fisier text , le vom afisa si le vom sterge din memorie (la final) . 1. Primul Context --> Prelucrearea Sirurilor de Caractere stringHandling.h --> numele fisierului (DECLARATII) // CONTINUT #pragma once #include "string.h" // Pentru strcpy_s , strlen #include "stdlib.h" // Pentru malloc // FUNCTII & CONSTANTE PENTRU MANIPULAREA SIRURILOR DE CARACTERE // MACROS #define STRING_LENGHT(string) (strlen(string)+1) // NE DETERMINA LUNGIMEA SIRULUI DE CARACTERE + 1 (NULL CARACTER) // Functii void allocAndFetchString(char** target, char* source); // PE PARCURS , VOM ADAUGA FUNCTIONALITATI NOI Si fisierul cu implementarea : #include "../StructuriDate/stringHandling.h" // Legam cu fisierul header asociat acestuia void allocAndFetchString(char** target, char* source) { size_t sizeTarget = STRING_LENGHT(source); *target = (char*)malloc(sizeTarget); // Alocam cu dimensiunea ajustata strcpy_s(*target,sizeTarget, source); // Copiem informatia spre noul string } 2. Al doilea Context --> Prelucrarea Fisierelor : #pragma once #include "stdio.h" // pentru operatiuni cu fisiere #define READMODE_TXT "r" // CONSTANTA CITIRE FISIERE TEXT EXISTENTE IN DIRECTOR /* * Primul parametru "file" va fi asociat cu fisierul pe care l deschidem * Al doilea parametru , e numele fisierului * Al treila parametru , e modalitatea de citire&scriere (SUNT 12 MODALITATI DE CITIRE/SCRIERE) * "w" --> citim fisiere text (EXISTA DEJA --> IL VA SUPRASCRIE && DACA NU --> IL VA CONSTRUI AUTOMAT) ; * "r" --> citim fisiere text (DACA NU EXISTA --> VA RETURNA EROARE) ; * "a" --> adaugare informatie fisier text (EXISTA DEJA --> IL VA SUPRASCRIE && DACA NU --> IL VA CONSTRUI AUTOMAT) ; * "wb" --> scriem in fisiere binare (idem "w") ; * "rb" --> citim in fisiere binare (idem "r") ; * "ab" --> citim in fisiere binare (idem "a") ; * "w+" --> citim & scriem in fisiere text (idem "w") ; * "r+" --> citim & scriem in fisiere text (idem "r") ; * "a+" --> citim & scriem & modificam in fisiere text (idem "a") ; * "wb+" --> citim & scriem in fisiere binare (idem "w"); * "rb+" --> citim & scriem in fisiere binare (idem "r") ; * "ab+" --> citit & scriem & modificam in fisiere binare (idem "a"); * */ // Functie care returneaza un fisier la care se asociaza numele acestuia // cat si modalitatea de citire/scriere FILE* openFile(const char* nameFile, const char* readMode); Si implementarea acestuia : fileHandling.c --> numele fisierului #include "../StructuriDate/fileHandling.h" // Asociem cu fisierul header a acestuia FILE* openFile(const char* nameFile, const char* readMode) // Aplicam modificari catre pointer { FILE* file = NULL; errno_t errFileOpen = fopen_s(&file, nameFile, readMode); // Deschidem fisierul in functie de parametrii ceruti if (errFileOpen) // DACA A INTAMPINAT O EROARE (DE EXEMPLU : NU GASESTE FISIERUL TEXT IN DIRECTOR UNDE SE AFLA SI SURSELE !!) printf("Error : %d \n", errFileOpen); else // DACA TOTUL E IN REGULA printf("**FISIERUL %s S-A DESCHIS CU SUCCES !**\n", nameFile); return file; } 3. Al treilea Context --> Operatiuni de inserare , parcurgere , modificare si stergere pentru roluri : #pragma once #include <stdlib.h> // Pentru malloc realloc #include <stdio.h> // Pentru operatiuni de intrare/iesire #include "../StructuriDate/stringHandling.h" // Folosim functiile si Constantele din acest header (allocAndFetchString) // Definim constante necesare #define MAX_BUFFER_STRING_ROLES 30 // MAXIM BITI ALOCATI PENTRU ROLURI #define DELIMITATER "|" // Delimitator pentru separarea datelor (id de nume) #define FILENAME_INPUT_ROLES "dateIntrareRoluriLeagueCS.txt" // ACEST NUME TREBUIE SA AIBA FISIER SA POATA FI CITIT // Definim Structura pentru fiecare rol typedef struct Roles { // Definim articolul Roluri cu doua campuri unsigned id; char* nameRole; unsigned isLastRole; // Aflam daca este ultimul rol }Role; // Sub aceasta eticheta putem construi instante // Definim functii pentru incarcarea , accesarea , modificarea si stergerea acestora . Role* fetchRoles(FILE* rolesInput); // Incarcam Rolurile in memorie void showRoles(Role* roles); // Afisam Rolurile void freeRoles(Role* roles); // Stergem rolurile din memorie Si implementarea acestuia : roles.c --> numele fisierului #include "../StructuriDate/roles.h" // Legam cu headerul asociat acestuia Role* fetchRoles(FILE* rolesInput) // Preluam din fisier { if (rolesInput == NULL) // FISIER NEASOCIAT SAU INVALID return NULL; // RETURNAM NULL // Daca nu Role* roles = (Role*)malloc(sizeof(Role)); // Alocam un rol pe moment char bufferLine[MAX_BUFFER_STRING_ROLES]; // Va Stoca liniile unsigned i = 1; while (fgets(bufferLine,MAX_BUFFER_STRING_ROLES, rolesInput)) // Citim fiecare linie pana nu mai avem de citi { char* pieceOfLine, * nextPieceOfLine; pieceOfLine = strtok_s(bufferLine, DELIMITATER, &nextPieceOfLine); // Preluam ID-ul (PRIMA PARTE A LINII) roles[i - 1].id = atoi(pieceOfLine); // CONVERTIM LINIA IN intreg prin "atoi" pieceOfLine = strtok_s(NULL, DELIMITATER, &nextPieceOfLine); // Preluam NUMELE (PARTEA A DOUA A LINII) allocAndFetchString(&roles[i-1].nameRole,pieceOfLine); if (!feof(rolesInput)) // Verificam daca suntem la finalul fisierului { roles[i - 1].isLastRole = 0; // Inca nu avem ultimul rol roles = realloc(roles, sizeof(Role) * (++i)); // Mai alocam spatiu pentru un rol } else //Daca da roles[i - 1].isLastRole = 1; // Avem ultimul rol } return roles; } void showRoles(Role* roles) { unsigned i = 0; printf_s(" Colectia de Roluri : { \n"); do { // Parcurgem colectia de roluri printf_s("ID ROL : %d \t NUME ROL : %s\n", roles[i].id, roles[i].nameRole); i++; } while (!roles[i-1].isLastRole); printf_s(" } \n\n"); } void freeRoles(Role** roles) { unsigned i = 0; do // Parcurgem fiecare Rol { free((*roles)[i].nameRole); // Si eliberam memoria alocata de numele rolului i++; } while (!(*roles)[i - 1].isLastRole); free(*roles); // Eliberam colectia *roles = NULL; } Al patrulea context --> Este reprezentat de "entry pointul" (punctul de start) a proiectului (Aici doar gestionam functionalitatile) : /* Legam toate entry point toate headerele dependente */ #include "../StructuriDate/roles.h" #include "../StructuriDate/fileHandling.h" // stringHandling.h nu este dependent de entry point int main() { FILE* file; file = openFile(FILENAME_INPUT_ROLES,READMODE_TXT); // dateIntrareLeagueCS.txt && dateIntrareRoluriLeagueCS.txt TREBUIE SA EXISTE IN DIRECTOR (ALTFEL VA ESUA) Role* roles = fetchRoles(file); // Am primit lista cu rolurile showRoles(roles); // Afisam Rolurile // ELIBERAM RESURSELE freeRoles(&roles); // Eliberam resursele ocupate de entitate fclose(file); // Eliberam resursele ocupate de fisier return 0; } Primim ca rezultat : Colectia de Roluri : { ID ROL : 0 NUME ROL : Membru ID ROL : 1 NUME ROL : Utilizator Premium ID ROL : 2 NUME ROL : Moderator ID ROL : 3 NUME ROL : Super Moderator ID ROL : 4 NUME ROL : Administrator } Pe scurt , am declarat si am asociat un fisier pentru a obtine date din el . Pe urma , am incarcat datele intr-o colectie de Roluri(roles , unde i poate fi in functie de cate linii s - au introdus in fisier , cu conditia de A RESPECTA MODELUL !! (id | nume_rol)) . Dupa , am afisat in consola si am eliberat resursele ocupate de colectie cat si de fisier . NOTA ** : Voi face cat de curand , un repository (GitHub) pentru a intelege mai bine organizarea fisierelor !! dateIntrareRoluriLeagueCS.txt
  12. Intr-adevar , e mult mai usor sa gestionezi un smart pointer care ne fac toate lucrurile (alocare prin constructor,eliberare prin destructor etc.) dar vreau sa arat , totusi , mecanismele din spate intr-un mod cat mai interactiv pentru incepatori (sau macar incerc) . Asa as fi putut sa folesesc string pentru "char*" , vectori si iteratori pentru colectii samd. (imi era extrem de usor) dar tind cititorului , sa i ofera o intelegere mai buna asupra cum functioneaza pointeri si colectiile , intr-un mod cat mai simplu de inteles. Oricum , voi tine si tutoriale viitoare si despre containere STL pentru a ne usura munca si a evita erorile . Multumesc frumos pentru obiecte , o seara faina !
  13. ** Referintele ** Referintele sunt tipuri de date complexe , gasite in C++ (nu in C) , care au abilitatea de a primi o referinta a oricarei variabile fara a se construi o copie . De ce ne ajuta referintele ? Cu ajutorul lor , putem transfera variabile catre o alta functie , intr-o maniera mai optima , fara a construi o copie acestuia . Cu aceasta modalitate , deducem ca exista 3 mari optiuni de transfer a parametrilor de la o functia la alta : prin valoare , argumentul va prelua o copie pe care o putem folosi pentru accesarea unei informatii . NU SE MODIFICA DUPA IESIREA DIN SUBPROGRAM ; (VALABIL IN C & C++) ; prin adresa , argumentul primeste o adresa pe care o poate folosi pentru accesarea sau inserarea/stergere/modificare a informatiei . SE MODIFICA DUPA IESIREA DIN SUBPROGRAM ; (VALABIL SI IN C SI C++) prin referinta , argumentul primeste o referinta (alias) care o poate folosi precum adresa (inserare,stergere,modificare) dar evitand pointeri . SE MODIFICA DUPA IESIREA DIN SUBPROGRAM . (RETINE : SE REGASESTE DOAR IN C++ , NU IN C) INDICATIE 1 * : Daca avem o variabila simpla (tipuri de date simple , arrays sau pointeri) folosim transferul prin valoare . (DOAR IN ACEST CONTEXT) !! INDICATIE 2* : Daca transferam obiecte (mai ales, cu multe campuri) , preferam transferul prin referinta !! ** Exemplu in C++ ** : *Transfer prin valoare : void setNrPosts(const unsigned nrPosts) // Transfer prin valoare (DOAR ACCESAM DATE DIN EL NU SI MODIFICAM) // IN ACEST CONTEXT SE PREFERA TRANSFERUL PRIN VALOARE (NU MODIFICAM SI AVEM DATE SIMPLE) { if (nrPosts > 0) // doar daca numarul de Posturi e mai mare decat 0 { this->nrPosts = nrPosts; // Atribuim membrului valoarea argumentului } } *Transfer prin adresa : void atribuireSirCaractere(char** target, const char* source) // Transfer prin adresa { // SE APLICA MODIFICARI ASUPRA ARGUMENTULUI + TREBUIE SA FIE POINTER DEOARECE ALOCAM NOI ZONE DE MEMORIE PENTRU SIRUL DE CARACTERE (TRANSFER PRIN ADRESA) // IN ACEST CONTEXT , TREBUIE SA OPTAM PENTRU TRANSFERUL PRIN ADRESA (AVEM NEVOIE CA ARGUMENTUL SA FIE POINTER!!) size_t bufferString = strlen(source) + 1; *target = new char [bufferString]; strcpy_s(*target, bufferString, source); } *Transfer prin referinta : void objectToString(Utilizator& const user) // Transferam obiectul prin referinta constanta (TRANSFERAM UN OBIECT) { // OBIECTULUI II SE VA CONSTRUI O REFERINTA CONSTANTA (NU APLICAM MODIFICARI PE ACEL OBIECT) // IN ACEASTA SITUATIE , ESTE DE PREFERABIL TRANSFERUL PRIN REFERINTA !! // DOAR AFISAM CAMPURILE OBIECTULUI cout << "\n{" << "\nID Utilizator : " << user.getId() << " ,\n" << "Nume Utilizator : " << user.getUsername() << " ,\n" << "Adresa Mail : " << user.getEmail() << " ,\n" << "Parola Utilizator : " << user.getPassword() << " ,\n" << "Numar Posturi : " << user.getnrPosts() << ", \n" << "Este Banat : " << (user.getisBanned() ? "ESTE BANAT" : "NU ESTE BANAT") << " ,\n}"; } Bineinteles , putem aplica modificari asupra referintei : .... RESTUL CODULUI (IL REGASITI IN TUTORIALELE DE POO TRECUTE) void changeObjectContent(Utilizator& user) // TRANSFER PRIN REFERINTA MODIFICABILA { user.setNrPosts(5); // APLICAM MODIFICARE ASUPRA REFERINTEI !! } int main() { Utilizator utilizator; changeObjectContent(utilizator); // Schimbam Continutul objectToString(utilizator); // Afisam Obiectul return 0; // Aici se declanseaza destructorul VASILE (La finalul functiei/programului) } Si vom avea ca rezultat : { ID Utilizator : 0 , Nume Utilizator : IMPLICIT , Adresa Mail : [email protected] , Parola Utilizator : implicitParola , Numar Posturi : 5, Este Banat : NU ESTE BANAT , } DESTRUCTORUL utilizatorului IMPLICIT A FOST DECLANSAT CU SUCCES !!
  14. Dupa o seara energica la sala
  15. ** Articole in C ** Articolele sunt tipuri de date complexe care stocheaza diferite informatii (de mai multe tipuri de date) dintr-un anumit camp . De exemplu , sa presupunem campul "utilizator" , poate stoca id-ul , numele , parola , data inregistrarii etc. (diferite tipuri de date) Articolele(din C) reprezinta aceeasi ideie de baza precum clasele din C++ doar ca nu se aplica principiile POO (Nu avem concept de incapsulare , polimorfism , mostenire etc.) NOTA** : Nu confundam cu articolele din C++ care dobandesc caracteristici POO , mai putin incapsulare (toti membrii sunt publici) spre deosebire de clasa . (unde avem si privat si protected) ** Exemplu in C ** : Definim doua articole (cu o legatura intre ele) : // Articole typedef struct Roles { // Definim articolul Roluri cu doua campuri unsigned id; char* nameRole; }Role; // Sub aceasta eticheta putem construi instante typedef struct Users { // Definim articolul Utilizatori cu 6 campuri // Articol sub alt Articol (nested) unsigned idUser; // numar natural unsigned nrPosts; // numar natural char* username; // un sir de caractere char* email; // un alt sir de caractere char* password; // alt sir de caractere Role* roles; // o colectie de roluri unsigned nrRoles;// Retinem in cate grupe se afla }User; // Sub aceasta eticheta putem construi instante /// NOTA ** : IN STRUCTURI NU PUTEM AVEA FUNCTII (In C++ e alta poveste) In a doua faza , definim rolurile pe care utilizator le poate avea : /// DEFINIM PRIN MACRO (SIRURI DE CARACTERE CONSTANTE) CATEVA ROLURI #define MEMBER "membru" #define PREMIUM "premium" #define MODERATOR "moderator" #define SUPERMODERATOR "superModerator" #define ADMINISTRATOR "administrator" /// DEFINIM NR_ROLURI MAXIM #define NR_ROLES 5 #define MAX_BUFFER_STRING 50 // Numar maxim de biti alocat pentru siruri de caractere (un caracter = un byte) Role* getRoles() // Returnam o colectie de NR_ROLES(5 roluri) { Role* roles = (Role*)malloc(sizeof(Role) * NR_ROLES); // Alocam o colectie de 5 roluri (Un Array de 5 ROLURI) const char* const newRoles[] = { MEMBER,PREMIUM,MODERATOR,SUPERMODERATOR,ADMINISTRATOR }; // INCARCAM TOATE ROLURILE INTR-O CONSTANTA DE SIRURI DE CARACTERE for (int i = 0; i < NR_ROLES; i++) // PARCURGEM CELE 5 ROLURI { roles[i].id = i; // Atribui cu indexul // atribuim rolurile din constanta in campul "nume roluri" din cadrul articolului roluri size_t bufferName = strlen(newRoles[i]) + 1; // roles[i].nameRole = (char*)malloc(sizeof(bufferName)); // Alocam spatiu pentru campu nostru strcpy_s(roles[i].nameRole,bufferName, newRoles[i]); // Copiem informatia } return roles; // Returnam rolurile inregistrate (articol incarcat) } Nota 1* : MACRO (alea cu "#define") sunt Constante care pot fi accesate la nivelul fisierului . (in toate subprogramele , mai putin cele de sus de declaratia acestora) ; Nota 2* : Cand articolul este pointer , pentru accesarea membriilor se foloseste sageata "->" . A treia parte , consta in incarcarea unui utilizator cu campurile :{ id,nume,email,parola,nrPosturi,roluri detinute} , de la tastatura : // Functia unde inregistram de la tastatura sirurile de caractere + le livram catre membrii articolului void getAndAllocString(char** target) // Alocam Dinamic fiecare sir de caracter { char temp[MAX_BUFFER_STRING]; // Definim o variabila intermediara care ne preia datele primite ca input scanf_s("%s",temp,MAX_BUFFER_STRING); // Luam Sirul de caractere de la tastatura size_t sizeString = sizeof(temp) + 1; // Alocam doar necesarul *target = (char*)malloc(sizeof(char) * sizeString); // Alocam doar memoria necesara strcpy_s(*target, sizeString, temp); // Transferam catre sirul de caractere } void insertUser(User* user , Role* role ) // L am pus pointer sa putem modifica datele , pe rol nu avem nevoie de modificari dar e colectie { printf("\n Introdu un id : "); scanf_s("%d", &user->idUser); // user.idUser ==> FOLOSIND sageata (pentru ca user e pointer) (->) accesam membrii printf("\n Introdu un nume de Utilizator : "); getAndAllocString(&user->username); printf("\n Introdu o adresa de Mail : "); getAndAllocString(&user->email); printf("\n Introdu o parola : "); getAndAllocString(&user->password); printf("\n Introdu un numar de posturi : "); scanf_s("%d", &user->nrPosts); printf("\n Dati mi un nivel de autoritate : (Pana la 5) "); scanf_s("%d", &user->nrRoles); if (user->nrRoles > NR_ROLES) // Daca nu respecta conditia user->nrRoles = 1; // Ii atribuim doar un Rol user->roles = (Role*)malloc(sizeof(Role) * user->nrRoles); // Alocam NUMARUL DE ROLURI PE CARE UTILIZATORUL IL DETINE // NOTA * : /// Aici : nrRoles = 1 ==> "membru" && nrRoles = 2 ==> "membru" & "premium" && nrRoles = 3 ==> "membru" && "premium" && "moderator" samd. // AM FOST PUTIN LENES , AM VRUT DOAR SA ARAT ACCESUL LA COLECTIA DE ROLURI ASOCIAT UTILIZATORULUI RESPECTIV for (int i = 0; i < user->nrRoles; i++) user->roles[i] = role[i]; // in functie de numarul de roluri } Afisam si eliberam utilizatorul : #include <stdio.h> // Pentru operatiuni de intrare si iesire (printf , scanfs ) #include <stdlib.h> // Pentru malloc , free #include <string.h> // Pentru operatiuni cu siruri de caracter ... Restul Codului ... void showStructure(User user) // Afisam Structura { printf_s("Utilizator : \n{\n *ID Utilizator : %d, \n *Nume Utilizator : %s, \n *Adresa Mail : %s, \n *Parola : %s ,\n *Numar Posturi : %d, \n", user.idUser, user.username, user.email, user.password, user.nrPosts); printf_s(" *Grupuri din care face parte : { \n "); for (int i = 0; i < user.nrRoles; i++) printf_s("\t*id Grup : %d | *nume Grup : %s , \n" , user.roles[i].id , user.roles[i].nameRole); // Afisam Id-urile si Grupurile asociate printf("} \n\n }"); } // NU UITAM SA ELIBERAM MEMORIA // NOTA* : TOT CE SE ALOCA SE ELIBEREAZA !!!!! void freeMemoryRoles(Role* role) { // ** Eliberam Rolurile (In aceeasi maniera cum le am alocat) for (int i = 0; i < NR_ROLES; i++) free(role[i].nameRole); // Eliberam sirurile de caracter // ** Eliberam colectia in sine free(role); role = NULL; } void freeMemoryUser(User user) { // Eliberam sirurile de caractere free(user.username); free(user.email); free(user.password); free(user.roles); // Eliberam colectia de grupuri } // Executia Subprogramelor int main() { Role* newRoles = getRoles(); // Injectam colectia cu o serie de roluri User utilizator1; // adaugam date intr-un utilizator ; insertUser(&utilizator1,newRoles); // Inseram in Structura showStructure(utilizator1); // Afisam Structura // Eliberam memoria alocata freeMemoryUser(utilizator1); freeMemoryRoles(newRoles); return 0; } Si avem ca rezultat : Utilizator : { *ID Utilizator : 1, *Nume Utilizator : alin, *Adresa Mail : [email protected], *Parola : esacca , *Numar Posturi : 443, *Grupuri din care face parte : { *id Grup : 0 | *nume Grup : membru , *id Grup : 1 | *nume Grup : premium , *id Grup : 2 | *nume Grup : moderator , } } NOTA 1* : Toate datele au fost introduse de la tastatura !! NOTA 2* : Putem introduce mai multi utilizatori !! (Voi face la urmatorul tutorial !! ) NOTA 3*: Aveti codul sursa in atasament !!! entryPoint.c
  16. ** Iterativitate vs Recursivitate ** Algoritmii , in general , pot fi implementati iterativ sau recursiv . Astfel ca , intr-o abordare iterativa folosim bucle (loopuri) iar in cea recursiva , folosim apelul repetitiv a unei functii , pentru repetarea unor parti din cod . Totusi , avem pe de o parte avantaje si dezavantaje , pentru fiecare tip de abordare. Astfel ca : Pe parte de eficienta & putere , iterativitatea este mult mai avantajoasa in defavoarea recursivitatii . In sensul ca , apelul repetat al functiilor pot consuma din memoria stack si pot ingreuna programul sau chiar , sa producem un blocaj de tip "stackoverflow" . (Supraincarcarea memoriei stack) . Plus , pe partea de iterativitate , avem un control mai bun pe numarul de repetari . Pe de alta parte , recursivitatea ofera posibilitatea de a construi un cod elegant , usor de mentinut . (Mai ales , daca discutam de o problema de natura recursiva !!) . ** Exemple in C ** Sa presupunem ca vrem sa aflam suma numerelor introduse la tastura . Abordare Iterativa #include <stdio.h> #include <stdlib.h> // Pentru malloc & free int insertArray(int** arr) // RETURNAM LUNGIMEA COLECTIEI { *arr = (int*)malloc(sizeof(int)); // Alocam colectie doar pentru un numar (MOMENTAN) char yesOrNo = 'n'; int bufferArr = 1; do { if (yesOrNo == 'y') { bufferArr++; // Marim lungimea colectiei cu +1 element *arr = (int*)realloc(*arr, sizeof(int) * bufferArr); // Mai alocam spatiu pentru un numar } printf("Dati-mi un numar : "); scanf_s("%d", &(*arr)[bufferArr-1]); // Inseram un nou element in colectie de la tastatura printf("Continuam [y/n] ?"); scanf_s(" %c", &yesOrNo, 1); // Daca yesOrNo = y (continuam) altfel iesim din functie } while (yesOrNo != 'n'); // Continuam bucla atat cat yesOrNo e DIFERIT DE 'n' return bufferArr; } int sumArray(int arr[],int bufferArr) { int sum = 0; // Initializam cu 0 for (int i = 0; i < bufferArr; i++) // Parcurgem toata colectia { sum += arr[i]; // Insumam toate elementele colectiei } return sum; } int main() { int* a = NULL; int bufferArr = insertArray(&a); // Trimitem pointerul a prin adresa (VOM MODIFICA STRUCTRURA ACESTUIA IN FUNCTIE ) si // ++ Vom returna lungimea finala in bufferArr // Afisam suma colectiei printf("\n INSUMAND TOATE VALORILE COLECTIEI VOM AVEA CA REZULTAT : %d ", sumArray(a,bufferArr)); // Eliberam Memoria Ocupata de Array (Sa prevenim Memory Leak) free(a); // Eliberam Colectia in sine a = NULL; // Setam NULL Pointer return 0; } Nota ** : In aceasta abordare , se pot observa in ambele functii , utilizarea buclelor (do-while si for) pentru inserarea , traversarea si accesarea membriilor din colectie !! Abordare Recursiva : Subprogramul de introducere a numerelor in colectie : int insertArray(int** arr) // RETURNAM LUNGIMEA COLECTIEI { // AM ALOCAT IN AFARA FUNCTIEI +1 element ca tot acest va deveni repetitiv char yesOrNo; static int index = 1; // STATIC sa retinem indexu intre apelurile recursive a functiei printf("Dati-mi un numar : "); scanf_s("%d",&(*arr)[index-1]); // Inseram un nou element in colectie de la tastatura printf("Continuam[y/n] ?"); scanf_s(" %c", &yesOrNo,1); // Primim confirmarea de la utilizare de a continua sau nu inserarea if (yesOrNo == 'n') // Daca nu continuam inserarea { return 1; // Oprim algoritmul (1 si nu 0 deoarece luam in calcul si primul element al listei ) } else { index++; // Indexu se mareste cu un element *arr = realloc(*arr, index * sizeof(int)); // Realocam inca o zona de memorie return 1 + insertArray(arr); // Apelam din nou functia de inserare pentru noul element (++ adaugam un nou elemnt ) } } Subprogramul de insumare a elementelor din colectie : int sumArray(int arr[],int bufferArr) { if (bufferArr <= 0) // Daca indexu ajunge la 0 { return 0; // returnam 0 in suma } else { int sum = sumArray(arr, bufferArr - 1) + arr[bufferArr - 1]; // Colectia se INSUMEAZA CU APELUL REPETITIV // al functiei ==> arr[bufferArr-1] + arr[bufferArr-2] + arr[bufferArr-3] + ... + arr[0] /* * * De exemplu daca avem arr = {5,3,4,5,2 } & Lungimea Colectiei : 5 sum = 2 + {5,3,4,5} ; bufferArr = 5 ; sum = 2 + 5 + {5,3,4} ; bufferArr = 4 ; sum = 7 + 4 + {5,3} ; bufferArr = 3 ; sum = 11 + 3 + {5} ; bufferArr = 2 ; sum = 14 + 5 ; bufferArr = 1 ; sum = 19 + 0 ; // BufferArr = 0 ==> Se incheie algoritmul sum = 19 ; */ return sum; } } Functia principala cu apelurile la functiile respective : #include <stdio.h> #include <stdlib.h> // Pentru realloc , malloc & free int main() { int* a = (int*)malloc(sizeof(int)); // Alocam o zona de memorie int int bufferArr = insertArray(&a);// Trimitem pointerul a prin adresa (VOM MODIFICA STRUCTRURA ACESTUIA IN FUNCTIE ) si // ++ Vom returna lungimea finala in bufferArr printf("\n INSUMAND TOATE VALORILE COLECTIEI VOM AVEA CA REZULTAT : %d ", sumArray(a,bufferArr)); // Eliberam Memoria Ocupata de Array (Sa prevenim Memory Leak) free(a); // Eliberam Colectia in sine a = NULL; // Setam NULL Pointer return 0; } NOTA 1 ** : Operatiunile de inserare , parcurgere si accesare , din cadrul colectiei , sunt efectuate prin apelurile repetitive/recursive a functiei . NOTA 2 ** : Apelurile recursive trebuie sa se faca intr-un mod controlat (Prin if-else) , altfel pot genera erori sau repetari , la infinit , al functiei . (Vom vedea in tutorialele ce urmeaza !!)
  17. ** " Ce este pointerul "this" " ? ** Pointerul "this" reprezinta o modalitate de a accesa membrii unei clase , in interiorul acesteia . Apare ca necesitate pentru evitarea conflictelor de "nume" (declarat) dintre membrii clasei si parametrii locali (argumentele unei functii , variabile locale etc.) . NOTA ** : Pointerul "this" reprezinta un concept STRICT C++ . Cu alte cuvinte , in celalalte limbaje cu paradigma POO nu avem acest concept deoarece nu exista pointeri . ** Exemplu Utilizare in C++ ** NOTA ** : Codul preluat este preluat din tutorialele trecute !! Sa presupunem ca avem constructorul cu parametrii : Utilizator(unsigned _id, const char* _username, const char* _email, const char* _password) // Constructor cu Parametrii Esentiali (Un utilizator NOU nu poate sa aiba ban sau posturi) { // Variabile cu Alocare Statica id = _id; // Preluam din parametru nrPosts = 0; // IMPLICIT 0 POSTURI LA CONSTRUCTIA UTILIZATORULUI isBanned = false; // NU E BANAT // Variabile cu Alocare Dinamica atribuireSirCaractere(&username, _username); atribuireSirCaractere(&email, _email); atribuireSirCaractere(&password, _password); } Totul e ok deoarece am evitat conflictul de "nume" dintre membrii clasei si parametrii . Practic , am pus un caracter suplimentar , "_" , ce face diferenta . Altfel : Utilizator(unsigned id, const char* username, const char* email, const char* password) // Schimba numele declarat asociate argumentelor constructorului ! // Constructor cu Parametrii Esentiali (Un utilizator NOU nu poate sa aiba ban sau posturi) { /// MEREU O VARIABILA LOCALA SAU UN ARGUMENT VOR AVEA PRIORITATE IN FATA MEMBRIILOR PRIVIND NUMELE !! // Variabile cu Alocare Statica /// APARE CONFLICTUL DE NUME SI VOR AVEA URMATOARELE EFECTE (RUNTIME SI LOGICE) : id = id; // ARGUMENTUL ID = ARGUMENTUL ID ; // Urmatorii doi sunt OK deoarece primesc valori implicite !! (Eventual la setteri vor aparea conflicte daca se pune acelasi nume la argument cu al membrului ) nrPosts = 0; // IMPLICIT 0 POSTURI LA CONSTRUCTIA UTILIZATORULUI isBanned = false; // NU E BANAT // Variabile cu Alocare Dinamica atribuireSirCaractere(&username, username); /// EROARE RUNTIME ==> USERNAME E SIR DE CARACTER CONSTANT IAR LA INCERCAREA DE A ACCESA MEMBRUL "USERNAME" va esua programul cu eroare la accesarea unei zone de memorie neexistenta !! (Pentru ca nu i s-a atribuit nimic) atribuireSirCaractere(&email, email); /// IDEM ca la prima atribuireSirCaractere(&password, password); /// IDEM ca la prima } Daca vrem sa pastram acelasi nume atat pentru membru cat si pentru argument , aplicam pointerul "*this" : Utilizator(unsigned id, const char* username, const char* email, const char* password) // Constructor cu Parametrii Esentiali (Un utilizator NOU nu poate sa aiba ban sau posturi) { // Variabile cu Alocare Statica this->id = id; // Accesam Membru cu pointerul this-> (Sageata ca E POINTER) (*this).nrPosts = 0; // SAU ASA isBanned = false; // Nu exista conflict de nume , NU AVEM DE CE sa l folosim // Variabile cu Alocare Dinamica atribuireSirCaractere(&this->username, username); atribuireSirCaractere(&(*this).email, email); atribuireSirCaractere(&this->password,password); ///// ORI "this->" ORI "(*this)." NU ARE IMPORTANTA (Recomand totusi prima varianta) } NOTA 1 * : IL PUTEM FOLOSI DOAR IN INTERIORUL CLASEI (In constructor,destructor,functii etc.) doar pentru acest scop !! NOTA 2* : NU SE POATE FOLOSI IN CADRUL FUNCTIILOR STATICE SI PENTRU ACCESAREA MEMBRIILOR STATICI (INDIFERENT CA FAC PARTE SAU NU DIN CLASA) !!
  18. ** Ce reprezinta si importanta acestuia in paradigma OOP ** Un destructor reprezinta o functie "speciala" care se ocupa de eliberarea memoriei alocate de membrii unei instante (Inchidem fisiere , diverse servicii etc.) . Practic , in constructor alocam memorie pentru membrii iar in destructor , le eliberam . ** Caracteristici ** Sunt membrii asemenea constructorilor , nu permit argumente si nu returneaza valori ; Se declanseaza , automat , la distrugerea obiectului (La iesirea din context sau la operatorul "delete") fara a fi solicitat explicit . (adica mentionat) ; NU poate fi constant sau static ; (Asemenea Constructorului) ; NU POT EXISTA MAI MULTI DESTRUCTORI (DOAR UNUL) !!! ** Nota 1 : NU EXISTA DESTRUCTOR IN majoritatea Limbajelor (cu paradigma OOP) precum C# , Java , Python etc. , deoarece au un sistem dedicat pentru gestionarea resurselor alocate !!! ** Nota 2 : E FOARTE IMPORTANT SA FOLOSIM DESTRUCTORI , de fiecare data , PENTRU A ELIBERA TOATA MEMORIA REZIDUALA ("Memory Leak") !! ** Declaratie Destructor ** ~<nume_clasa>(){ // Aici Eliberam Toata Memoria Reziduala } // De exemplu , daca avem clasa "Utilizator" , definim destructoru : ~Utilizator(){ // Continut Destructor } ** Exemplu de Utilizare Destructor ** 1. Sa presupunem ca avem o clasa "Utilizator" cu campurile : class Utilizator { private: // Sector Privat // Campuri unsigned id; // NUMAR NATURAL char* username; // SIR DE CARACTERE char* email; // SIR DE CARACTERE char* password; // SIR DE CARACTERE unsigned nrPosts; // NUMAR NATURAL bool isBanned; // E BANAT }; 2. Alocam si Initializam datele prin doi constructori : class Utilizator{ // Campuri ... public: // Sector Public /* * CONSTRUCTORI */ Utilizator() { // Constructor Default // Alocam si Initializam date cu informatii IMPLICITE (DEFAULT ) // Variabile cu Alocare Statica id = 0; nrPosts = 0; isBanned = false; // Variabile cu Alocare Dinamica atribuireSirCaractere(&username, "IMPLICIT"); atribuireSirCaractere(&email, "[email protected]"); atribuireSirCaractere(&password, "implicitParola"); } Utilizator(unsigned _id, const char* _username, const char* _email, const char* _password) // Constructor cu Parametrii Esentiali (Un utilizator NOU nu poate sa aiba ban sau posturi) { // Variabile cu Alocare Statica id = _id; // Preluam din parametru nrPosts = 0; // IMPLICIT 0 POSTURI LA CONSTRUCTIA UTILIZATORULUI isBanned = false; // NU E BANAT // Variabile cu Alocare Dinamica atribuireSirCaractere(&username, _username); atribuireSirCaractere(&email, _email); atribuireSirCaractere(&password, _password); } }; 3. Sa nu uitam de functia "atribuireSirCaractere" (Declarata inafara functiei) care ne permite sa alocam & atribuim siruri de caractere : void atribuireSirCaractere(char** target, const char* source) { size_t bufferString = strlen(source) + 1; *target = new char [bufferString]; strcpy_s(*target, bufferString, source); } 4. Adaugam cativa getteri si setteri pentru afisare /* Getteri & Setteri */ const unsigned const getId() { return id; } const char* const getUsername() { return username; } const char* const getEmail() { return email; } const char* const getPassword() { return password; } const unsigned const getnrPosts() { return nrPosts; } const bool const getisBanned() { return isBanned; } // Setteri // NU Putem seta ID-ul cuiva void setNrPosts(const unsigned _nrPosts) { if (_nrPosts > 0) // doar daca numarul de Posturi e mai mare decat 0 { nrPosts = _nrPosts; } } void setIsBanned(const bool _isBanned) { isBanned = _isBanned; } void setUsername(const char* _username) { // Realocam spatiu pentru Nume Utilizator delete username; // Delete Existing Memory // Allocate New Memory atribuireSirCaractere(&username, _username); } void setEmail(const char* _email) { // Realocam Spatiu pentru Mail delete email; // Delete Existing Memory // Allocate New Memory atribuireSirCaractere(&email, _email); } void setPassword(const char* _password) { // Realocam Spatiu pentru Parola delete password; // Delete Existing Memory // Allocate New Memory atribuireSirCaractere(&password,_password); } 5. Adaugam Destructorul clasei : class Utilizator{ // Restul Clasei... // Destructor ~Utilizator() { cout << "\nDESTRUCTORUL utilizatorului " << username << " A FOST DECLANSAT CU SUCCES !!\n"; // Eliberam memoria ocupata de variabilele alocate dinamic delete username; delete email; delete password; // Setam Pointeri pe NULL username = nullptr; email = nullptr; password = nullptr; } }; 6. In functia principala (main) , declaram obiecte noi , le initializam si vedem actiunea destructorului : #include <iostream> // Pentru OBIECTELE std::cout , std::cin using namespace std; // Pentru a substitui "std::cout" cu "cout" , "std::cin" cu "cin" etc. void atribuireSirCaractere(char** target, const char* source) { /// detalii .. } class Utilizator{ // detalii .. }; /* Functie Personalizata pentru a afisa Obiectele */ void objectToString(Utilizator& const user) // Transferam obiectul prin referinta constanta) { // DOAR AFISAM CAMPURILE OBIECTULUI cout << "\n{" << "\nID Utilizator : " << user.getId() << " ,\n" << "Nume Utilizator : " << user.getUsername() << " ,\n" << "Adresa Mail : " << user.getEmail() << " ,\n" << "Parola Utilizator : " << user.getPassword() << " ,\n" << "Numar Posturi : " << user.getnrPosts() << ", \n" << "Este Banat : " << (user.getisBanned() ? "ESTE BANAT" : "NU ESTE BANAT") << " ,\n}"; } int main() { Utilizator userVasile(1, "Vasile", "[email protected]", "vasileParola"); // Alocati static Utilizator* userIon = new Utilizator(2, "Ion", "[email protected]", "ionParola"); { // Scenariul 1 : Obiect alocat static si construit sub un context , loop etc. Utilizator defaultUser; // Setam date noi defaultUser.setUsername("Alin"); defaultUser.setEmail("[email protected]"); defaultUser.setPassword("alinPassword"); defaultUser.setNrPosts(50); objectToString(defaultUser); // Afisam Obiectul // Iesim din Context (La sfarsitul acestor acolade , obiectul iese din context si declanseaza destructorul ) } // Scenariul 2 : Obiect alocat static si construit in main objectToString(userVasile); // Afisam Vasile // Scenariul 3 : Obiect alocat dinamic si construit in main objectToString(*userIon); // Afisam Ion delete userIon; // Aici se declanseaza destructorul ION userIon = nullptr; return 0; // Aici se declanseaza destructorul VASILE (La finalul functiei/programului) } 6. Dand executie , vom avea urmatorul rezultat : { ID Utilizator : 0 , Nume Utilizator : Alin , Adresa Mail : [email protected] , Parola Utilizator : alinPassword , Numar Posturi : 50, Este Banat : NU ESTE BANAT , } DESTRUCTORUL utilizatorului Alin A FOST DECLANSAT CU SUCCES !! { ID Utilizator : 1 , Nume Utilizator : Vasile , Adresa Mail : [email protected] , Parola Utilizator : vasileParola , Numar Posturi : 0, Este Banat : NU ESTE BANAT , } { ID Utilizator : 2 , Nume Utilizator : Ion , Adresa Mail : [email protected] , Parola Utilizator : ionParola , Numar Posturi : 0, Este Banat : NU ESTE BANAT , } DESTRUCTORUL utilizatorului Ion A FOST DECLANSAT CU SUCCES !! DESTRUCTORUL utilizatorului Vasile A FOST DECLANSAT CU SUCCES !! SCENARIUL 1 : Observam ca destructorul obiectului "IMPLICIT" s-a declansat la sfarsitul acoladelor , unde a iesit din context ; SCENARIUL 2 : Destructorul obiectului "Ion" (alocat dinamic) s-a declansat , automat , la intalnirea cu operatorul "delete" . (Se distruge obiectul si iese din context) ; SCENARIUL 3 : Destructorul obiectului "Vasile" s-a declansat la sfarsitul programului (dupa ce am returnat 0 in "main") .
  19. ** Bubble Sort ** Bubble Sort sau Sortare cu Bule , este similara cu cea de selectie doar ca se compara vecinii intre ei . Consta in doua bucle iar algoritmul ia sfarsit cand nu mai exista interschimbari . ** Interpretare ** Avem o colectie cu 6 elemente : [4 , 55 , 22, 67 , 89, 90] --> valori [0 , 1 , 2 , 3, 4 ,5 ] --> indecsi Sa presupunem ca cerem sa o ordonam descrescator !!! La prima indexare : i = 0 1. 4 < 55 ==> 4 mai mic decat 55 --> efectuam interschimbare : [55,4,22,67,89,90] ; 2. 4 < 22 ==> 4 mai mic decat 22 --> efectuam interschimbare : [55,22,4,67,89,90] ; 3. 4 < 67 ==> 4 mai mic decat 67 --> efectuam interschimbare : [55,22,67,4,89,90] ; 4. 4 < 89 ==> 4 mai mic decat 89 --> efectuam interschimbare : [55,22,67,89,4,90] ; 5. 4 < 90 ==> 4 mai mic decat 90 --> efectuam interschimbare : [55,22,67,89,90,4] ; La a doua indexare : i = 1; 1. 55 > 22 ==> 55 mai mare decat 22 --> continuam ; 2. 22 < 67 ==> 22 mai mic decat 67 --> efectuam interschimbare : [55,67,22,89,90,4] ; 3. 22 < 89 ==> 22 mai mic decat 89 --> efectuam interschimbare : [55,67,89,22,90,4] ; 4. 22 < 90 ==> 22 mai mic decat 90 --> efectuam interschimbare : [55,67,89,90,22,4] ; 5. 22 > 4 ==> 22 mai mare decat 4 --> continuam La a treia indexare : i = 2 ; 1. 55 < 67 ==> 67 mai mare decat 55 --> efectuam interschimbare : [67,55,89,90,22,4] ; 2. 55 < 89 ==> 55 mai mic decat 89 --> efectuam interschimbare : [67,89,55,90,22,4] ; 3. 55 < 90 ==> 55 mai mic decat 90 --> efectuam interschimbare : [67,89,90,55,22,4] ; 4. 55 > 22 ==> 55 mai mare decat 22 --> continuam 5. 22 > 4 ==> 22 mai mare decat 4 --> continuam La a patrea iteratie : i = 3 ; 1. 67 < 89 ==> 67 mai mic decat 89 ==> efectuam interschimbare : [89,67,90,55,22,4] ; 2. 67 < 90 ==> 67 mai mic decat 90 ==> efectuam interschimbare : [89,90,67,55,22,4] ; 3. 67 > 55 ==> 67 mai mare decat 55 ==> continuam ; 4. 55 > 22 ==> 55 mai mare decat 22 ==> continuam ; 5. 22 > 4 ==> 22 mai mare decat 4 ==> continuam ; La a cincea iteratie : i = 4 ; 1. 89 < 90 ==> 89 mai mic decat 90 ==> efectuam interschimbare : [90,89,67,55,22,4] ; 2. 89 > 67 ==> 89 mai mare decat 67 ==> continuam ; 3. 67 > 55 ==> 67 mai mare decat 55 ==> continuam ; 4. 55 > 22 ==> 55 mai mare decat 22 ==> continuam ; 5. 22 > 4 ==> 22 mai mare decat 4 ==> continuam ; La a sasea iteratie : i = 5 ; 1. 90 > 89 ==> 90 mai mare decat 89 ==> continuam ; 2. 89 > 67 ==> 89 mai mare decat 67 ==> continuam ; 3. 67 > 55 ==> 67 mai mare decat 55 ==> continuam ; 4. 55 > 22 ==> 55 mai mare decat 22 ==> continuam ; 5. 22 > 4 ==> 22 mai mare decat 4 ==> continuam ; ==> NIMIC DE INTERSCHIMBAT ==> SFARSIT ALGORITM NOTA ** : Daca dorim ordine crescatoare , doar inversam comparatiile !! ** Interpretare cod C ** #include <stdio.h> #include <stdlib.h> // Pentru malloc & free int* bubbleSort(int *arr,int bufferArray) { int stillUnordered = 0; // Valoare 0 (Nu exista bool in C) for (int i = 0; i < bufferArray - 1; i++) { for (int j = 0; j < (bufferArray-i-1); j++) { if (arr[j] < arr[j + 1]) // "<" pentru descrescator si ">" pentru crescator { // Efectuam Interschimbarea int temp = arr[j]; arr[j] = arr[j + 1]; // Arr[j+1] ii va lua locul lu arr[j] arr[j + 1] = temp; // Valoarea mai mica o ducem mai in spate stillUnordered = 1; } } if (stillUnordered != 1) // Algoritmul s-a finalizat { break; // Nu mai e necesar sa rulam tot loopul } } return arr; // Returnam colectia ordonata } int main() { int arrayBuffer; printf("Cate numere doresti sa aiba colectia : "); scanf_s("%d", &arrayBuffer); int* a = (int*)malloc(arrayBuffer * sizeof(int)); // ALOCAM UN ARRAY IN FUNCTIE DE CATE NUMERE VREA UTILIZATORUL SA INTRODUCA printf("Insereaza %d numere la intamplare : \n",arrayBuffer); for (int i = 0; i < arrayBuffer; i++) { printf("colectie[%d] = ", i); scanf_s("%d", &a[i]); // Inseram numerele de la tastatura } a = bubbleSort(a,arrayBuffer); // Transferam colectia prin valoare si rezultatul o egalam cu a /// Printam Colectia printf("Printam colectia ordonata : \n"); for (int i = 0; i < arrayBuffer; i++) { printf("v[%d]=%d\n", i, a[i]); } // Eliberam Memoria Ocupata de Array (Sa prevenim Memory Leak) free(a); // Eliberam Colectia in sine a = NULL; // Setam NULL Pointer return 0; } NOTA 1 ** : ALGORITM USOR DE IMPLEMENTAT SI INTELES !! NOTA 2 ** : CU CAT COLECTIA E MAI MARE CU ATAT ALGORITMUL DEVINE MAI INEFICIENT (Timp de Executie mai mare ) ; NOTA 3 ** : DIN PRICINA NUMEROASELOR COMPARATII , SE PREFERA ALGORITMUL DE SELECTIE IN DEFAVOAREA ACESTUIA !!
  20. ** INTRODUCERE IN VARIABILE STATICE ** Variabilele Statice sunt variabile locale care isi mentin valoarea si daca ies din context . Practic , valorile statice isi pot pastra valoarea la fiecare iteratie a unei bucle sau la apelul unei functii . Ele se initializeaza astfel : static <tip_date> <numele_variabilei>; // Daca nu sunt initializate , sunt atribuite implicit cu valoarea 0 ! Exemplu de efect al variabilelor statice : for (int index = 0; index < 10; index++) { static int i; // Declaram o variabila statica int j = 0; // Declaram o variabila normala cout << "i : " << i << " | " << "j : " << j << endl; // Post Incrementam ambele variabile cu += 1 i++; j++; } Vom avea ca rezultat : i : 0 | j : 0 i : 1 | j : 0 i : 2 | j : 0 i : 3 | j : 0 i : 4 | j : 0 i : 5 | j : 0 i : 6 | j : 0 i : 7 | j : 0 i : 8 | j : 0 i : 9 | j : 0 REZUMAT ** : Variabila "i" (statica) isi PASTREAZA valoarea la fiecare iteratie (sau la iesirea din context) spre deosebire de variabila j (normala) . De asemenea , pot exista functii statice : static int getStaticValue() { static int i; return i++; } int getNonStaticValue() { int j = 0; return j++; } int main() { for (int index = 0; index < 10; index++) { cout << "i : " << getStaticValue() << " | " << "j : " << getNonStaticValue() << endl; } return 0; } /* rezultat : i : 0 | j : 0 i : 1 | j : 0 i : 2 | j : 0 i : 3 | j : 0 i : 4 | j : 0 i : 5 | j : 0 i : 6 | j : 0 i : 7 | j : 0 i : 8 | j : 0 i : 9 | j : 0 */ ** Integrare Membrii Statici in Paradigma Orientata Pe Obiecte ** Pe scurt , membrii statici isi pastreaza valoarea intre instante . Practic , ele au aceeasi valoare indiferent de instanta !! class Demo { private: // Declaram doua variabile int j; static inline int i; // inline e valabil pentru C++ 17 in sus public: Demo(int index) { j = index; i = index; } // Setam niste getteri static inline const int getI() { return i; } int const getJ() { return j; } // NOTA ** : Membrii Statici necesita "o dubla initializare" . Din acest motiv , folosim "inline" !! VALABIL DOAR PENTRU C17++ IN SUS !! }; int main() { // Instantiem O Colectie de Pointeri Demo** arrOfDemo = new Demo * [10]; for (int i = 0; i < 10; i++) { arrOfDemo[i] = new Demo(i); // Instantiem 10 obiecte de tip Demo cu i diferit } // Printam Obiectele for (int i = 0; i < 10; i++) { // Accesam i si j de la fiecare instanta cout << "Obiectul " << i << " : i = " << arrOfDemo[i]->getI() << " | " << "j : " << arrOfDemo[i]->getJ() << endl; } // Eliberam memoria ocupata de instante for (int i = 0; i < 10; i++) { delete arrOfDemo[i]; // Eliberam fiecare Instanta in parte } // Eliberam colectia si o punem pe null !! delete[] arrOfDemo; arrOfDemo = nullptr; return 0; } /* Rezultatul : Obiectul 0 : i = 9 | j : 0 Obiectul 1 : i = 9 | j : 1 Obiectul 2 : i = 9 | j : 2 Obiectul 3 : i = 9 | j : 3 Obiectul 4 : i = 9 | j : 4 Obiectul 5 : i = 9 | j : 5 Obiectul 6 : i = 9 | j : 6 Obiectul 7 : i = 9 | j : 7 Obiectul 8 : i = 9 | j : 8 Obiectul 9 : i = 9 | j : 9 // Diferenta se remarca prin faptul ca valoarea statica (i) isi pastreaza aceeasi valoare la fiecare instanta spre deosebire de cea non - statica (j) care e dependenta de obiect !! */ NOTA ** : Vom discuta in tutorialele ce urmeaza , mai in detaliu despre acesti membrii !!!
  21. ** Ce reprezinta si importanta procedeului de sortare ** Sortarea , a unei colectii , reprezinta procedeul prin care accesam si modificam POZITIA elementelor asociate acesteia , pe baza unui criteriu . De exemplu , putem ordona de la mic la mare (intr-o colectie de numere), de la A la Z (intr-o colectie de siruri de caractere) etc. Sortarea se poate efectua sub mai multe procedee , unul mai optim decat altu din punct de vedere , a timpului de executie si a resurselor alocate . Nota ** : Definim colectie orice entitate care contine o multime de elemente (array,lista,arbore etc.) ; ** In ce Consta Sortarea Prin Selectie ** Sortarea Prin Selectie se bazeaza pe doua bucle , una care acceseaza toate elementele colectiei iar cealalta , in interiorul acesteia , care compara repetitiv un element cu restul . Daca in comparatie, se gaseste un element mai mic acesta , se va efectua o interschimbare intre acestia. ** Exemplu Selectie prin Sortare ** Sa presupunem ca avem 6 numere naturale intr o colectie [44 , 22, 67, 23 , 21, 11] --> NUMERE NATURALE [0 , 1 , 2 , 3 , 4 , 5 ] --> INDECSI EFECTUAM O SORTARE A COLECTIEI DE LA MARE LA MIC : Prima Iteratie : i = 0 ; 1. 44 > 22 --> 44 mai mare decat 22 --> nu efectuam nimc --> continuam ; 2. 44 < 67 --> 44 mai mic decat 67 --> efectuam interschimbarea --> [67 , 22 , 44 , 23 , 21 , 11] ; 3. 67 > 23 --> 67 mai mare decat 23 --> nu efectuam nimc --> continuam ; 4. 67 > 21 --> 67 mai mare decat 21 --> nu efectuam nimic --> continuam ; 5. 67 > 11 --> 67 mai mare decat 11 --> nu efectuam nimic --> continuam . A doua iteratie : i = 1 ; 1. 22 < 44 --> 22 mai mic decat 44 --> efectuam interschimbarea --> [67 , 44 , 22 , 23 , 21 , 11] ; 2. 44 > 23 --> 44 mai mare decat 23 --> nu efectuam nimc --> continuam ; 3. 44 > 21 --> 44 mai mare decat 21 --> nu efectuam nimc --> continuam ; 4. 44 > 11 --> 44 mai mare decat 11 --> nu efectuam nimc --> continuam . A treia iteratie : i = 2 ; 1. 22 < 23 --> 22 mai mic decat 23 --> efectuam interschimbarea --> [67, 44 , 23 , 22 , 21 , 11] ; 2. 23 > 21 --> 23 mai mare decat 21 --> nu efectuam nimc --> continuam ; 3. 23 > 11 --> 23 mai mare decat 11 --> nu efectuam nimc --> continuam . A patra iteratie : i = 3 ; 1. 22 > 21 --> 23 mai mare decat 21 --> nu efectuam nimc --> continuam ; 2. 22 > 11 --> 22 mai mare decat 11 --> nu efectuam nimic --> continuam . A cincea iteratie : i = 4 ; 1. 21 > 11 --> 21 mai mare decat 11 --> nu efectuam nimic --> continuam . FINAL ALGORITM Algoritmul sortat de la mare la mic : [67, 44 , 23 , 22 , 21 , 11] NOTA ** : Pentru la mic la mare , doar inversam comparatia !!! Procedeul e acelasi !! ** Algoritm in C ** #include <stdio.h> #include <stdlib.h> // Pentru malloc & free void selectionSorting(int** arr , int arrayBuffer) { for (int i = 0; i < arrayBuffer - 1; i++) // Traversam toata colectia mai putin ultinmul element { for (int j = i + 1; j < arrayBuffer; j++) { if ((*arr)[i] < (*arr)[j]) // "<" PENTRU NUMERE DESCRESCATOARE IAR ">" PENTRU NUMERE CRESCATOARE { // Efectuam Algoritmul de Inteschimbare int temp = (*arr)[i]; (*arr)[i] = (*arr)[j]; (*arr)[j] = temp; } // Daca nu , continuam } } } int main() { int arrayBuffer; printf("Cate numere doresti sa aiba colectia : "); scanf_s("%d", &arrayBuffer); int* a = (int*)malloc(arrayBuffer * sizeof(int)); // ALOCAM UN ARRAY IN FUNCTIE DE CATE NUMERE VREA UTILIZATORUL SA INTRODUCA printf("Insereaza %d numere la intamplare : \n",arrayBuffer); for (int i = 0; i < arrayBuffer; i++) { printf("colectie[%d] = ", i); scanf_s("%d", &a[i]); // Inseram numerele de la tastatura } selectionSorting(&a,arrayBuffer); // Transferam colectia prin adresa /// Printam Colectia printf("Printam colectia ordonata : \n"); for (int i = 0; i < arrayBuffer; i++) { printf("v[%d]=%d\n", i, a[i]); } // Eliberam Memoria Ocupata de Array (Sa prevenim Memory Leak) free(a); // Eliberam Colectia in sine a = NULL; // Setam NULL Pointer return 0; } NOTA 1 ** : E USOR DE IMPLENTAT SI INTELES , IDEAL UNDE SE LUCREAZA CU LISTE MICI SI SIMPLITATEA E NECESARA !! NOTA 2 ** : CU CAT LISTA ESTE MAI MARE , CU ATAT VOM AVEA O COMPLEXITATE TIMP MAI MARE (MAI INEFICIENT) !!
  22. ** Algoritm de Cautare Binar ** Este un algoritm de cautare utilizat intr-o colectie SORTATA , ne ofera posibilitatea de a miscora timpul de executie (Complexitate Timp mai optim) prin divizarea repetata a intervalelor la jumatate . ** Explicatie ** Sa presupunem ca avem o colectie de 10 numere (SORTATA) : [11 , 22 , 34 , 56 , 65 , 76 , 78 , 84 , 96 , 98] Si dorim sa aflam daca exista numar 78 in colectie si la ce index : APLICAM ALGORITMUL :: --> AFLAM INDEX-UL CARE-I CORESPUNDE NUMARULUI DIN MIJLOCUL INTERVALULUI : (9+0)/2 = 4.5 ==> 5 ==> Verificam daca a[5] = 76 este echivalent cu 78 ==> DIFERIT CONTINUAM ALGORITMUL ; --> CUNOASTEM FAPTUL CA 78 > 76 ASA CA VOM STII CA NUMARUL CAUTAT SE AFLA IN INTERVALUL DIN DREAPTA [76 , 78 , 84 , 96 , 98 ] --> AFLAM INDEXUL CAREI CORESPUNDE NUMARUL DIN MIJLOCUL INTERVALULUI : (5+9)/2 = 14/2 = 7 (indexul din mijloc) ==> Verificam daca a[7] = 84 este echivalent cu 78 ==> DIFERIT CONTINUAM ALGORITMUL ; --> CUNOASTEM FAPTUL CA 84 > 78 ASA CA VOM STII CA NUMARUL CAUTAT SE AFLA IN INTERVALUL DIN STANGA [ 76 , 78 , 84 ] --> AFLAM INDEXUL CAREI CORESPUNDE NUMARUL DIN MIJLOCUL INTERVALULUI : (5+7)/2 = 6 (Indexul din mijloc) ==> verficam daca [a6] = 78 = este echivalent cu 78 ==> AM GASIT ELEMENTU , INTRERUPEM ALGORITMUL CU SUCCES !! ** Interpretare in Cod C ** : #include <stdio.h> #include <stdlib.h> // Pentru malloc & free int main() { int arrayBuffer; printf("Cate numere doresti sa aiba colectia : "); scanf_s("%d", &arrayBuffer); int* a = (int*)malloc(arrayBuffer * sizeof(int)); // ALOCAM UN ARRAY IN FUNCTIE DE CATE NUMERE VREA UTILIZATORUL SA INTRODUCA printf("Insereaza %d numere in sir crescator : \n",arrayBuffer); for (int i = 0; i < arrayBuffer; i++) { printf("colectie[%d] = ",i); scanf_s("%d", &a[i]); // Inseram numerele de la tastatura } int numberToSearch, found = 0, index; do { printf("Insereaza numarul pe care vrei sa l cauti in colectie : "); scanf_s("%d", &numberToSearch); int leftIndex = 0, RightIndex = arrayBuffer - 1; // Aflam Primul Si Ultimul Index // LE AM INITIALIZAT IN AFARA LOOPULUI PENTRU A SI PASTRA VALOAREA LA FIECARE ITERARE !!! do { int mid = (leftIndex + RightIndex) / 2; // Aflam Indexul Din Mijlocul Intervalului if (a[mid] == numberToSearch) // Comparam Cu Mijlocul { // Daca Am gasit numarul index = mid; // Preluam Indexul found = 1; break; } else if(a[mid] < numberToSearch) { // DACA NUMARUL CAUTAT ESTE MAI MARE DECAT MIJLOCUL leftIndex = mid; // Vom Cauta in Continuare de la Mijloc Spre Dreapta } else { // DACA NUMARUL CAUTAT ESTE MAI MIC DECAT MIJLOCUL RightIndex = mid; } } while (leftIndex <= RightIndex); printf("\n"); } while (found == 0); printf("Am gasit elementul %d la pozitia %d", numberToSearch, index); // Eliberam Memoria Ocupata de Array (Sa prevenim Memory Leak) free(a); // Eliberam Colectia in sine a = NULL; // Setam NULL Pointer return 0; } NOTA 1 ** : ALGORITM INEFICIENT IN CAZUL COLECTIILOR DEZORDONATE (NESORTATE) !!! Explicatie : Sa presupunem ca avem o colectie de 10 numere (NESORTAT) : [98 , 33 , 22 , 11 , 65 , 55 , 44 , 78 , 45 , 99] Si dorim sa aflam daca exista numarul 44 in colectie si la ce index : Aplicam Algoritmul : 1. mid = (0+9)/2 = 4.5 a[5] = 55 diferit de 44 ==> 55 > 44 ==> CAUTAM IN INTERVALUL DIN STANGA [98 , 33 , 22 , 11 , 65 , 55] NU L GASIM PE 44 IN ACEST INTERVAL !! ==> ALGORITMUL ESUEAZA NOTA 2 ** : FOARTE BUN DACA AVEM O COLECTIE MARE DE DATE , SCUTINDU NE DE A CAUTAT FIECARE ELEMENT !! (CU CONDITIA DE A FI ORDONAT)
  23. ** Analiza Algoritmilor ** Algoritmii sunt modalitati de identificare si rezolvare a unei sau mai multe probleme . In rezolvarea unei probleme , pot exista mai multe solutii dar unele pot fi mai eficiente sau nu . Eficacitatea unui algoritm este masurata in TIMP SI SPATIU . * TIMPUL CONSTA IN PERIOADA DE EXECUTIE A ALGORITMULUI . CU CAT TINDE SPRE 0 , cu atat este mult mai eficient din acest aspect !! * SPATIUL CONSTA IN RESURSELE ALOCATE IN EXECUTAREA ALGORITMULUI . CU CAT SPATIUL ESTE MAI MIC , CU ATAT ALGORITMUL ESTE MAI EFICIENT !! ** Introducere in Algoritmii de Cautare ** Algoritmii de cautare reprezinta modalitati diferite de rezolvare a problemei privind cautarea unui element sau mai multe , intr-o colectie (array,liste,arbori etc.) . Importanta algoritmilor de cautare : Ne ajuta la cautarea unui produs sau persoana , dupa preferintele noastre , de pe un site de e-commerce sau social media (persoana) ; Ne ajuta in diferite sisteme de recunoastere vocala , faciala etc. ; Ne ajuta sa cautam relevant intr o baza de date ; Ne ajuta la aflarea rutei optime dintr - o retea etc. ** Algoritmul de Cautare Liniar ** Cautarea Liniara reprezinta cea mai usoara modalitate de a descoperi un termen dintr- o colectie . Ea consta in verificarea fiecarui element in parte , de la un cap la celalalt . Explicatie : Definim o colectie de 10 numere . Sa cautam termenul 30 in colectie : [40 , 50 , 35 , 60 , 70 , 78 , 30 , 10 , 5 , 12] Navigam prin colectie si luam la comparatie fiecare numar (de la cifra 40 pana la 30) 40 diferit de 30 ==> mergem la urmatorul 50 diferit de 30 ==> mergem la urmatorul 35 diferit de 30 ==> mergem la urmatorul 60 diferit de 30 ==> mergem la urmatorul 70 diferit de 30 ==> mergem la urmatorul 78 diferit de 30 ==> mergem la urmatorul 30 egal cu 30 ==> TERMEN GASIT , OPRIM ALGORITMUL !!! Interpretare algoritm in C : #include <stdio.h> int main() { int a[10]; printf("Insereaza 10 numere : \n"); for (int i = 0; i < 10; i++) { printf("colectie[%d] = ",i); scanf_s("%d", &a[i]); // Inseram numerele de la tastatura } int numberToSearch, found = 0, index; do { printf("Insereaza numarul pe care vrei sa l cauti in colectie : "); scanf_s("%d", &numberToSearch); for (int i = 0; i < 10; i++) // Navigam prin colectie { if (numberToSearch == a[i]) // Cautam secvential prin toata colectia si comparam cu fiecare individ { // DACA S -A IMPLINIT CONDITIA DE MAI SUS found = 1; // Am gasit elementul index = i; // Salvam indexul break; // Intrerupem bucla !! } } printf("\n"); } while (found == 0); printf("Am gasit elementul %d la pozitia %d", numberToSearch, index); return 0; } NOTA 1 ** : Algoritmul devine mai ineficient cu cat elementul cautat este mai aproape de capat (TIMPUL DE EXECUTIE DEVINE DIN CE IN CE MAI MARE !!) NOTA 2 ** : NU SE RECOMANDA ACEST ALGORITM DE CAUTARE CAND AVEM DE A FACE CU COLECTII DE MARI DIMENSIUNI SAU ORDONATE !!!
  24. ** Constructor cu Argumente (Parametrii) ** Constructorul sau Constructorii cu parametrii sunt metode care ne permit sa avem instante (obiecte) unice in functie de parametrii luati . De asemenea , pot exista si impreuna cu constructorul implicit . Reconstruim clasa de la tutorialul trecut (cu constructorul implicit) + functia de alocare a sirurilor de caractere : void atribuireSirCaractere(char** target, const char* source) { size_t bufferString = strlen(source) + 1; *target = new char [bufferString]; strcpy_s(*target, bufferString, source); } class Utilizator { public : // Punem enumul pe public deoarece trebuie sa l accesam din exterior enum class type { // Tip de Utilizator MEMBER, PREMIUM, MODERATOR, ADMIN }; private: // Sector Privat (Membrii aflati la acest nivel de acces NU pot fi accesati unsigned id; // Numar Natural char* username; // String char* email; // String char* password; // String unsigned nrPosts; // Numar Natural bool isForbidden; // Banat sau NU type userType; // Tip Utilizator public: // Sector Public (Membrii aflati la acest nivel de acces POT FI ACCESATI) Utilizator() { /// Definitie Constructor fara parametrii (argumente) //// Definim Stringurile pe care le dorim sa le atribuim campurilor // Initializam campurile statice id = 0; nrPosts = 0; isForbidden = false; userType = type::MEMBER; // Member by Default // Atribuire Nume de Utilizator atribuireSirCaractere(&username, "Vasile"); // Atribuire Nume atribuireSirCaractere(&email, "[email protected]"); // Atribuire Email atribuireSirCaractere(&password, "vasileParola"); } // Definim Getteri const unsigned _getIdUser() { return id; } const char* const _getUsername() { return username; } const char* const _getEmail() { return email; } const char* const _getPassword() { return password; } const unsigned _getNrPosts() { return nrPosts; } const bool _isForbidden() { return isForbidden; } const type _getType() { return userType; } }; NOTA ** : Am adaugat trei campuri noi ("isForbidden","NrPosts" si "TypeUser") sa devina mai interesant ; Acum in clasa respectiva , vom adauga 4 constructori cu paramatrii : Utilizator(unsigned _id,type _userType) { // Constructor care preia ca argument ID-ul si tipul de user ; id = _id; // Atribuim id-ul din argumentul preluat userType = _userType; // Atribuim tipul din argumentul preluat // Restu e implicit isForbidden = false; nrPosts = 0; atribuireSirCaractere(&username, "Vasile"); // Atribuire Nume atribuireSirCaractere(&email, "[email protected]"); // Atribuire Email atribuireSirCaractere(&password, "vasileParola"); } Utilizator(unsigned _id, const char* _username,type _userType) // Al doilea Constructor cu id si nume preluat { // Atribuire cu argumente preluate id = _id; atribuireSirCaractere(&username, _username); userType = _userType; // Restu Implicit isForbidden = false; nrPosts = 0; atribuireSirCaractere(&email, "[email protected]"); // Atribuire Email atribuireSirCaractere(&password, "vasileParola"); // Atribuire Parola A } Utilizator(unsigned _id, const char* _username , const char* _email , const unsigned _nrPosts) // Al treilea Constructor cu id , nume , email preluat si numar posturi { // Atribuire cu argumente preluate id = _id; atribuireSirCaractere(&username, _username); atribuireSirCaractere(&email, _email); // Atribuire Email nrPosts = _nrPosts; // Atribuire cu argumente default atribuireSirCaractere(&password, "vasileParola"); // Atribuire Parola A userType = type::MEMBER; // Atribuire Tip Utilizator isForbidden = false; } /// Constructor care preia toate argumentele Utilizator(unsigned _id, const char* _username, const char* _email, const char* _password,const unsigned _nrPosts,const bool _isForbidden,type _userType) { // Atribuire cu argumente preluate id = _id; nrPosts = _nrPosts; isForbidden = _isForbidden; userType = _userType; atribuireSirCaractere(&username, _username); // Atribuire Nume Utilizator atribuireSirCaractere(&email, _email); // Atribuire Email atribuireSirCaractere(&password, _password); // Atribuire Parola } NOTA ** : PUTEM FACE CATI CONSTRUCTORI CU PARAMETRII DORIM NOI !! (TOTUSI E RECOMANDAT DOAR CE E STRICT NECESAR) Pentru a putea afisa un enum ca sir de caractere , avem nevoie de un adaptor in interiorul clasei : static const char* typeUser(type userType) // O Folosim la nivel static { switch (userType) { case type::ADMIN: return "Administrator"; break; case type::MODERATOR: return "Moderator"; break; case type::PREMIUM: return "Utilizator Premium"; break; default: return "Utilizator Simplu"; break; } } NOTA ** : L am notat cu "static" deoarece functia nu depinde de campurile instantei !! Vom discuta in tutorialele ce urmeaza despre membrii statici , in detaliu !! Totodata , construim o alta functie in interiorul clasei care sa ne afiseze datele (Cu scopul de a nu repeta cod aiurea ): void toString(){ // Interfata de afisare a fiecarui obiect cout << _getIdUser() << " | " << _getUsername() << " | " << _getEmail() << " | " << _getPassword() << " | " << _isForbidden() << " | " << _getNrPosts() << " | " << typeUser(_getType()) << endl; } Acum , trecem in functia main si instantiem 5 obiecte (1 cu constructor default si 4 cu parametrii ) : int main() { Utilizator vasileEntitate1; // Instantiat cu Constructorul Default (Implicit) // Afisam Campurile : ID | USERNAME | EMAIL | PASSWORD vasileEntitate1.toString(); Utilizator vasileEntitate2(1,Utilizator::type::MEMBER); // Instantiere Prim Constructor vasileEntitate2.toString(); Utilizator ionEntitate(2, "Ion", Utilizator::type::PREMIUM); // Instantiere Al Doilea Constructor ionEntitate.toString(); Utilizator alinEntitate(3, "Alin", "[email protected]" ,50); // Instantiere Al Treilea Constructor alinEntitate.toString(); Utilizator georgeEntitate(4, "George", "[email protected]", "georgeParola" , 80 , false,Utilizator::type::ADMIN); // Instantiere Al Treilea Constructor georgeEntitate.toString(); return 0; } Si primim ca rezultat : 0 | Vasile | [email protected] | vasileParola | 0 | 0 | Utilizator Simplu 1 | Vasile | [email protected] | vasileParola | 0 | 0 | Utilizator Simplu 2 | Ion | [email protected] | vasileParola | 0 | 0 | Utilizator Premium 3 | Alin | [email protected] | vasileParola | 0 | 50 | Utilizator Simplu 4 | George | [email protected] | georgeParola | 0 | 80 | Administrator
  25. ** Importanta Constructori ** Constructorii sunt metode care NU returneaza un tip de date , pot detine parametrii sau nu, si sunt utilizati pentru initializarea si alocarea dinamica a campurilor unei clase . Asemenea , ei poarta numele clasei si se declanseaza la instantierea clasei !!! ** Constructor fara Parametrii ** Constructorul fara Parametrii sau Implicit (Default) este un constructor fara argumente , el se declanseaza daca nu oferim parametrii la instantiere . Construim o functie in afara clasei care ne permite alocarea si atribuirea pentru fiecare sir de caractere : void atribuireSirCaractere(char** target, const char* source) // Luam ca argument sirul de caracter pe care dorim sa l initializam dar si valoarea pe care dorim sa o atribuim // Nota ** : char** pentru ca dorim sa efectuam o modificare a argumentului { size_t bufferString = strlen(source) + 1; // Aflam numarul de caractere pe care l are sursa + 1 bit (pentru caracterul terminal) *target = new char [bufferString]; // Alocam Targetul in functie de "bufferstring" strcpy_s(*target, bufferString, source); /// Atribuim targetul cu sursa } Construim clasa "Utilizator" cu campurile "id , username , emal , password " : class Utilizator { private: // Sector Privat (Membrii aflati la acest nivel de acces NU pot fi accesati) unsigned id; // Numar Natural char* username; // String char* email; // String char* password; // String }; Definim un costructor fara parametrii cu rolul de a atribui acele campuri private : class Utilizator { public: // Sector Public (Membrii aflati la acest nivel de acces POT FI ACCESATI) Utilizator() { /// Definitie Constructor fara parametrii (argumente) // Initializam campurile id = 0; // O initializam cu o valoare default // Atribuire Stringuri de Caractere (Accesam functia de mai sus) /* Astfel ca : username , email , password --> sunt targeturi (transferate prin adresa, continutul acestor pointeri se poate schimba la apelul functiei) Celalalte valori (al doilea parametru al functiei) sunt siruri de caractere constante (transferate prin valoare deoarece ne intereseaza sa atribuim targetul cu aceste valori) !! */ atribuireSirCaractere(&username, "Vasile"); // Atribuire Nume atribuireSirCaractere(&email, "[email protected]"); // Atribuire Email atribuireSirCaractere(&password, "vasileParola"); // Atribuire Parola } }; Definim getteri pentru accesa campurile in functia main : // Definim Getteri // Functii Constante deoarece ne intereseaza doar sa citim valorile !!! const unsigned _getIdUser() { return id; } const char* const _getUsername() { return username; } const char* const _getEmail() { return email; } const char* const _getPassword() { return password; } Construim doua entitati de utilizator ("vasileEntitate1" , respectiv "vasileEntitate2") si afisam continutul acestora : int main() { Utilizator vasileEntitate1; // Instantiez + Declansam constructorul fara parametrii // Afisam Campurile : ID | USERNAME | EMAIL | PASSWORD cout << vasileEntitate1._getIdUser() << " | " << vasileEntitate1._getUsername() << " | " << vasileEntitate1._getEmail() << " | " << vasileEntitate1._getPassword() << endl; Utilizator vasileEntitate2; // Instantiem alt obiect dar Declansam acelasi constructor cout << endl; /// VOM AVEA ACELASI REZULTAT cout << vasileEntitate2._getIdUser() << " | " << vasileEntitate2._getUsername() << " | " << vasileEntitate2._getEmail() << " | " << vasileEntitate2._getPassword() << endl; return 0; } NOTA ** : VOM OBSERVA CA AMBELE ENTITATI LA APELUL CONSTRUCTORULUI IMPLICIT , NE FURNIZEAZA ACELEASI DETALII !!
×
×
  • Creează nouă...

Informații Importante

Termeni de Utilizare & Politică Intimitate