programarecpp

august 5, 2011

foreach() in C/C++

Filed under: Algoritmi, C/C++ — Etichete:, , , , — ovidiu91 @ 11:14 am

Observand utilitatea instructiunii foreach() din C#, am hotarat sa creez o functie pentru C/C++ care sa imite sintaxa si avantajul scrierii unui cod mai aerisit.

Functia foreach() are urmatoarele prototipuri:

  • template<typename thisType>
     void foreach( thisType element of unsigned arraySize in thisType (*arrayOfElements), void (*functionPointer)(thisType));
  •  template<typename thisType>
     void foreach( thisType element in thisType (*arrayOfElements) until thisType lastElement, void (*functionPointer)(thisType));

unde:

  • thisType este tipul datelor prelucrate;
  • element este variabila care preia fiecare valoare din tabloul unidimensional arrayOfElements;
  • functionPointer este un pointer la o functie de tip void care are un singur parametru de tipul datelor din arrayOfElements.

iar specializarile:

  • arraySize este numarul de elemente care vor fi iterate in tabloul arrayOfElements; iteratia incepe de la elementul cu indicele 0 (zero);
  • lastElement este punctul de oprire al iteratiei; la intalnirea acestui element, se iese din functia foreach(), fara ca lastElement sa fie prelucrat.

Exemplu de folosire al functiei foreach():

#include <iostream>
#include <string>

//header-ul ce contine definitia functiei foreach()
#include "foreach.h"

using namespace std;

void Hello(int i)
{
    cout<<" Hello from "<<i<<" !"<<'\n';
    return;
}

void Func(string s)
{
    cout<<s<<" func"<<'\n';
    return;
}

int main(void)
{
    int v[100];
    int i;

    for(i=0; i<100; i++)
        v[i]=i;

    //base function 
    foreach( i of 30 in v, Hello);
    if(error)
    {
        cout<<lastErrorMessage<<'\n';
    }

    //overloaded
    foreach(i in v until 10, Hello);

    string text[3];
    text[0] = "abcd";
    text[1] = "efgh";
    text[2] = "xyz";
    string cuvant;
    string limita = "xyz";

    //va afisa "abcd" si "efgh"
    foreach(cuvant in text until limita, Func);     

    system("pause");
    return 0;
}

Link descarcare header: foreach.h

PS: din pacate, WordPress nu este de acord cu upload-ul fisiereler de tip .h, astfel incat am fost nevoit sa convertesc continutul header-ului intr-un fisier .pdf.

Pointeri la o functie in C/C++

Filed under: C/C++ — Etichete:, , , — ovidiu91 @ 9:36 am

Un pointer este un tip de date predefinit in limbajul C/C++ care stocheaza o adresa de memorie. Asadar, se pot crea pointeri pentru variabile, clase, obiecte si functii. Dar care este scopul unui pointer la o functie?

Sa privim la prototipul functiei qsort(), din cadrul stdlib.h:

void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) );

Dupa cum se poate observa, al 4-lea parametru al functiei este un pointer la o functie care returneaza un intreg, pentru a stabili ordinea elementelor la sortare( mai multe detalii, aici). Prin urmare, pointerii pot fi folositi pentru a transmite functii ca parametri pentru alte functii sau pentru evenimente. In ultimul caz, functia care este apelata in urma aparitiei unui eveniment este denumita callback function.

Declararea unui pointer la o functie:

tip_functie (*nume_pointer_la_functie) ( tip_parametru1, tip_parametru2, ...);

Folosind exemplul de mai sus, vom avea:

int ( * comparator ) ( const void *, const void * );

unde:

  • int este tipul functiei spre care se pointeaza;
  • comparator este numele pointer-ului la functie;
  • const void *  reprezinta tipul celor 2 parametrii ai functiei spre care se pointeaza.

Apelarea unei functii prin intermediul unui pointer:

#include <iostream>
#include <string>

using namespace std;

void HelloWorld(string name)
{
    cout<<"Hello, "<<name<<"! "<<'\n';
    return;
 }

int main(void)
{
    //declararea pointer-ului
    void (*functionPointer)(string);

    //atribuirea adresei functiei spre care pointeaza; "&" este optional
    functionPointer= &HelloWorld;

    //apelul functiei prin intermediul pointer-ului
    functionPointer("world");

    system("pause");
    return 0;
}

