logo

C/C++ segmentavimo klaida

Segmentavimo gedimai C arba C++ yra klaida, kuri įvyksta, kai programa bando pasiekti atminties vietą, prie kurios ji neturi leidimo. Paprastai ši klaida įvyksta, kai pažeidžiama prieiga prie atminties, ir yra bendrosios apsaugos gedimo tipas. Seg gedimai yra segmentavimo gedimų santrumpa.

The šerdies sąvartynas reiškia programos būsenos, ty jos išteklių atmintyje ir procesoriaus, įrašymą. Bandymas pasiekti neegzistuojančią atmintį arba atmintį, kurią naudoja kiti procesai, taip pat sukelia segmentavimo gedimą, dėl kurio atsiranda branduolio išmetimas.



Kai programa veikia, ji turi prieigą prie tam tikrų atminties sričių. Pirma, kaminas naudojamas kiekvienos funkcijos vietiniams kintamiesiems laikyti. Be to, jo atmintis gali būti paskirta vykdymo metu ir išsaugota krūvoje (nauja C++, taip pat galite išgirsti tai vadinama nemokama parduotuvė ). Vienintelė atmintis, kurią programai leidžiama pasiekti, yra jos pačios (anksčiau minėta atmintis). Segmentavimo klaida atsiras dėl bet kokios prieigos už to regiono ribų.

Segmentavimo klaida yra specifinė klaida, kurią sukelia prieiga prie atminties tau nepriklauso :

  • Kai kodo dalis bando atlikti skaitymo ir rašymo operaciją tik skaitomoje atminties vietoje arba atlaisvintame atminties bloke, tai žinoma kaip segmentavimo klaida.
  • Tai klaida, rodanti atminties sugadinimą.

Įprasti segmentavimo gedimų scenarijai

Esant segmentavimo klaidai, programa bando pasiekti atmintį, kuriai nėra prieigos teisės arba kurios nėra. Kai kurie bendri scenarijai, galintys sukelti segmentavimo gedimus, yra šie:



  1. Eilutės literalo keitimas
  2. Prieiga prie adreso, kuris yra atlaisvintas
  3. Prieiga prie masyvo ribų esančių indekso ribų
  4. Netinkamas scanf() naudojimas
  5. Stack Overflow
  6. Nuorodos panaikinimas neinicijuotoje rodyklėje

1. Stygos pažodinio žodžio modifikavimas

Eilučių literalai saugomi tik skaitomoje atminties dalyje. Štai kodėl toliau pateikta programa gali sugesti (suteikia segmentavimo klaidą), nes eilutė *(str+1) = 'n' bando įrašyti tik skaitomą atmintį.

Pavyzdys:

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;> }>

>

>

Išvestis

timeout: stebima komanda išmetė branduolį

/bin/bash: 1 eilutė: 32 Segmentavimo gedimo skirtasis laikas 15s ./83b16132-8565-4cb1-aedb-4eb593442235 <83b16132-8565-4cb1-aedb-4eb5934in42235.

Norėdami gauti daugiau informacijos, žr. Stygų saugojimas C.

2. Prieiga prie laisvo adreso

Žemiau esančiame kode, atlaisvinus atminties bloką, žymeklis p panaikinamas, o to neleidžia kompiliatorius. Tokios rodyklės vadinamos kabančiomis rodyklėmis ir jos sukelia segmento gedimus arba nenormalų programos nutraukimą vykdymo metu.

Pavyzdys:

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;> }>

Java serverio puslapiai

>

>

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;> }>

>

>

Išvestis

Segmentation Fault>

3. Prieiga prie užribio masyvo indekso

C ir C++ prieiga prie neriboto masyvo indekso gali sukelti segmentavimo gedimą arba kitą neapibrėžtą elgesį. C ir C++ masyvų ribų tikrinimas nėra. Nors C++, konteinerių naudojimas, pvz., su metodu std::vector::at() arba su if() sakiniu, gali užkirsti kelią neribotoms klaidoms.

