Segmentační chyby v C nebo C++ je chyba, ke které dochází, když se program pokusí získat přístup k umístění paměti, ke kterému nemá oprávnění. Obecně k této chybě dochází při narušení přístupu do paměti a jedná se o typ obecné chyby ochrany. Segfaulty jsou zkratky pro segmentační chyby.
The jádrový výsyp se týká záznamu stavu programu, tedy jeho zdrojů v paměti a procesoru. Pokus o přístup k neexistující paměti nebo paměti, která je používána jinými procesy, také způsobí chybu segmentace, která vede k výpisu jádra.
Program má během svého běhu přístup k určitým oblastem paměti. Za prvé, zásobník se používá k uložení lokálních proměnných pro každou funkci. Navíc může mít paměť alokovanou za běhu a uloženou na hromadě (nové v C++ a můžete také slyšet, jak se nazývá bezplatný obchod ). Jediná paměť, ke které má program povolen přístup, je jeho vlastní (paměť zmíněná výše). Chyba segmentace bude důsledkem jakéhokoli přístupu mimo tuto oblast.
Chyba segmentace je specifický druh chyby způsobené přístupem do paměti, která vám nepatří :
- Když se část kódu pokusí provést operaci čtení a zápisu v místě pouze pro čtení v paměti nebo uvolněném bloku paměti, nazývá se to chyba segmentace.
- Je to chyba indikující poškození paměti.
Běžné scénáře chyb segmentace
V případě chyby segmentace se program pokusí o přístup k paměti, která nemá oprávnění k přístupu nebo která neexistuje. Některé běžné scénáře, které mohou způsobit chyby segmentace, jsou:
- Úprava řetězcového literálu
- Přístup k adrese, která je uvolněna
- Přístup k hranicím indexu mimo pole
- Nesprávné použití scanf()
- Přetečení zásobníku
- Dereferencování neinicializovaného ukazatele
1. Úprava řetězcového literálu
Řetězcové literály jsou uloženy v části paměti pouze pro čtení. To je důvod, proč níže uvedený program může selhat (zobrazí chybu segmentace), protože řádek *(str+1) = ‚n‘ se pokouší zapsat paměť pouze pro čtení.
Příklad:
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;> }> |
>
>
Výstup
časový limit: monitorovaný příkaz vypustil jádro
/bin/bash: řádek 1: 32 Časový limit chyby segmentace 15s ./83b16132-8565-4cb1-aedb-4eb593442235 <83b16132-8565-4cb1-aedb-4eb593442235in.
Další podrobnosti naleznete v části Úložiště řetězců v jazyce C.
2. Přístup k adrese, která je uvolněna
Zde v níže uvedeném kódu je ukazatel p dereferencován po uvolnění paměťového bloku, což kompilátor neumožňuje. Takové ukazatele se nazývají visící ukazatele a způsobují chyby segmentu nebo abnormální ukončení programu za běhu.
Příklad:
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;> }> |
strojové učení pod dohledem
>
>
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;> }> |
>
>
Výstup
Segmentation Fault>
3. Přístup mimo rámec Array Index
V C a C++ může přístup k indexu pole mimo hranice způsobit chybu segmentace nebo jiné nedefinované chování. Neexistuje žádná kontrola hranic pro pole v C a C++. Ačkoli v C++ může použití kontejnerů, jako je například metoda std::vector::at() nebo příkaz if(), zabránit chybám mimo rámec.
Příklad:
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;> }> |
>
>
Výstup
Segmentation Faults>
4. Nesprávné použití scanf()
Funkce scanf() očekává jako vstup adresu proměnné. Zde v tomto programu n nabývá hodnoty 2 a předpokládá svou adresu jako 1000. Pokud předáme n do scanf(), vstup načtený z STDIN je umístěn do neplatné paměti 2, která by měla být místo toho 1000. To způsobí poškození paměti vedoucí k chybě segmentace.
Příklad:
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++
// 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;> }> |
>
>
Výstup
Segementation Fault>
5. Přetečení zásobníku
Nejde o problém související s ukazatelem, i když kód nemusí mít jediný ukazatel. Je to kvůli nedostatku paměti na zásobníku. Je to také typ poškození paměti, ke kterému může dojít v důsledku velké velikosti pole, velkého počtu rekurzivních volání, mnoha místních proměnných atd.
Příklad:
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;> }> |
>
>
Výstup
Segmentation Fault>
6. Přetečení vyrovnávací paměti
Pokud jsou data uložená ve vyrovnávací paměti větší než přidělená velikost vyrovnávací paměti, dojde k přetečení vyrovnávací paměti, což vede k chybě segmentace. Většina metod v jazyce C neprovádí vázanou kontrolu, takže k přetečení vyrovnávací paměti dochází často, když zapomeneme vyrovnávací paměti přidělit požadovanou velikost.
Příklad:
C
java výjimky
// 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;> }> |
>
>
Výstup
Segmentation Fault>
7. Dereferencování neinicializovaného nebo NULL ukazatele
Běžnou chybou programování je dereferencování neinicializovaného ukazatele ( wild pointer ), což může vést k nedefinovanému chování. Když je ukazatel použit v kontextu, který s ním zachází jako s platným ukazatelem a přistupuje k jeho základní hodnotě, přestože nebyl inicializován, aby ukazoval na platné umístění paměti, dojde k této chybě. Výsledkem může být poškození dat, chyby programu nebo chyby segmentace. V závislosti na jejich prostředí a stavu při dereferencování mohou neinicializované ukazatele přinést různé výsledky.
Jak víme, ukazatel NULL neukazuje na žádné místo v paměti, takže jeho dereferencování bude mít za následek chybu segmentace.
Příklad:
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;> }> |
>
>
Výstup
Segmentation Fault>
Jak opravit chyby segmentace?
Chyby segmentace můžeme opravit tak, že budeme opatrní ohledně uvedených příčin:
- Vyhněte se úpravám řetězcových literálů.
- Při používání ukazatelů buďte opatrní, protože jsou jednou z nejčastějších příčin.
- Zvažte velikost vyrovnávací paměti a zásobníku před uložením dat, abyste se vyhnuli přetečení vyrovnávací paměti nebo zásobníku.
- Kontrola hranic před přístupem k prvkům pole.
- Použijte scanf() a printf() opatrně, abyste se vyhnuli nesprávným specifikátorům formátu nebo přetečení vyrovnávací paměti.
Celkově je příčinou chyby segmentace přístup k paměti, která vám v tomto prostoru nepatří. Dokud se tomu vyhneme, můžeme se vyhnout chybě segmentace. Pokud ani poté nemůžete najít zdroj chyby, doporučuje se použít debugger, protože to přímo vede k bodu chyby v programu.