Transmiterea unei functii ca parametru prin intermediul unui pointer:

#include <iostream>
#include <string>

using namespace std;

int Average(int x, int y)
{
    return ((x+y)/2);
}

void ShowAverage(int myArray[10], unsigned counter, int (*theFunctionPointer)(int, int))
{
    for(int i=0; i<counter-1; i++)
      {
         cout<<"Average between "<<myArray[i]<<" and "<<myArray[i+1]<<" is "<<theFunctionPointer(myArray[i], myArray[i+1])<<". "<<'\n';
      }
    return;
}

int main(void)
{
    int someArray[10] = {4, 5, 6, 2, 9, 8};
    int someCounter = 6;

    //declararea pointer-ului
    int (*functionPointer)(int, int);

    //atribuirea adresei functiei spre care pointeaza; "&" este optional
    functionPointer= &Average;

    //trimiterea functiei ca parametru prin intermediul pointer-ului
    ShowAverage( someArray, someCounter, functionPointer);

    system("pause");
    return 0;
}

Desigur, apelul functiei ShowAverage() poate fi facut si in modul urmator:

ShowAverage( someArray, someCounter, Average);

aprilie 12, 2011

String explode in C++

Cei care au lucrat cu PHP sunt familiarizati cu o functie foarte utila, pentru siruri de caractere: explode(). Aceasta imparte un sir de caractere, in functie de caracterul delimitator specificat. Cum am avut nevoie, recent, sa impart un sir de caractere dupa un anumit delimitator, iar in C++ nu exista explode(), am creat eu un echivalent al sau:

(mai mult…)

martie 6, 2011

Rezolvare cod recursiv in C/C++

Filed under: Algoritmi, C/C++ — Etichete:, , , — ovidiu91 @ 6:26 pm

Foarte des, la examene si lucrari, se dau exemple de cod recursiv in C/C++ si se cere mentionarea rezultatului dupa executie. Cea mai sigura si simpla, in acelasi timp, metoda de a calcula acest lucru este dupa algoritmul urmator:

(presupunem ca avem dat urmatorul cod recursiv )

int f(int a, int b) 
{
  if (a == 0)
    return b - 2;
  else 
    if (b == 0) 
      return a - 2;
    else
      if (a < 0 && b < 0)
        return f(a + 1, b + 1) - 2;
      else
        if (a > 0 && b > 0)
          return f(a - 1, b - 1) + 2;
        else
          if (a < 0) 
            return f(a + 1, b - 1);
          else
            return f(a - 1, b + 1);
}

Metoda de rezolvare:

  • f(3, 5) = 2 + f(2, 4) = 2 + ( 2 + f(1, 3)) = 2 + ( 2 + ( 2 + f(0, 2))) = 2 + ( 2 + ( 2 + (0))) = 6
  • f(2, 3) = 2 + f(1, 2) = 2 + ( 2 + f(0, 1)) = 2 + ( 2+( (-1))) = 3
  • f(-3, -2) = (-2) + f(-2, -1) = (-2) + ((-2) + f(-1, 0)) = (-2) + ((-2) +((-3))) = -7

La fiecare pas, este important sa copiati partea formatata cu rosu, adica rezultatele retinute pe stiva, care se aduna ( sau scad/inmultesc/impart, in functie de codul dat) la final. Parantezele formatate cu verde reprezinta valoarea returnata de un apel recursiv. Acesta este trucul pentru a nu pierde din vedere rezultatul corect.

februarie 7, 2011

Functii cu numar variabil de parametrii in C/C++

Dupa cum ati observat pana acum, in limbajul C/C++ exista functii cu numar variabil de parametrii. Cel mai banal, dar si cel mai intalnit exemplu, este functia printf() (impreuna cu variatiile sale: fprintf(), sprintf() )  preferata de programatori in detrimentul operatorului “<<“. O asemenea functie poate fi creata cu ajutorul header-ului stdarg.h si a macro-urilor definite in acesta: va_list, va_start(), va_arg() si va_end().

Prototipul unei functii cu numar variabil de parametrii este:

