Testowanie efektów ubocznych (side effects): Jeśli funkcja wpływa na stan systemu lub zmienia stan obiektów/innych zmiennych, to można przetestować, czy te zmiany są poprawne i oczekiwane. Na przykład, jeśli funkcja zapisuje dane do bazy danych, możesz sprawdzić, czy te dane zostały zapisane w oczekiwany sposób.
Testowanie wyjątków (exceptions): Można przetestować, czy funkcja rzuca wyjątki (błędy w trakcie wykonania), gdy powinna. W ten sposób można zweryfikować, czy funkcja zachowuje się zgodnie z oczekiwaniami w sytuacjach wyjątkowych. - to dostarcza programownie obiektowe (!!!).
Testowanie typów zwracanych przez funkcję: Jeśli funkcja zwraca wartość, można przetestować, czy jest ona poprawnego typu. Na przykład, jeśli funkcja powinna zwracać liczbę całkowitą, można sprawdzić, czy zwraca wartość typu int. Zwykle powinna być to “najmniejsza grupa typów”.
Testowanie czy funkcja zwraca wartości niemodyfikujące stanu: Jeśli funkcja nie wpływa na stan systemu lub zmienia stan obiektów/innych zmiennych, można przetestować, czy zwraca poprawne wartości dla różnych argumentów wejściowych.
Program w języku C po skompilowaniu wykorzystuje trzy rodzaje pamięci:
Przypadek do analizy:
Zmienne globalne:
Problem?
Zmienne statyczne:
| Rodzaj pamięci | Zasięg | Okres istnienia |
|---|---|---|
| globalna | cały plik | cały okres działania aplikacji |
| statyczna | funkcja, w której została zadeklarowana | cały okres działania aplikacji |
| automatyczna (lokalna) | funkcja, w której została zadeklarowana | czas wykonywania funkcji |
| dynamiczna | określony przez wskaźniki odnoszące się do tej pamięci | do momentu zwolnienia pamięci |
Wskaźnik (ang. pointer) to specjalny rodzaj zmiennej, w której zapisany jest adres (innej zmiennej lub funkcji) w pamięci komputera.
| Symbol | znaczenie | użycie |
|---|---|---|
* |
weź wartość x |
*x |
* |
deklaracja wskaźnika do wartości | int *x; |
& |
weź adres | &x |
Przeanalizujmy kod:
void idzPrawoDol(int x, int y)
{
x=x+1;
y=y-1;
}
int main()
{
int x=20, y=15;
idzPrawoDol(x,y);
printf("Aktualna pozycja: [ %d, %d ] \n",x,y);
return 0;
}Na wyjściu otrzymujemy:
Aktualna pozycja: [ 20, 15 ]
Dlaczego tak się dzieje?
W języku C argumenty przekazywane są przez wartość.
Na początku funkcji main mamy dwie zmienne:
Podczas wykonywania funkcji idzPrawoDol następuje kopiowanie wartości do zmiennych lokalnych:
Potem zmiana zmiennych lokalnych:
Jak to naprawić? Użyjemy wskaźników.
void idzPrawoDol(int *x, int*y)
{
*x=*x+1;
*y=*y-1;
}
int main()
{
int x=20, y=15;
idzPrawoDol(&x,&y);
printf("Aktualna pozycja: [ %d, %d ] \n",x,y);
return 0;
}Na wyjściu będzie:
Aktualna pozycja: [ 21, 14 ]
Ważne, że poniższe zapisy są równoważne:
Pamięć wirtualna – mechanizm zarządzania pamięcią komputera zapewniający procesowi wrażenie pracy w jednym, dużym, ciągłym obszarze pamięci operacyjnej podczas, gdy fizycznie może być ona pofragmentowana, nieciągła i częściowo przechowywana na urządzeniach pamięci masowej. Systemy korzystające z tej techniki ułatwiają tworzenie rozbudowanych aplikacji oraz poprawiają wykorzystanie fizycznej pamięci RAM w systemach wielozadaniowych.
ASLR (Address Space Layout Randomization) tłumaczony jest jako mechanizm losowego generowania lokalizacji alokacji pamięci wirtualnej.
Poprawnie:
lub
Wątpliwe dla niektórych kompilatorów
Wskaźnik na stałą wartość:
Stały wskaźnik:
Stały wskaźnik na stałą wartość:
mallocFunkcja służy do dynamicznego rezerwowania miejsca w pamięci. Gdy funkcja zostanie wywołana, w przypadku sukcesu zwróci wskaźnik do nowo zarezerwowanego miejsca w pamięci; w przypadku błędu zwraca wartość NULL.
freeFunkcja free zwalnia blok pamięci wskazywany przez ptr wcześniej przydzielony przez malloc. Jeżeli ptr ma wartość NULL funkcja nie robi nic.
intPełna analogia.
Dereferencja niezainicjalizowanych wskaźników: