5 CPA 3 Extending expressive power: pointers, functions and memory

Wskaźniki - przetrzymując informację o lokalizacji, adresie innych danych.

inicjacja:
int *p;

jedyną wartością jaką można samemu przypisać do p jest 0;
p=0;    albo p=NULL,   nie można literału np.234

do p możemy przypisać adres zmiennej który uzyskujemy &
p=&i;

żeby zobaczyć wartość jaka kryje się pod adresem przechowywanym przez p
*p

cout<<*p;

co ważne:
*p=4; 
nie zmieni wartości p, ale zmiennej wskazywanej przez p

sizeof - ile bajtow pamieci zajmuje argument

i=sizeof(char);

char c;
int i=sizeof c;

char tab[10];
i=sizeof tab;    -> rozmiar całej tablicy

int *ptr;
int tab[3];   tak naprawdę tab jest wskaznikiem na pierwszy element tablicy

ptr=tab;    albo    ptr=&tab[0];

dodając do wskaźnika typu int  1 tak naprawdę podnosimy adres o 4, więc możemy chodzić po tablicy:

ptr+1=&tab[1];


Funkcje:
deklaracja funkcji to prototyp
ciało funkcji to definicja

void jak nic nie zwraca, przyjmuje

jeśli definicja poniżej main to przed mainem musi być deklaracja,prototyp zakończony;
prototyp nie musi miec nazw argumentów(parametrów) np:

int funkcja(int);

side efect - efekt uboczny funkcji -- kiedy zawiera zmienna globalna;

GreetManyTimes(1 + sizeofego);    - wyświetli 1+sizeofego   (wyliczy)



funkcje które coś zwracają czyli nie:   void funkcja (int aa);   ale int funkcja(int aa);
mogą być wywoływane
value=funckja(2);
albo funkcja(2);     -> i wtedy tracą to co zwracają


przekazywanie parametru funkcji przez wartość - tworzy kopie i nie zmienia oryginalnej zmiennej

przekazywanie przez referencje wygląda tak


void funkcja(int &aa);
tutaj normalnie
}

przekazywana przez referencję może być tylko ZMIENNA ( przez wartośc może być wynik funkcji która coś zwraca)


można w stylu C przekazać wskaźnik
void ByPtr(int *ptr)
ale tu operujemy
*ptr zeby operować na wartościach

przykła:

int  variable = 1;
int *pointer  = &variable;

ByPtr(pointer);



Parametr domyślny:
void funkcja(int repeats=1)

co ważne jeśli masz 2 parametry, to nie możesz podać tylko drugiego


INLINE - jeśli funkcje wyweoływane pod rząd wiele razy to można dodać ten parametr
prologi i epilog funkcji wywołany tylko raz, oszczedza miejsce w pamięci


inline int function(int parameter)
{}


Przeciążanie funkcji - ilość argumentów, typ argumentów
zwracany parametr NIE JEST BRANY POD UWAGE!


W przypadku:
void PlayWithNumber(int x) { … }
void PlayWithNumber(float x) { … }
:
PlayWithNumber(1.0);

nie wybierze float bo 1.0 jest w c++ typu double a w dół nie będzie degradował, jeśli chcemy zeby zadziałało dać 1 wtedy wybierze int albo dać jako parametr (1.0f)


Operator   ?:

oblicza1   ?  jeśliniezero:jeślizero
np:

return a>b ? a:b

wersja z 3 parametrami:

return a > b ? (a > c ? a : c) : (b > c ? b : c)

Sortowanie bąbelkowe:
#include <iostream>
 
using namespace std;