tip_functie nume_functie( tip_argument nume_argument, …);

Astfel, (cel putin) primul argument este intotdeauna fix, vizibil, restul argumentelor fiind declarate prin mecanismul elipsa, reprezentat de cele 3 puncte dupa virgula.

Cele 4 constructii definite in header si utilizate sunt:

  • va_list : variabila pointer, de tip void*, folosita pentru parcurgerea listei de argumente
  • void va_start( va_list obiect, NumeArgument) : initializeaza parcurgerea la primul element
    • Parametrii:
      • obiect : variabila de tip va_list care va parcurge lista de argumente
      • NumeArgument : numele ultimului argument vizibil din definitia functiei
  • tip va_arg( va_list obiect, tip) : ofera urmatorul argument
    • Parametrii:
      • obiect : variabila de tip va_list care va parcurge lista de argumente; devine urmatorul argument din lista
      • tip : tipul de date al argumentului
  • void va_end( va_list obiect) : termina actiunea de parcurgere a listei, eliberand si memoria astfel
    • Parametrii:
      • obiect : variabila de tip va_list folosita la initializare, prin apelarea va_start()

Pentru a exemplifica, vom crea o functie suma(), care va avea de adunat un numar variabil de parametrii:

#include <stdarg.h>
#include <iostream>

using namespace std;

int suma(int NrArgumente,...)
{
   va_list argument; 			//declaram variabila de tip va_list
   int i, rezultat= 0;
   va_start(argument, NrArgumente); 	//apelam va_start() si o initializam
   for (i = 0; i < NrArgumente; i++)
     rezultat += va_arg(argument, int); //valoarea argumentului + inaintare

/*
instructiunea de mai sus putea fi scrisa si sub forma:
int aux;
for (i = 0; i < NrArgumente; i++)
  {
    aux = va_arg(argument, int);
    rezultat += aux;
  }
*/ 

   va_end(argument); 		      // terminare parcurgere + eliberare memorie
   return rezultat;
}

int main(void)
{
   cout << suma(5, 1,2,3,4,5) << '\n';  	//=15
   cout << suma(3, 1,2,3) << '\n';		//=6
   cout << suma(2, 10,100) << '\n';             //=110

   return 0;
}

 

 

#include <stdarg.h>
#include <iostream>
int suma(int nargs,…){
va_list args; //declaratie
int i, total = 0;
va_start(args, nargs); //initializare
for (i = 0; i < nargs; i++)
total += va_arg(args, int); //val.arg.+ inaintare
va_end(args); // eliberare
return total;
}
int main(){
std::cout << suma(7, 1,2,3,4,5,6,7);  //=28
std::cout << suma(3, 1,2,3); //=6
return 0;
}

februarie 4, 2011

Suprascrierea functiei WndProc() in Borland C++ Builder

Filed under: C/C++ — Etichete:, , , , , — ovidiu91 @ 7:47 pm

Asa cum am mentionat in articolul anterior, in decursul ultimelor zile, am fost nevoit sa gasesc o metoda de a verifica mesajele trimise de sistemul de operare, mai exact pe cele de tipul WM_DEVICECHANGE, intr-un mediu RAD, prin intermediul functiei WndProc(). Acest lucru se poate dovedi, la inceput, un impediment, din moment ce functia este deja predefinita in proiect si nu chiar accesibila. Am descoperit, insa, dupa cateva cautari pe internet, o metoda de a defini propria functie WndProc() intr-un proiect, suprascriind-o pe cea initiala.

Prototipul functiei WndProc():

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

 

In Borland C++ Builder (2007), presupunand ca avem un proiect de tip VCL Forms Application cu o clasa definita pentru un TForm1, vom adauga declaratia:

virtual void __fastcall WndProc(Messages::TMessage &Message);

in fisierul header, in corpul clasei, cu atributul public: , iar definitia o vom scrie in fiserul cpp:

void __fastcall TForm1::WndProc(Messages::TMessage &Message)
{
 if ( Message.Msg == WM_DEVICECHANGE )
 {
    //codul pentru prelucrarea mesajului
 }

 TForm::WndProc( Message ); // cazul "default"
}

Membrii lui Message sunt Msg, WParamLo, WParamHi, WParam, LParamLo, LParamHi, LParam, ResultLo, ResultHi precum si Result.

