Edycja: dodałem źródło dla przykładu.
Natknąłem się na ten przykład :
char source[MAX] = "123456789";
char source1[MAX] = "123456789";
char destination[MAX] = "abcdefg";
char destination1[MAX] = "abcdefg";
char *return_string;
int index = 5;
/* This is how strcpy works */
printf("destination is originally = '%s'\n", destination);
return_string = strcpy(destination, source);
printf("after strcpy, dest becomes '%s'\n\n", destination);
/* This is how strncpy works */
printf( "destination1 is originally = '%s'\n", destination1 );
return_string = strncpy( destination1, source1, index );
printf( "After strncpy, destination1 becomes '%s'\n", destination1 );
Który wyprodukował ten wynik:
miejsce docelowe to pierwotnie = 'abcdefg' Po strcpy miejsce docelowe staje się „123456789” miejsce docelowe1 pierwotnie = 'abcdefg' Po strncpy miejsce docelowe1 zmienia się na „12345fg”
Zastanawiam się, dlaczego ktoś miałby chcieć tego efektu. Wygląda na to, że byłoby to zagmatwane. Ten program sprawia, że myślę, że można by w zasadzie skopiować czyjeś nazwisko (np. Tom Brokaw) z Tomem Bro763.
Jakie są zalety używania strncpy()
nad strcpy()
?
strcpy
zamiaststrncpy
?”.getline
spowoduje nieprawidłowe wyniki, gdy oceniam je na podstawie starannie opracowanych danych wejściowych. :)Odpowiedzi:
strncpy
zwalcza przepełnienie bufora, wymagając podania w nim długości.strcpy
zależy od końcowego\0
, co nie zawsze może wystąpić.Po drugie, nie rozumiem, dlaczego zdecydowałeś się skopiować tylko 5 znaków z 7-znakowego ciągu, ale to daje oczekiwane zachowanie. To tylko kopiowanie pierwszych
n
znaków, gdzien
jest trzeci argument.Wszystkie
n
funkcje są używane do kodowania obronnego przed przepełnieniem bufora. Należy ich używać zamiast starszych funkcji, takich jakstrcpy
.źródło
strncpy
został początkowo wprowadzony do biblioteki C, aby zajmować się polami nazw o stałej długości w strukturach takich jak pozycje katalogów. Takie pola nie są używane w taki sam sposób jak łańcuchy: końcowe null jest niepotrzebne dla pola o maksymalnej długości, a ustawienie końcowych bajtów dla krótszych nazw na wartość null zapewnia wydajne porównania pod względem pola.strncpy
nie jest z pochodzenia „ograniczonym strcpy”, a Komitet wolał raczej uznać istniejącą praktykę niż zmienić jej funkcję, aby lepiej dostosować ją do takiego zastosowania.strncpy
jest to bezpieczniejsza wersja .strcpy
strncpy
zamiast,strcpy
ponieważ jest to znacznie bardziej defensywna funkcja ... tak właśnie powiedziałem.snprintf
, ale nie ma to znaczeniastrncat
i jest całkowicie nieprawdziwestrncpy
. Jak ta odpowiedź mogła kiedykolwiek dostać tyle głosów pozytywnych? Pokazuje, jak zła jest sytuacja dotycząca tej fałszywej funkcji. Używanie go nie jest obronne: w większości sytuacji programista nie rozumie jego semantyki i tworzy potencjalnie niezerowy ciąg zakończony.strncpy()
Funkcja została zaprojektowana z bardzo konkretnego problemu pamiętać: manipulowania ciągi przechowywane w sposób oryginalnych wpisów do katalogów UNIX. Używały one tablicy o stałym rozmiarze, a terminator nul był używany tylko wtedy, gdy nazwa pliku była krótsza niż tablica.To właśnie kryje się za dwiema osobliwościami
strncpy()
:Dla „bezpieczniejszego
strcpy()
” lepiej jest używać w następującystrncat()
sposób:if (dest_size > 0) { dest[0] = '\0'; strncat(dest, source, dest_size - 1); }
To zawsze zakończy zerowanie wyniku i nie skopiuje więcej niż to konieczne.
źródło
dest[0] = '\0';
przed wywołaniem strncat? Czy mógłby pan to wyjaśnić?strncat()
łączy ciąg źródłowy na końcu ciągu docelowego. Chcemy tylko skopiować ciąg źródłowy do miejsca docelowego, więc najpierw ustawiamy miejsce docelowe na pusty ciąg - to właśniedest[0] = '\0';
robi.Chociaż znam intencję, która się za tym kryje
strncpy
, nie jest to dobra funkcja. Unikaj obu. Raymond Chen wyjaśnia .Zobacz także Dlaczego strncpy jest niepewne?
źródło
strncpy NIE jest bezpieczniejsze niż strcpy, po prostu zamienia jeden typ błędów na inny. W C, obsługując łańcuchy C, musisz znać rozmiar swoich buforów, nie ma sposobu na obejście tego. strncpy było uzasadnione w przypadku katalogu wspomnianego przez innych, ale poza tym nigdy nie powinieneś go używać:
źródło
To, czego szukasz, to funkcja,
strlcpy()
która zawsze kończy ciąg z 0 i inicjalizuje bufor. Jest również w stanie wykryć przepełnienia. Jedynym problemem jest to, że nie jest (naprawdę) przenośny i występuje tylko w niektórych systemach (BSD, Solaris). Problem z tą funkcją polega na tym, że otwiera kolejną puszkę robaków, co widać w dyskusjach na http://en.wikipedia.org/wiki/StrlcpyOsobiście uważam, że jest znacznie bardziej przydatny niż
strncpy()
istrcpy()
. Ma lepszą wydajność i jest dobrym towarzyszemsnprintf()
. W przypadku platform, które go nie mają, jest to stosunkowo łatwe do wdrożenia. (w fazie rozwoju aplikacji zastępuję te dwie funkcje (snprintf()
istrlcpy()
) wersją trappingową, która brutalnie przerywa program w przypadku przepełnienia bufora lub obcięcia. Pozwala to szybko wyłapać najgorszych przestępców. Szczególnie jeśli pracujesz na bazie kodu innej osoby .EDYCJA:
strlcpy()
można łatwo zaimplementować:size_t strlcpy(char *dst, const char *src, size_t dstsize) { size_t len = strlen(src); if(dstsize) { size_t bl = (len < dstsize-1 ? len : dstsize-1); ((char*)memcpy(dst, src, bl))[bl] = 0; } return len; }
źródło
dstsize > 0
i nic nie robić, jeśli nie jest.dstsize
spowoduje wywołaniememcpy
długościlen
w buforze docelowym i przepełnienie go.Ta
strncpy()
funkcja jest bezpieczniejsza: musisz podać maksymalną długość, jaką może zaakceptować bufor docelowy. W przeciwnym razie może się zdarzyć, że łańcuch źródłowy nie zostanie poprawnie zakończony zerem. W takim przypadkustrcpy()
funkcja może zapisać więcej znaków do miejsca docelowego, uszkadzając wszystko, co znajduje się w pamięci za buforem docelowym. Jest to problem przepełnienia bufora używany w wielu exploitachRównież dla funkcji API POSIX, takich jak,
read()
które nie umieszczają kończącego 0 w buforze, ale zwracają liczbę odczytanych bajtów, możesz albo ręcznie wstawić 0, albo skopiować go używającstrncpy()
.W Twoim przykładowym kodzie w
index
rzeczywistości nie jest indeksem, alecount
- mówi, ile maksymalnie znaków ma skopiować ze źródła do celu. Jeśli wśród pierwszych n bajtów źródła nie ma bajtu zerowego, ciąg umieszczony w miejscu docelowym nie zostanie zakończony wartością nullźródło
strncpy wypełnia miejsce docelowe wartością „\ 0” dla rozmiaru źródła, nawet jeśli rozmiar miejsca docelowego jest mniejszy ....
manpage:
źródło
strncpy
wypełnia miejsce docelowe za pomocą „\ 0” dla argument size, jeśli długość źródła jest mniejsza. Argument rozmiar nie jest rozmiarem źródła, a nie maksymalną liczbą znaków do skopiowania ze źródła, ponieważ jeststrncat
to rozmiar miejsca docelowego.strncpy
nad innymi operacjami kopiowania jest to, że gwarantuje, że cała lokalizacja docelowa zostanie zapisana. Ponieważ kompilatory mogą próbować wykazać się „kreatywnością” podczas kopiowania struktur zawierających pewne nieokreślone wartości, zapewnienie pełnego zapisu wszystkich tablic znaków w strukturach może być najprostszym sposobem uniknięcia „niespodzianek”.strncpy
aby zapewnić zerowe zakończenie:strncpy(dest, src, dest_size)[dest_size - 1] = '\0';
char[8]
wewnątrz struktury radzi sobie do 8 znaków może być ładniejsze niż użycie a,char[8]
ale tylko możliwość obsługi 7 znaków lub konieczność skopiowania ciągu dochar[9]
bufora, a następniememcpy
do miejsca docelowego.char
wskaźnikami, dopóki nie osiągną zera. Te tylko rzeczą zerowej zakończone łańcuchy są naprawdę dobre, jest literały ciągów znaków, a nawet istnieje zmiennej długości kodowane prefiks będzie prawdopodobnie lepiej. W przypadku prawie wszystkiego innego byłoby lepiej, gdyby łańcuchy były poprzedzone długością lub miały specjalny prefiks, który wskazywałby, żechar*
jest to coś podobnegostruct stringInfo {char header[4]; char *realData; size_t length; size_t size;}
.Może to być używane w wielu innych scenariuszach, w których musisz skopiować tylko część oryginalnego ciągu do miejsca docelowego. Używając strncpy () możesz skopiować ograniczoną część oryginalnego ciągu w przeciwieństwie do strcpy (). Widzę, że wysłany przez Ciebie kod pochodzi z witryny publib.boulder.ibm.com .
źródło
To zależy od naszych wymagań. Dla użytkowników systemu Windows
Używamy strncpy zawsze, gdy nie chcemy kopiować całego ciągu lub chcemy skopiować tylko n liczby znaków. Ale strcpy kopiuje cały ciąg, w tym kończący znak null.
Te linki pomogą Ci dowiedzieć się więcej o strcpy i strncpy oraz o tym, gdzie możemy ich użyć.
o strcpy
o strncpy
źródło
strncpy jest bezpieczniejszą wersją strcpy w rzeczywistości nigdy nie powinieneś używać strcpy, ponieważ jego potencjalna luka w przepełnieniu bufora sprawia, że system jest podatny na wszelkiego rodzaju ataki
źródło