Mam globalną strukturę:
struct thread_data{
char *incall[10];
int syscall arg_no;
int client_socket;
};
I w głównym ()
char buffer[256];
char *incall[10];
struct thread_data arg_to_thread;
strcpy(incall[0],buffer); /*works fine*/
strcpy(arg_to_thread.incall[0],buffer); /*causes segmentation fault*/
Dlaczego tak się dzieje i proszę zasugerować wyjście.
Dzięki
3 odpowiedzi
Segfault oznacza, że coś jest nie tak. Ale nie segfault nie oznacza, że coś nie jest nie tak. Jeśli dwie sytuacje są w zasadzie takie same, a jedna jest segfault, a druga nie, zwykle oznacza to, że są obie błędne, ale tylko jedna z nich uruchamia segfault.
Patrząc na linię char* incall[10]
, oznacza to, że masz tablicę 10 wskaźników do znaku. Domyślnie te wskaźniki będą wskazywać losowe miejsca. Dlatego strcpying do incall[0] będzie kopiować ciąg do losowej lokalizacji. To najprawdopodobniej spowoduje segfault! Musisz najpierw zainicjować incall[0] (używając malloc
).
Więc ważniejsze pytanie brzmi: dlaczego nie jest segfault w pierwszej linii? Wyobrażam sobie, że powodem jest to, że tak się składa, że to, co było wcześniej w pamięci, było prawidłowym wskaźnikiem. Dlatego strcpy nie segfault, po prostu nadpisuje coś innego, co później spowoduje całkowicie nieoczekiwane zachowanie. Musisz więc poprawić oba wiersze kodu.
Innym problemem (gdy już to naprawisz) jest to, że strcpy
sam w sobie jest bardzo niebezpieczny — ponieważ kopiuje ciągi, aż znajdzie 0 bajtów, a następnie się zatrzyma, nigdy nie możesz być pewien, ile dokładnie skopiować (chyba że używasz strlen
do przydzielenia pamięci docelowej). Dlatego powinieneś zamiast tego użyć strncpy
, aby ograniczyć liczbę kopiowanych bajtów do rozmiaru bufora.
strcpy()
jest całkowicie bezpieczny. Nie wszyscy zapewniają, że są bezpieczni. (Istnieje argument, że jeśli wiesz, jak długie są łańcuchy, możesz użyć memmove()
, a czasem memcpy()
, aby wykonać kopiowanie łańcucha wydajniej.) Pamiętaj, że strncpy()
nie gwarantuje zerowego zakończenia Twoich ciągów. (Korzystanie z strncat()
jest jeszcze bardziej niebezpieczne!)
strncpy()
są, IMNSHO, przewyższane przez złe zachowanie w jednym przypadku, w którym naprawdę potrzebujesz tego, aby zachowywać się rozsądnie. Żyłbym z zerowym wypełnieniem, gdyby gwarantowało zerowe zakończenie. W swoim pierwotnym zastosowaniu nie zerowe zakończenie było pozytywną cnotą, ale to już historia starożytna. (Zaprojektowano go do kopiowania 14-znakowych nazw plików w katalogach w systemie Unix.)
Nie zainicjalizowałeś wskaźnika incall[0]
, więc Bóg wie tylko, dokąd pisze pierwszy strcpy()
. Masz pecha, że Twój program nie zawiesza się od razu.
Nie zainicjalizowałeś wskaźnika arg_to_thread.incall[0]
, więc Bóg wie tylko, dokąd pisze drugi strcpy()
. Masz szczęście, że Twój program ulega awarii teraz, a nie później.
W żadnym wypadku nie jest to wina kompilatora; musisz zawsze upewnić się, że zainicjujesz swoje wskaźniki.
- Upewnij się, że masz wystarczająco dużo pamięci przydzielonej dla buforów łańcuchowych.
- Trzymaj się z dala od
strcpy
. Zamiast tego użyjstrncpy
.strcpy
jest znanym źródłem luk w zabezpieczeniach związanych z przepełnieniem bufora - koszmarem bezpieczeństwa i konserwacji, dla którego tak naprawdę nie ma usprawiedliwienia.
strncpy()
nie gwarantuje zerowego zakończenia twoich łańcuchów, jeśli źródło jest zbyt długie. Gwarantuje również wypełnienie pustego ciągu, jeśli źródło jest krótsze niż miejsce docelowe. (Użycie strncat()
jest jeszcze bardziej ryzykowne! Jaki rozmiar określasz w parametrze długości? Odpowiedź nie jest wielkością ciągu docelowego!)
Podobne pytania
Powiązane pytania
Nowe pytania
c
C jest językiem programowania ogólnego przeznaczenia, używanym do programowania systemów (system operacyjny i systemy wbudowane), bibliotek, gier i wielu platform. Ten znacznik powinien być używany w przypadku ogólnych pytań dotyczących języka C, zgodnie z definicją w standardzie ISO 9899 (najnowsza wersja 9899: 2018, chyba że określono inaczej - również oznaczanie żądań dotyczących wersji za pomocą c89, c99, c11 itd.). C różni się od C ++ i nie należy go łączyć ze znacznikiem C ++ bez racjonalnego powodu.