Un mic upgrade

Filed under: Diverse — Etichete:, , , , — ovidiu91 @ 6:54 pm

In decursul ultimelor zile, fiind si in vacanta intersemestriala, am decis ca este vremea sa mai pun mana pe un IDE si sa aprofundez cunostintele de programare. Si cum as putea face acest lucru mai bine daca nu creand un program? Zis si facut. De fapt, mai mult zis, deoarece, din pacate, socotelile de pe hartie nu se potrivesc cu cele de la compilare… Si asa am inceput o odisee (intrerupta doar de 2 iesiri la o bere cafea), care a tinut aproape 3 zile, in cautarea unui mediu RAD (Rapid Application Development), care sa-mi permita adaugarea si manipularea usoara a unor controale dar care sa-mi lase la dispozitie si proceduri din aplicatiile Win32 native, precum este WndProc(). Am (re)descoperit, astfel, Managed C++ (MC++) din Visual Studio dar si Borland C++ Builder, care m-au scutit de mult efort la crearea unei interfate pentru program, compensand, intr-un sens negativ, insa, la capitolul manipulare proceduri.

Datorita acestei experiente, m-am gandit ca ar trebui sa extind putin aria de subiecte abordate pe blog si sa includ si o categorie pentru tehnologia .Net, din moment ce ma vad pus in situatia de a apela la ea. Asadar, pe viitor vor putea fi citite si articole legate de MC++, C++/CLI si, posibil, C#.

ianuarie 19, 2011

Ridicarea unui numar natural la o putere in ASM

Filed under: Algoritmi, ASM, C/C++ — Etichete:, , — ovidiu91 @ 6:50 pm

Functia urmatoare preia 2 parametrii: x- baza si p-puterea la care trebuie ridicat x.

int ridicare_la_putere(int x, int p)
{
  int rezultat;

  _asm
  {
    mov eax, x;        //registrul in care se va stoca rezultatul
    mov ebx, p;        //puterea la care trebuie ridicat numarul
    dec ebx;           //deja avem x^1

  loop_start:
    mul x;        //eax = eax*x
    dec ebx;

    cmp ebx, 0;
    ja loop_start;

    mov rezultat, eax;
  }

  return rezultat;
}

Suma elementelor unui tablou unidimensional in ASM

Filed under: Algoritmi, ASM, C/C++ — Etichete:, — ovidiu91 @ 6:28 pm

Functia urmatoare calculeaza suma elementelor unui tablou unidimensional (vector) de tip unsigned:

int suma_elementelor(int* x, int lg)
{
  int suma;

  _asm
  {
    mov ecx, lg;    //contor
    mov eax, x;        //pointerul la elementele vectorului
    xor ebx, ebx;    //suma elementelor
    xor edx, edx;    //indicele 

  loop_start:
    mov esi, [eax+4*edx];
    add ebx, esi;
    inc edx;
    loop loop_start;
 
    mov suma, ebx;
  }

  return suma;
}

ianuarie 18, 2011

Numarare biti “setati” intr-un numar natural, in ASM

Filed under: Algoritmi, ASM, C/C++ — Etichete:, , , , — ovidiu91 @ 8:42 pm

Problema:

Dorim sa numaram cati biti “setati”, adica egali cu valoarea 1, avem intr-un numar natural (unsigned).

Idee de rezolvare:

Algoritmul banal presupune compararea numarului cu masca 0×1 (= 1, in baza 10), apoi shiftarea acestuia cu o pozitie spre dreapta, pana cand devine egal cu 0.

Implementare:

int numar_biti(int x)
{

 int c;

 _asm
 {
    mov eax, x;
    mov ebx, 0x1;    //masca
    mov edx, 0;        //rezultatul

 loop_start:
   and ebx, eax;
   add edx, ebx;
   mov ebx, 1;
   shr eax, 1;

   cmp eax, 0;
   je loop_end;

   jmp loop_start;

 loop_end:
   mov c, edx;
 }

 return c;
}

 

Posturi mai vechi »

Theme: Silver is the New Black. Bloguieşte pe WordPress.com.

Follow

Get every new post delivered to your Inbox.