2009-06-03 13 views
5

W poniższym kodzie, linia:Segmentacja wina - char wskaźnik

*end = *front; 

daje winy segmentacji. Zadałem podobne pytanie: here, ale nie jestem pewien, czy to dlatego, że mam dwie kopie num. Proszę wyjaśnić, dlaczego jest to wadliwe. Dziękuję Ci.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

char* getPalin(char* num); 

int main() 
{ 
    char* num = (char*)malloc(100); 

    num = "123456"; 

    printf("%s\n", getPalin(num)); 

    return 0; 
} 

char* getPalin(char* num) 
{ 
    int length = strlen(num); 

    if (length % 2 == 0) 
    { 
     char* front = num; 
     char* end = num + strlen(num) - 1; //pointer to end 

     while(front != num + (length/2)) //pointers not middle yet 
     { 
      *end = *front; 

      printf("%c", *end); 

      front++; 
      end--; 
     } 
    } 

    return num; 
} 

Odpowiedz

15

Te dwie linie:

char* num = (char*)malloc(100); 
num = "123456"; 

mają następujący efekt.

Pierwsza alokuje 100 bajtów i ustawia num, tak aby wskazywały te bajty.

Drugi zmienia num na punkt "123456", który prawie na pewno jest w pamięci tylko do odczytu.

Każda próba zmiany zawartości pamięci tylko do odczytu spowoduje naruszenie segmentacji. Trzeba skopiować ciąg do „d nummalloc przed przystąpieniem do jego zmiany, z:

strcpy (num, "123456"); 

to linia powinna mieć gdzie masz aktualnie:

num = "123456"; 
4

Stosować

strncpy(num, "123456", 100); 

zamiast

num = "123456"; 
+0

Niestety, nie sizeof (num), ale rozmiar przydzielonej pamięci, czyli 100. I.e. strncpy (liczba, "123456", 100); – Konstantin

+3

OP poprosił o wyjaśnienie, ale dałeś tylko rozwiązanie. I nigdy nie zapomnij ręcznie dodać null-terminator po strncpy, ponieważ nie ma gwarancji, że strncpy je doda. Wiem, że nie ma to znaczenia w tym przykładzie, ponieważ "123456" jest krótszy niż 100 bajtów, ale jeśli zdecydowałeś się użyć strncpy zamiast strcpy, używaj go właściwie - uniknąłeś jednego potencjalnego problemu (przepełnienie bufora), ale wprowadziłeś inny (ciąg bez znaku) . – qrdl

+0

@qrdl - Jeśli rozmiar docelowy określony w strncpy jest większy niż długość łańcucha, strncpy automatycznie wyrówna się z pustymi znakami. Dopiero, gdy rozmiar docelowy jest określony jako mniejszy niż długość ciągu, który ma być skopiowany, można pominąć terminator o wartości zero. Innym piontem jest pamiętać, że strncpy NIE sprawdzi, czy w pamięci docelowej jest wystarczająca ilość miejsca. Tak więc przypuszczam, że strncpy (liczba, "123456", sizeof (num)) byłoby bardziej poprawne. – ChrisBD

1

Jak na odpowiedź Konstantego.

Przydzielono już pamięć dla num za pomocą instrukcji malloc.

Gdybyś nie to można uciec:

char* num = "123456"; 

Które określić i przydzielić pamięci w locie, ale to najprawdopodobniej zostać przydzielone jako stała, a więc tylko do odczytu.

Użycie strncpy zamiast strcpy do skopiowania "123456" zapewni, że każda dodatkowa spacja poza końcem terminatora o wartości null będzie również inicjowana na wartość null, o ile n będzie równe 100 (dla twojego przykładu). W przeciwnym razie bez inicjalizacji pamięci przydzielonej przez malloc na wartość null (memset (liczba, 0, 100)), możliwe jest, że można przekroczyć koniec napisu.

Prawie zapomniałem. Wskazane jest używanie strcpy_s lub strncpy_s, ponieważ są one bezpieczniejsze, chociaż dla twojego kodu nie będzie to miało znaczenia.

+0

Rzeczywiście uważam te dwie funkcje _s() za kulę dla osób, które nie wiedzą, jak kodować defensywnie [tj. Najpierw sprawdzają warunki wstępne - nigdy nie znalazłem nawet potrzeby użycia strncpy() i nadal mój kod jest jako "bezpieczny", jak każdy używający wariantów _s()]. Co więcej, nie są jeszcze częścią standardu. – paxdiablo

+0

Stąd powód, dla którego powiedziałem, że jest wskazany. Nigdy nie przestaje mnie zadziwiać, jak wiele komercyjne oprogramowanie pozostawia otwarte na ataki z wykorzystaniem bufora. – ChrisBD

0

Przyczyną błędu jest:

char* num = (char*)malloc(100); 

W tej linii zostały uznane num jako wskaźnik do tablicy lub wskaźnik do jej pierwszego elementu nie jako ciąg znaków.

num = "123456"; 

W tym wierszu użyłeś num, ponieważ zadeklarowałeś go jako ciąg.Jest to naruszenie segmentacji, a tym samym błąd seg. Preferrable (poprawne) składnia kodu jest:

char num[100]; 
    strcpy(num,"123456"); //Even if you use num="123456"; here it would still be wrong 

LUB

char* num = (char*)malloc(100); 
    strcpy(num,"123456"); 

LUB

char num[100]={'1','2','3','4','5','6'}; 

Każda z nich będzie wykonywać swoją pracę.