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ść:
malloc
Funkcja 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.
free
Funkcja free zwalnia blok pamięci wskazywany przez ptr wcześniej przydzielony przez malloc
. Jeżeli ptr ma wartość NULL funkcja nie robi nic.
int
Pełna analogia.
Dereferencja niezainicjalizowanych wskaźników: