0Pricing
C Academy · Lekcja

Wiszące wskaźniki

Niebezpieczeństwa użycia po free

Wiszące wskaźniki to bezpłatna lekcja C Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C Academy zawiera 4 lekcji w sumie.

Czym jest wiszący wskaźnik

Wiszący wskaźnik wskazuje pamięć, która została już zwolniona lub z innego powodu nie jest już prawidłowa.

Użycie takiego wskaźnika prowadzi do niezdefiniowanego działania programu: awarii, uszkodzenia danych lub trudnych do wykrycia błędów.

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *p = malloc(sizeof(int));
    *p = 5;
    printf("%d\n", *p);
    free(p);
    p = NULL;
    return 0;
}

Użycie po zwolnieniu pamięci

Najczęstszą przyczyną jest odczyt lub zapis przez wskaźnik po wywołaniu free.

Zwolniony blok mógł już zostać wykorzystany do czegoś innego.

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *p = malloc(sizeof(int));
    *p = 42;
    free(p);
    /* Reading *p here would be use-after-free. */
    p = NULL;
    printf("avoided use-after-free\n");
    return 0;
}

NULL po zwolnieniu pamięci

Ustawienie wskaźnika na NULL zaraz po zwolnieniu pamięci zamienia przypadkowe użycie w wyraźną awarię albo nieszkodliwe wywołanie free(NULL).

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    char *buf = malloc(10);
    buf[0] = 'A';
    free(buf);
    buf = NULL;
    if (buf == NULL) printf("buf is safely null\n");
    return 0;
}

Zwracanie adresu zmiennej lokalnej

Zwrócenie adresu zmiennej lokalnej (na stosie) tworzy wiszący wskaźnik: zmienna przestaje istnieć po zakończeniu działania funkcji.

Zamiast tego należy użyć sterty lub przekazać bufor.

#include <stdio.h>
#include <stdlib.h>

int *make_value(int v) {
    int *p = malloc(sizeof(int));
    *p = v;
    return p;
}

int main(void) {
    int *p = make_value(99);
    printf("%d\n", *p);
    free(p);
    return 0;
}

Wiele wskaźników do jednego bloku

Jeśli dwa wskaźniki odnoszą się do tego samego bloku, zwolnienie pamięci przez jeden z nich sprawia, że drugi staje się wiszący.

Należy śledzić własność pamięci, aby tylko właściciel ją zwalniał.

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *a = malloc(sizeof(int));
    *a = 7;
    int *b = a;
    printf("%d\n", *b);
    free(a);
    a = NULL;
    b = NULL;
    printf("both nulled\n");
    return 0;
}

Wiszący wskaźnik po realloc

Gdy realloc przenosi blok, każdy stary wskaźnik do poprzedniej lokalizacji staje się wiszący.

Należy używać wyłącznie wskaźnika zwróconego przez realloc.

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *a = malloc(sizeof(int));
    a[0] = 1;
    int *b = realloc(a, 50 * sizeof(int));
    /* a may now be dangling; use only b. */
    b[0] = 2;
    printf("%d\n", b[0]);
    free(b);
    return 0;
}

Zwalnianie pamięci w funkcji pomocniczej

Jeśli funkcja pomocnicza zwolni blok, wskaźnik wywołującego pozostanie wiszący. Należy wyzerować go po wywołaniu albo zaprojektować funkcję pomocniczą tak, aby przyjmowała wskaźnik do wskaźnika.

#include <stdio.h>
#include <stdlib.h>

void destroy(int **p) {
    free(*p);
    *p = NULL;
}

int main(void) {
    int *p = malloc(sizeof(int));
    *p = 5;
    destroy(&p);
    printf("p is %s\n", p == NULL ? "null" : "set");
    return 0;
}

Dlaczego jest to niebezpieczne

Użycie pamięci po jej zwolnieniu jest niebezpieczne, ponieważ może ona zawierać już inne dane. Zapisy mogą uszkodzić niezwiązany stan programu, a atakujący mogą wykorzystać ten błąd.

Wiszące wskaźniki zależne od zakresu

Wskaźnik do zmiennej lokalnej zakresu blokowego staje się nieprawidłowy po zakończeniu tego bloku. Wskaźniki należy przechowywać nie dłużej niż trwa istnienie obiektów, na które wskazują.

#include <stdio.h>

int main(void) {
    int *p;
    {
        int x = 10;
        p = &x;
        printf("in scope: %d\n", *p);
    }
    /* p now dangles; do not dereference it here. */
    printf("block ended\n");
    return 0;
}

Wykrywanie wiszących wskaźników

Narzędzia takie jak AddressSanitizer i Valgrind wykrywają użycie pamięci po jej zwolnieniu w czasie działania programu i wskazują dokładny wiersz.

Podczas programowania należy kompilować program z włączonymi sanitizerami.

Podsumowanie bezpiecznego cyklu życia w kodzie

Przydzielić pamięć, użyć jej, zwolnić i wyzerować wskaźnik. Konsekwentne stosowanie tej zasady zapobiega powstawaniu wiszących wskaźników.

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *p = malloc(sizeof(int));
    if (!p) return 1;
    *p = 123;
    printf("%d\n", *p);
    free(p);
    p = NULL;
    return 0;
}

Szybki sprawdzian

Sprawdź swoją wiedzę o wiszących wskaźnikach.

Podsumowanie

Dowiedział się Pan / Dowiedziała się Pani o wiszących wskaźnikach:

  • Wskazują one zwolnioną pamięć lub pamięć spoza zakresu; ich użycie jest niezdefiniowanym działaniem programu.
  • Należy unikać zwracania adresów zmiennych lokalnych; nigdy nie należy używać wskaźnika po free ani po przeniesieniu bloku przez realloc.
  • Po zwolnieniu pamięci należy ustawiać wskaźniki na NULL i śledzić własność pamięci.
  • Sanitizery i Valgrind pomagają wykrywać użycie pamięci po jej zwolnieniu.

Często zadawane pytania

Czy lekcja „Wiszące wskaźniki” jest bezpłatna?

Tak — pełny tekst „Wiszące wskaźniki” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C Academy, przejdź na CoddyKit PRO. Kurs C Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Wiszące wskaźniki”?

Niebezpieczeństwa użycia po free Ćwiczysz C Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C Academy?

Nie wymagamy żadnego doświadczenia. C Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Wiszące wskaźniki”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C Academy?

Tak. Każda lekcja C Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. malloc i free
  2. calloc i realloc
  3. Wycieki pamięci
  4. Wiszące wskaźniki
← Powrót do C Academy