Błędy segmentacji w C lub C++ to błąd występujący, gdy program próbuje uzyskać dostęp do lokalizacji pamięci, do której nie ma uprawnień dostępu. Ogólnie rzecz biorąc, ten błąd występuje, gdy zostanie naruszony dostęp do pamięci i jest rodzajem ogólnego błędu zabezpieczenia. Błędy seg to skrót od błędów segmentacji.
The zrzut rdzenia odnosi się do zapisu stanu programu, czyli jego zasobów w pamięci i procesorze. Próba uzyskania dostępu do nieistniejącej pamięci lub pamięci używanej przez inne procesy również powoduje błąd segmentacji, który prowadzi do zrzutu pamięci.
Podczas działania program ma dostęp do określonych obszarów pamięci. Po pierwsze, stos służy do przechowywania zmiennych lokalnych dla każdej funkcji. Co więcej, może mieć przydzieloną pamięć w czasie wykonywania i zapisaną na stercie (nowość w C++ i możesz także usłyszeć, że nazywa się to darmowy sklep ). Jedyną pamięcią, do której program może uzyskać dostęp, jest jego pamięć (wspomniana wcześniej). Dostęp spoza tego regionu spowoduje błąd segmentacji.
Błąd segmentacji to specyficzny rodzaj błędu powodowanego przez dostęp do pamięci nie należy do ciebie :
- Kiedy fragment kodu próbuje wykonać operację odczytu i zapisu w lokalizacji tylko do odczytu w pamięci lub w zwolnionym bloku pamięci, nazywa się to błędem segmentacji.
- Jest to błąd wskazujący na uszkodzenie pamięci.
Typowe scenariusze błędów segmentacji
W przypadku błędu segmentacji program próbuje uzyskać dostęp do pamięci, do której nie ma autoryzacji lub która nie istnieje. Oto niektóre typowe scenariusze, które mogą powodować błędy segmentacji:
- Modyfikowanie literału ciągu
- Dostęp do adresu, który jest zwolniony
- Dostęp do granic indeksu spoza tablicy
- Niewłaściwe użycie scanf()
- Przepełnienie stosu
- Dereferencja niezainicjowanego wskaźnika
1. Modyfikowanie literału ciągu
Literały łańcuchowe są przechowywane w części pamięci przeznaczonej tylko do odczytu. Dlatego poniższy program może ulec awarii (powoduje błąd segmentacji), ponieważ linia *(str+1) = „n” próbuje zapisać pamięć tylko do odczytu.
Przykład:
C
// C program to demonstrate segmentation fault> // by modifying a string literal> #include> int> main()> {> >char>* str;> >// Stored in read only part of data segment //> >str =>'GfG'>;> >// Problem: trying to modify read only memory //> >*(str + 1) =>'n'>;> >return> 0;> }> |
>
>
C++
// C++ program to demonstrate segmentation fault> // by modifying a string literal> #include> using> namespace> std;> int> main()> {> >char>* str;> >// Stored in read only part of data segment //> >str =>'GfG'>;> >// Problem: trying to modify read only memory //> >*(str + 1) =>'n'>;> >return> 0;> }> |
>
>
Wyjście
timeout: monitorowane polecenie zrzuciło rdzeń
/bin/bash: linia 1: 32 Limit czasu błędu segmentacji 15 s ./83b16132-8565-4cb1-aedb-4eb593442235 <83b16132-8565-4cb1-aedb-4eb593442235.in
Aby uzyskać więcej informacji, zobacz Przechowywanie ciągów w C.
2. Dostęp do zwolnionego adresu
W poniższym kodzie wskaźnik p jest dereferowany po zwolnieniu bloku pamięci, na co kompilator nie pozwala. Takie wskaźniki nazywane są wskaźnikami wiszącymi i powodują błędy segmentów lub nieprawidłowe zakończenie programu w czasie wykonywania.
Przykład:
C
// C program to demonstrate segmentation fault> // by Accessing an address that is freed> #include> #include> int> main(>void>)> {> >// allocating memory to p> >int>* p = (>int>*)>malloc>(8);> >*p = 100;> >// deallocated the space allocated to p> >free>(p);> >// core dump/segmentation fault> >// as now this statement is illegal> >*p = 110;> >printf>(>'%d'>, *p);> >return> 0;> }> |
vlc pobieraj filmy z YouTube
>
>
C++
// C++ program to demonstrate segmentation fault> // by Accessing an address that is freed> #include> using> namespace> std;> int> main(>void>)> {> >// allocating memory to p> >int>* p = (>int>*)>malloc>(>sizeof>(>int>));> >*p = 100;> >// deallocated the space allocated to p> >free>(p);> >// segmentation fault> >// as now this statement is illegal> >*p = 110;> >return> 0;> }> |
>
>
Wyjście
Segmentation Fault>
3. Dostęp do indeksu tablicy poza granicami
W językach C i C++ dostęp do indeksu tablicy spoza zakresu może spowodować błąd segmentacji lub inne niezdefiniowane zachowanie. W językach C i C++ nie ma sprawdzania granic tablic. Chociaż w C++ użycie kontenerów, takich jak metoda std::vector::at() lub instrukcja if(), może zapobiec błędom poza granicami.
Przykład:
C
// C program to demonstrate segmentation> // fault when array out of bound is accessed.> #include> int> main(>void>)> {> >int> arr[2];> >// Accessing out of bound> >arr[3] = 10;> >return> (0);> }> |
>
>
C++
// C++ program to demonstrate segmentation> // fault when array out of bound is accessed.> #include> using> namespace> std;> int> main()> {> >int> arr[2];> >// Accessing out of bound> >arr[3] = 10;> >return> 0;> }> |
>
>
Wyjście
Segmentation Faults>
4. Niewłaściwe użycie scanf()
Funkcja scanf() oczekuje adresu zmiennej jako danych wejściowych. Tutaj w tym programie n przyjmuje wartość 2 i przyjmuje adres 1000. Jeśli przekażemy n do scanf(), dane wejściowe pobrane ze STDIN zostaną umieszczone w nieprawidłowej pamięci 2, która zamiast tego powinna wynosić 1000. Powoduje to uszkodzenie pamięci prowadzące do błędu segmentacji.
Przykład:
C
// C program to demonstrate segmentation> // fault when value is passed to scanf> #include> int> main()> {> >int> n = 2;> >scanf>(>'%d'>, n);> >return> 0;> }> |
>
>
C++
połącz bazę danych Java
// C++ program to demonstrate segmentation> // fault when value is passed to scanf> #include> using> namespace> std;> int> main()> {> >int> n = 2;> >cin>> n;> >return> 0;> }> |
>
>
Wyjście
Segementation Fault>
5. Przepełnienie stosu
Nie jest to problem związany ze wskaźnikami, nawet kod może nie mieć ani jednego wskaźnika. Dzieje się tak z powodu braku pamięci na stosie. Jest to również rodzaj uszkodzenia pamięci, który może wystąpić z powodu dużego rozmiaru tablicy, dużej liczby wywołań rekurencyjnych, dużej liczby zmiennych lokalnych itp.
Przykład:
C
// C program to illustrate the> // segmentation fault due to> // stack overflow> #include> int> main()> {> >int> arr[2000000000];> >return> 0;> }> |
>
>
C++
// C++ program to illustrate> // the segmentation fault> // due to stack overflow> #include> using> namespace> std;> int> main()> {> >int> array[2000000000];> >return> 0;> }> |
>
>
Wyjście
Segmentation Fault>
6. Przepełnienie bufora
Jeśli dane przechowywane w buforze są większe niż przydzielony rozmiar bufora, następuje przepełnienie bufora, co prowadzi do błędu segmentacji. Większość metod w języku C nie wykonuje sprawdzania wiązań, więc przepełnienie bufora zdarza się często, gdy zapomnimy przydzielić buforowi wymaganą wielkość.
Przykład:
C
// C program to illustrate the> // segementation fault due to> // buffer overflow> #include> int> main()> {> >char> ref[20] =>'This is a long string'>;> >char> buf[10];> >sscanf>(ref,>'%s'>, buf);> >return> 0;> }> |
>
>
C++
// C++ program to illustrate the> // segementation fault due to> // buffer overflow> #include> using> namespace> std;> int> main()> {> >char> ref[20] =>'This is a long string'>;> >char> buf[10];> >sscanf>(ref,>'%s'>, buf);> >return> 0;> }> |
>
>
Wyjście
Segmentation Fault>
7. Wyłuskiwanie niezainicjowanego wskaźnika lub wskaźnika NULL
Częstym błędem programistycznym jest wyłuskiwanie niezainicjowanego wskaźnika (wild pointer), co może skutkować niezdefiniowanym zachowaniem. Gdy wskaźnik jest używany w kontekście, który traktuje go jako prawidłowy wskaźnik i uzyskuje dostęp do jego wartości bazowej, nawet jeśli nie został zainicjowany tak, aby wskazywał prawidłową lokalizację pamięci, występuje ten błąd. Może to wynikać z uszkodzenia danych, błędów programu lub błędów segmentacji. W zależności od środowiska i stanu podczas dereferencji niezainicjowane wskaźniki mogą dawać różne wyniki.
Jak wiemy, wskaźnik NULL nie wskazuje żadnej lokalizacji w pamięci, więc wyłuskanie go spowoduje błąd segmentacji.
Przykład:
C
// C program to demonstrate segmentation> // fault when uninitialized pointer> // is accessed> #include> int> main()> {> >int>* ptr;> >int>* nptr = NULL;> >printf>(>'%d %d'>, *ptr, *nptr);> >return> 0;> }> |
>
>
C++
// C++ program to demonstrate segmentation> // fault when uninitialized pointer> // is accessed> #include> using> namespace> std;> int> main()> {> >int>* ptr;> >int>* nptr = NULL;> >cout << *ptr <<>' '> << *nptr;> >return> 0;> }> |
>
>
Wyjście
Segmentation Fault>
Jak naprawić błędy segmentacji?
Możemy naprawić błędy segmentacji, zwracając uwagę na wymienione przyczyny:
- Unikaj modyfikowania literałów ciągów.
- Zachowaj ostrożność podczas używania wskaźników, ponieważ są one jedną z najczęstszych przyczyn.
- Uwzględnienie rozmiaru bufora i stosu przed zapisaniem danych, aby uniknąć przepełnienia bufora lub stosu.
- Sprawdzanie granic przed uzyskaniem dostępu do elementów tablicy.
- Używaj scanf() i printf() ostrożnie, aby uniknąć nieprawidłowych specyfikatorów formatu lub przepełnienia bufora.
Ogólnie rzecz biorąc, przyczyną błędu segmentacji jest dostęp do pamięci, która nie należy do Ciebie w tym obszarze. Dopóki będziemy tego unikać, możemy uniknąć błędu segmentacji. Jeśli nawet po wykonaniu tej czynności nie możesz znaleźć źródła błędu, zaleca się użycie debugera, ponieważ prowadzi on bezpośrednio do miejsca wystąpienia błędu w programie.