Defecțiuni de segmentare în C sau C++ este o eroare care apare atunci când un program încearcă să acceseze o locație de memorie pe care nu are permisiunea de a o accesa. În general, această eroare apare atunci când accesul la memorie este încălcat și este un tip de eroare generală de protecție. Segfaults sunt abrevierea pentru erori de segmentare.
The haldă de miez se referă la înregistrarea stării programului, adică a resurselor acestuia în memorie și procesor. Încercarea de a accesa memorie inexistentă sau memorie care este utilizată de alte procese cauzează, de asemenea, eroarea de segmentare care duce la o descărcare de bază.
Un program are acces la anumite regiuni de memorie în timp ce rulează. În primul rând, stiva este folosită pentru a păstra variabilele locale pentru fiecare funcție. Mai mult decât atât, ar putea avea memorie alocată în timpul execuției și salvată în heap (nou în C++ și s-ar putea să o auzi, de asemenea, numită magazin gratuit ). Singura memorie pe care programul are permisiunea să o acceseze este propria (memoria menționată anterior). O eroare de segmentare va rezulta din orice acces în afara acelei regiuni.
Eroare de segmentare este un tip specific de eroare cauzată de accesarea memoriei care nu-ți aparține :
- Când o bucată de cod încearcă să facă o operație de citire și scriere într-o locație de numai citire din memorie sau bloc eliberat de memorie, aceasta este cunoscută ca o eroare de segmentare.
- Este o eroare care indică coruperea memoriei.
Scenarii comune de erori de segmentare
Într-o eroare de Segmentare, un program încearcă să acceseze memoria care nu este autorizată să o acceseze sau care nu există. Câteva scenarii comune care pot cauza erori de segmentare sunt:
- Modificarea unui șir literal
- Accesarea unei adrese care este eliberată
- Accesarea limitelor de index în afara matricei
- Utilizarea necorespunzătoare a scanf()
- Depășirea stivei
- Dereferencing pointer neinițializat
1. Modificarea unui șir literal
Literale de șir sunt stocate în secțiunea de numai citire a memoriei. De aceea, programul de mai jos se poate bloca (da o eroare de segmentare) deoarece linia *(str+1) = ‘n’ încearcă să scrie o memorie doar pentru citire.
Exemplu:
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;> }> |
>
>
Ieșire
timeout: comanda monitorizată a descărcat nucleul
/bin/bash: line 1: 32 Segmentation fault timeout 15s ./83b16132-8565-4cb1-aedb-4eb593442235 <83b16132-8565-4cb1-aedb-4eb593442235in.
Consultați Stocarea pentru șiruri în C pentru mai multe detalii.
2. Accesarea unei adrese care este eliberată
Aici, în codul de mai jos, indicatorul p este dereferențiat după eliberarea blocului de memorie, ceea ce nu este permis de compilator. Astfel de pointeri se numesc pointeri suspendați și produc erori de segment sau terminarea anormală a programului în timpul rulării.
Exemplu:
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;> }> |
câte taste au tastaturile
>
>
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;> }> |
>
>
Ieșire
Segmentation Fault>
3. Accesarea în afara limitelor Array Index
În C și C++, accesarea unui index de matrice în afara limitelor poate provoca o eroare de segmentare sau alt comportament nedefinit. Nu există nicio verificare a limitelor pentru matrice în C și C++. Deși în C++, utilizarea containerelor, cum ar fi cu metoda std::vector::at() sau cu o instrucțiune if(), poate preveni erorile out-of-bound.
Exemplu:
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;> }> |
>
>
Ieșire
Segmentation Faults>
4. Utilizarea necorespunzătoare a scanf()
Funcția scanf() așteaptă ca intrare adresa unei variabile. Aici, în acest program, n ia o valoare de 2 și își asumă adresa ca 1000. Dacă trecem n la scanf(), intrarea preluată de la STDIN este plasată în memoria invalidă 2 care ar trebui să fie 1000. Acest lucru cauzează coruperea memoriei care duce la o eroare de segmentare.
Exemplu:
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;> }> |
>
>
Ieșire
Segementation Fault>
5. Depășirea stivei
Nu este o problemă legată de pointer, chiar și codul poate să nu aibă un singur pointer. Din cauza rămânerii fără memorie pe stivă. Este, de asemenea, un tip de corupție a memoriei care se poate întâmpla din cauza dimensiunii mari ale matricei, a unui număr mare de apeluri recursive, a multor variabile locale etc.
Exemplu:
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;> }> |
>
sortați grămada
>
Ieșire
Segmentation Fault>
6. Buffer Overflow
Dacă datele stocate în buffer sunt mai mari decât dimensiunea alocată a buffer-ului, are loc o depășire a tamponului care duce la o eroare de segmentare. Majoritatea metodelor din limbajul C nu efectuează verificarea legăturilor, așa că depășirea buffer-ului are loc frecvent atunci când uităm să alocăm dimensiunea necesară tamponului.
Exemplu:
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;> }> |
>
>
Ieșire
Segmentation Fault>
7. Dereferentarea unui pointer neinițializat sau NULL
Este o eroare obișnuită de programare să dereferiți un pointer neinițializat ( pointer sălbatic ), ceea ce poate duce la un comportament nedefinit. Când un pointer este utilizat într-un context care îl tratează ca pe un pointer valid și accesează valoarea sa de bază, chiar dacă nu a fost inițializat pentru a indica o locație de memorie validă, apare această eroare. Coruperea datelor, erori de program sau erori de segmentare pot rezulta din aceasta. În funcție de mediul și starea lor la dereferențiere, pointerii neinițializați pot da rezultate diferite.
După cum știm, pointerul NULL nu indică nicio locație de memorie, așa că dereferențiarea va duce la o eroare de segmentare.
Exemplu:
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;> }> |
>
>
Ieșire
Segmentation Fault>
Cum se remediază erorile de segmentare?
Putem remedia erorile de segmentare fiind atenți la cauzele menționate:
- Evitați modificarea literalelor de șir.
- Fiți atenți când utilizați indicatori, deoarece acestea sunt una dintre cele mai frecvente cauze.
- Luând în considerare dimensiunea tamponului și a stivei înainte de stocarea datelor pentru a evita supraîncărcarea tamponului sau a stivei.
- Verificarea limitelor înainte de a accesa elementele matricei.
- Utilizați scanf() și printf() cu atenție pentru a evita specificatorii de format incorecți sau depășirea tamponului.
În general, cauza erorii de segmentare este accesarea memoriei care nu vă aparține în spațiul respectiv. Atâta timp cât evităm să facem asta, putem evita greșeala de segmentare. Dacă nu puteți găsi sursa erorii chiar și după ce ați făcut-o, este recomandat să utilizați un depanator, deoarece duce direct la punctul de eroare în program.