Co to jest błąd segmentacji? Czy jest inaczej w C i C ++? W jaki sposób powiązane są błędy segmentacji i zwisające wskaźniki?
NullPointerException
.
Co to jest błąd segmentacji? Czy jest inaczej w C i C ++? W jaki sposób powiązane są błędy segmentacji i zwisające wskaźniki?
NullPointerException
.
Odpowiedzi:
Błąd segmentacji to szczególny rodzaj błędu spowodowanego dostępem do pamięci, która „nie należy do ciebie”. Jest to mechanizm pomocniczy, który chroni przed uszkodzeniem pamięci i wprowadzaniem trudnych do debugowania błędów pamięci. Za każdym razem, gdy pojawia się awaria, wiesz, że robisz coś złego z pamięcią - uzyskujesz dostęp do zmiennej, która została już zwolniona, zapisujesz w części pamięci tylko do odczytu itp. Błąd segmentacji jest zasadniczo taki sam w większości języków, które pozwalają na bałagan z zarządzanie pamięcią, nie ma zasadniczej różnicy między segfault w C i C ++.
Istnieje wiele sposobów, aby uzyskać awarię, przynajmniej w językach niższego poziomu, takich jak C (++). Typowym sposobem na uzyskanie segfault jest wyzerowanie wskaźnika zerowego:
int *p = NULL;
*p = 1;
Kolejna awaria zdarza się, gdy próbujesz zapisać w części pamięci oznaczonej jako tylko do odczytu:
char *str = "Foo"; // Compiler marks the constant string as read-only
*str = 'b'; // Which means this is illegal and results in a segfault
Zwisający wskaźnik wskazuje na rzecz, która już nie istnieje, jak tutaj:
char *p = NULL;
{
char c;
p = &c;
}
// Now p is dangling
Wskaźnik p
zwisa, ponieważ wskazuje na zmienną c
znakową, która przestała istnieć po zakończeniu bloku. A kiedy spróbujesz wyrejestrować zwisający wskaźnik (jak *p='A'
), prawdopodobnie dostaniesz awarię.
c
jest lokalny, oznacza to, że został on wypchnięty na stos później {
i wyskakuje z niego później }
. zwisający wskaźnik jest tylko odniesieniem do przesunięcia, które jest teraz poza stosem. dlatego modyfikowanie go w prostym programie nigdy nie wywoła żadnej awarii. z drugiej strony może to prowadzić do segfaultu w bardziej złożonym przypadku użycia, gdzie inne wywołania funkcji mogą prowadzić do wzrostu stosu i przechowywania danych wskazanych przez wiszący wskaźnik. zapisywanie do tych danych (lokalne zmienne) prowadziłoby do nieokreślonego zachowania (segfault & Co)
SIGSEGV
, więc nie oczekuję, że taki sygnał zakłócałby się ze stosem.
Warto zauważyć, że błąd segmentacji nie jest spowodowany bezpośrednim dostępem do innej pamięci procesu (to właśnie czasami słyszę), ponieważ jest to po prostu niemożliwe. Dzięki pamięci wirtualnej każdy proces ma własną wirtualną przestrzeń adresową i nie ma możliwości uzyskania dostępu do innej za pomocą dowolnej wartości wskaźnika. Wyjątkiem mogą być biblioteki współdzielone, które są tą samą fizyczną przestrzenią adresową odwzorowaną na (ewentualnie) różne adresy wirtualne i pamięć jądra, która jest nawet odwzorowana w ten sam sposób w każdym procesie (myślę, aby uniknąć opróżniania TLB podczas syscall). I takie rzeczy jak shmat;) - to, co uważam za dostęp „pośredni”. Można jednak sprawdzić, czy zwykle znajdują się one z dala od kodu procesu i zazwyczaj jesteśmy w stanie uzyskać do nich dostęp (dlatego tam są,
Mimo to błąd segmentacji może wystąpić w przypadku niewłaściwego dostępu do naszej (procesowej) pamięci (na przykład próby zapisu w przestrzeni, której nie można zapisać). Ale najczęstszym powodem jest dostęp do części wirtualnej przestrzeni adresowej, która w ogóle nie jest odwzorowana na fizyczną.
A wszystko to w odniesieniu do systemów pamięci wirtualnej.
Błąd segmentacji jest spowodowany żądaniem strony, której proces nie ma na liście w tabeli deskryptorów, lub nieprawidłowym żądaniem strony, którą ma na liście (np. Żądanie zapisu na stronie tylko do odczytu).
Zwisający wskaźnik to wskaźnik, który może, ale nie musi wskazywać prawidłowej strony, ale wskazuje „nieoczekiwany” segment pamięci.
Szczerze mówiąc, jak wspomnieli inni plakaty, Wikipedia ma na ten temat bardzo dobry artykuł, więc zajrzyj tam. Ten typ błędu jest bardzo powszechny i często nazywany innymi rzeczami, takimi jak naruszenie dostępu lub ogólny błąd ochrony.
Nie różnią się niczym w C, C ++ ani żadnym innym języku, który pozwala na korzystanie ze wskaźników. Tego rodzaju błędy są zwykle powodowane przez wskaźniki
Według wikipedii:
Błąd segmentacji występuje, gdy program próbuje uzyskać dostęp do lokalizacji pamięci, do której nie ma dostępu, lub próbuje uzyskać dostęp do lokalizacji pamięci w sposób, który jest niedozwolony (na przykład próba zapisu do lokalizacji tylko do odczytu lub nadpisać część systemu operacyjnego).
Błąd segmentacji jest również spowodowany awarią sprzętu, w tym przypadku pamięci RAM. Jest to mniej powszechna przyczyna, ale jeśli nie znajdziesz błędu w kodzie, być może pomoże ci memtest.
Rozwiązaniem w tym przypadku jest zmiana pamięci RAM.
edytować:
Oto odniesienie: Błąd segmentacji według sprzętu
Błąd segmentacji występuje, gdy proces (działająca instancja programu) próbuje uzyskać dostęp do adresu pamięci tylko do odczytu lub zakresu pamięci, który jest używany przez inny proces lub uzyskać dostęp do nieistniejącego (niepoprawnego) adresu pamięci. Problem Dangling Reference (wskaźnik) oznacza, że próba uzyskania dostępu do obiektu lub zmiennej, której zawartość została już usunięta z pamięci, np .:
int *arr = new int[20];
delete arr;
cout<<arr[1]; //dangling problem occurs here
Strona błędu segmentacji Wikipedii ma bardzo ładny opis na ten temat, podając tylko przyczyny i przyczyny. Szczegółowy opis znajduje się na wiki.
W obliczeniach błąd segmentacji (często skracany do segfault) lub naruszenie dostępu to błąd zgłaszany przez sprzęt z ochroną pamięci, powiadamiający system operacyjny (OS) o naruszeniu dostępu do pamięci.
Oto niektóre typowe przyczyny błędu segmentacji:
Te z kolei są często spowodowane błędami programowania, które powodują nieprawidłowy dostęp do pamięci:
Dereferencje lub przypisywanie do niezainicjowanego wskaźnika (dziki wskaźnik, który wskazuje na losowy adres pamięci)
Dereferencje lub przypisywanie do zwolnionego wskaźnika (zwisający wskaźnik, który wskazuje na pamięć, która została zwolniona / cofnięta / usunięta)
Przepełnienie bufora.
Przepełnienie stosu.
Próba uruchomienia programu, który nie kompiluje się poprawnie. (Niektóre kompilatory generują plik wykonywalny pomimo obecności błędów czasu kompilacji).
Krótko mówiąc: błąd segmentacji to system operacyjny wysyłający do programu sygnał informujący, że wykrył nielegalny dostęp do pamięci i przedwcześnie kończy działanie programu, aby zapobiec uszkodzeniu pamięci.
„Błąd segmentacji” oznacza, że próbowałeś uzyskać dostęp do pamięci, do której nie masz dostępu.
Pierwszy problem dotyczy twoich argumentów main. Główną funkcją powinno być int main(int argc, char *argv[])
i powinieneś sprawdzić, czy argc wynosi co najmniej 2, zanim uzyskasz dostęp do argv [1].
Ponadto, ponieważ przekazujesz liczbę zmiennoprzecinkową do printf (która, nawiasem mówiąc, przekształca się w podwójną podczas przekazywania do printf), powinieneś użyć specyfikatora formatu% f. Specyfikator formatu% s dotyczy ciągów znaków (tablice znaków zakończone „\ 0”).
Błąd segmentacji lub naruszenie dostępu występuje, gdy program próbuje uzyskać dostęp do miejsca pamięci, które nie istnieje lub próbuje uzyskać dostęp do miejsca pamięci w sposób niedozwolony.
/* "Array out of bounds" error
valid indices for array foo
are 0, 1, ... 999 */
int foo[1000];
for (int i = 0; i <= 1000 ; i++)
foo[i] = i;
Tutaj ja [1000] nie istnieje, więc występuje błąd.
Przyczyny błędu segmentacji:
it arise primarily due to errors in use of pointers for virtual memory addressing, particularly illegal access.
De-referencing NULL pointers – this is special-cased by memory management hardware.
Attempting to access a nonexistent memory address (outside process’s address space).
Attempting to access memory the program does not have rights to (such as kernel structures in process context).
Attempting to write read-only memory (such as code segment).
Istnieje kilka dobrych wyjaśnień „błędu segmentacji” w odpowiedziach, ale ponieważ w przypadku błędu segmentacji często występuje zrzut zawartości pamięci, chciałem się podzielić, gdzie jest relacja między częścią „zrzuconego rdzenia” w usterce segmentacji (zrzucony rdzeń) i pamięć pochodzi z:
Od około 1955 do 1975 r. - przed pamięcią półprzewodnikową - dominującą technologią w pamięci komputera były małe magnetyczne pączki naciągnięte na druty miedziane. Pączki były znane jako „rdzenie ferrytowe”, a pamięć główna zwana „pamięcią rdzeniową” lub „rdzeniem”.
Zabrano stąd .
Jest wystarczająco dużo definicji błędu segmentacji, chciałbym zacytować kilka przykładów, które napotkałem podczas programowania, które mogą wydawać się głupimi błędami, ale zmarnują dużo czasu.
możesz otrzymać błąd segmentacji w poniższym przypadku, podczas gdy niedopasowanie typu argumet w printf
#include<stdio.h>
int main(){
int a = 5;
printf("%s",a);
return 0;
}
wynik : Segmentation Fault (SIGSEGV)
gdy zapomniałeś przydzielić pamięć wskaźnikowi, ale próbujesz go użyć.
#include<stdio.h>
typedef struct{
int a;
}myStruct;
int main(){
myStruct *s;
/* few lines of code */
s->a = 5;
return 0;
}
wynik : Segmentation Fault (SIGSEGV)
Proste znaczenie Segmentation fault
polega na tym, że próbujesz uzyskać dostęp do pamięci, która nie należy do ciebie.Segmentation fault
występuje, gdy próbujemy czytać i / lub pisać zadania w miejscu pamięci tylko do odczytu lub próbujemy zwolnić pamięć. Innymi słowy, możemy to wyjaśnić jako pewnego rodzaju uszkodzenie pamięci.
Poniżej wymienię typowe błędy popełniane przez programistów, które do nich prowadzą Segmentation fault
.
scanf()
w niewłaściwy sposób (zapomniałem umieścić &
).int num;
scanf("%d", num);// must use &num instead of num
int *num;
printf("%d",*num); //*num should be correct as num only
//Unless You can use *num but you have to point this pointer to valid memory address before accessing it.
char *str;
//Stored in read only part of data segment
str = "GfG";
//Problem: trying to modify read only memory
*(str+1) = 'n';
// allocating memory to num
int* num = malloc(8);
*num = 100;
// de-allocated the space allocated to num
free(num);
// num is already freed there for it cause segmentation fault
*num = 110;
printf()
i scanf()
„