Pavyzdys:

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;> }>

>

>

Išvestis

Segmentation Faults>

4. Netinkamas scanf() naudojimas

Funkcija scanf() tikisi kintamojo adreso kaip įvesties. Šioje programoje n reikšmė yra 2 ir jos adresas yra 1000. Jei n perduodame į scanf(), iš STDIN paimta įvestis patalpinama į netinkamą 2 atmintį, kuri turėtų būti 1000. Tai sukelia atminties sugadinimą, dėl kurio atsiranda segmentavimo klaida.

Pavyzdys:

C




// C program to demonstrate segmentation> // fault when value is passed to scanf> #include> int> main()> {> >int> n = 2;> >scanf>(>'%d'>, n);> >return> 0;> }>

>

pabandykite gaudyti bloką java
>

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;> }>

>

>

Išvestis

Segementation Fault>

5. Stack Overflow

Tai nėra su žymekliu susijusi problema, net kode gali nebūti vieno žymeklio. Taip yra dėl to, kad dėtuvėje pritrūko atminties. Tai taip pat yra atminties sugadinimo tipas, kuris gali atsirasti dėl didelio masyvo dydžio, daugybės rekursinių skambučių, daugybės vietinių kintamųjų ir kt.

Pavyzdys:

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;> }>

>

>

Išvestis

Segmentation Fault>

6. Buferio perpildymas

Jei buferyje saugomi duomenys yra didesni nei paskirtas buferio dydis, įvyksta buferio perpildymas, dėl kurio atsiranda segmentavimo klaida. Dauguma C kalbos metodų neatlieka ribojimų tikrinimo, todėl buferio perpildymas įvyksta dažnai, kai pamirštame buferiui skirti reikiamą dydį.

Pavyzdys:

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;> }>

>

>

Išvestis

Segmentation Fault>

7. Nuorodos į nepainicijuotą arba NULL žymeklį panaikinimas

Įprasta programavimo klaida panaikinti inicijuotą rodyklę (laukinę žymeklį), kuri gali sukelti neapibrėžtą elgesį. Kai žymeklis naudojamas kontekste, kuris traktuoja jį kaip tinkamą rodyklę ir pasiekia pagrindinę jo reikšmę, net jei ji nebuvo inicijuota, kad būtų nukreipta į galiojančią atminties vietą, įvyksta ši klaida. Dėl to gali atsirasti duomenų sugadinimo, programos klaidų arba segmentavimo klaidų. Priklausomai nuo aplinkos ir būsenos panaikinant nuorodas, nepainicijuoti rodyklės gali duoti skirtingus rezultatus.

Kaip žinome, NULL rodyklė nenurodo į jokią atminties vietą, todėl atšaukus nuorodą į jį atsiras segmentavimo klaida.

Pavyzdys:

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;> }>

>

>

Išvestis

Segmentation Fault>

Kaip ištaisyti segmentavimo klaidas?

Segmentavimo klaidas galime ištaisyti atidžiai stebėdami nurodytas priežastis:

  • Nekeiskite eilučių literalų.
  • Būkite atsargūs naudodami rodykles, nes jie yra viena iš dažniausiai pasitaikančių priežasčių.
  • Prieš išsaugant duomenis atsižvelkite į buferį ir dėklo dydį, kad išvengtumėte buferio ar dėklo perpildymo.
  • Prieš pasiekiant masyvo elementus tikrinama, ar nėra ribų.
  • Atsargiai naudokite scanf() ir printf(), kad išvengtumėte neteisingų formato specifikacijų arba buferio perpildymo.

Apskritai, segmentavimo gedimo priežastis yra prieiga prie atminties, kuri jums nepriklauso toje erdvėje. Tol, kol vengiame to daryti, galime išvengti segmentavimo gedimo. Jei net tai padarę nerandate klaidos šaltinio, rekomenduojama naudoti derintuvą, nes jis tiesiogiai veda į programos klaidos tašką.