int main(void) {
        int  numbers[5];
        int  aux;
        bool swapped;
        // ask the user to enter 5 values 
        for(int i = 0; i < 5; i++) {
                cout << endl << "Enter value #" << i + 1 << ": ";
                cin >> numbers[i];
        }
        // sort them 
        do {
                swapped = false;
                for(int i = 0; i < 4; i++) {
                        if(numbers[i] > numbers[i + 1]) {
                            swapped = true;
                            aux = numbers[i];
                            numbers[i] = numbers[i + 1];
                            numbers[i + 1] = aux;
                         }
                }
        } while(swapped);
        // print results 
        cout << endl << "Sorted array: " << endl;
        for(int i = 0; i < 5; i++)
                cout << numbers[i] << " ";
        cout << endl;
        return 0;
}

.

amorphous pointer

VOID *ptr     ->  nie można dereferencji czyli wartości określić (*ptr=1) ale można przekonwertować w inny wskaźnik określonego typu

Alokacja pamięci:
new - musi byc okreslony typ do rezerwacji pamięci, jeśli tablica, wielkosc, zwraca wskaźnik i nie wypełnia trescią  (zawiera śmieci)

float *array=new float[20];
int count=new int;

Uwalnianie pamięci:
delete [] array;
delete count;

po skasowaniu wszystkie wskazniki ktore wskazywaly na ten obszar spowoduja bład programu

tworzenie tablic za pomoca new podczas trwania programu to tworzenie dynamiczne

Przykłady funkcji


int *f3(int &a) {         -> pobiera zwykły int, przekazuje referencja a zwraca adres do tej zmiennej
        return &a;            -> dlatego mamy return &a  (zwroc adres)
    }                               -> a przed naz. funkcji int* bo zwraca adres (czyli wskaznik)


   int *f2(int *a) {       -> pobierz wskaźnik (int *a), co wazne jak zwraca tez wskaznik
        return a;               -> przez return to wystarczy samo return a; (zmienna wskaznikowa
    }                               ->zwraca adres bez dodatkowych


int f1(int *a) {            -> przyjmij wskaznik ale zwroc wartość (dlatego int f1 bez *
        return *a;            -> i dlatego return *a czyli zwroc wartosc ze wskaznika
    }


Przypomnienie do zmiennych
int  - 4 bajty   (całkowity)
long - 4 bajty (calkowity  określany L)
long long - 8 bajtów (calkowity  )
float - 4 bajty (zmiennoprzecinkowy 7 znakow okreslany  f )
double - 8 bajtów   (zmienno przecinkowy 15 znaków  określany  f)
long double - 12 bajtów



ZADANIA:

Zad1:

#include <iostream>
    using namespace std;
 
    int main() {
        float f[2];
        float *p1 = f, *p2 = p1 + 1;
        cout << (p2 - p1) / sizeof(float);
        return 0;
    }
 
wynik 0


bo p2-p1  da 1  (odjete wskazniki (adresy) ale roznica pomimo ze skacza co 4 wyjdzie 1 bo float)
sozeof(float) = 4
czyli  1/4   a to dla danych int  wyjdzie  0



Zad2:

   #include <iostream>
    using namespace std;


    int fun(int a, int b) {                   -> moga byc inty a moze przyjac chary,
        return b-a;                               ->zamieni wtedy na liczby asci i je odejmie
    }                                                  -> i zwroci w tym przypadku inta, roznica z asci


    int main() {
        cout << fun('a','c') ;                 -> jeśli było by przeciązenie, to co najmniej jedna
        return 0;                                   -> musiala by byc char zeby rozpoznal
    }                                                    ->chyba ze by nie bylo zadnej innej przeciazonej z dwoma int

wynik 2 bo taka różnica kodów ASCI znakow   c    a


Zad3:

#include <iostream>
    using namespace std;

    int fun(long a) {
        return a / a;
    }

    int fun(int a) {
        return 2 * a;
    }

    int fun(double a) {
        return 3* a;
    }

    int main() {
        cout << fun(1000000000L) << fun (1L) << fun(1.f);
        return 0;
    }


wynik 111      , wywołanie 1L  wywoła funkcje przeciazona longiem nie int.
                          wywołanie fun(1.f) wywoła funkcję z double