Wypełnienie strun w C

80

Napisałem tę funkcję, która ma wykonywać StringPadRight ("Hello", 10, "0") -> "Hello00000".

Działa, ale ma dziwne skutki uboczne ... niektóre inne zmienne ulegają zmianie. Jak mogę to naprawić?


źródło

Odpowiedzi:

173

Warto wiedzieć, że printf wykonuje za Ciebie dopełnienie, używając% -10s jako ciągu formatu, który wypełni dane wejściowe bezpośrednio w polu o długości 10 znaków

wyjdzie

W tym przypadku symbol - oznacza „Wyrównaj do lewej”, 10 oznacza „Dziesięć znaków w polu”, a s oznacza, że ​​wyrównujesz ciąg.

Formatowanie w stylu Printf jest dostępne w wielu językach i ma wiele odniesień w Internecie. Oto jedna z wielu stron wyjaśniających flagi formatowania. Jak zwykle pomocna jest również strona printf WikiPedia (głównie lekcja historii o tym, jak szeroko rozpowszechnił się printf).

Tom Leys
źródło
4
A co, jeśli chcesz, aby ciąg był uzupełniony innym znakiem oprócz spacji? Czy istnieje sposób na zrobienie tego w printf w C?
Peter Ajtai
Wygląda na to, że nie jest to możliwe. (Zrobiłem coś w Google. Również strona podręcznika dla printfnie wydaje się zawierać żadnych wskazówek dotyczących takich funkcji.)
Victor Zamanian,
@victor - cplusplus.com/reference/clibrary/cstdio/printf - patrz punkt 'Flags' i sekcji 'width'.
Tom Leys,
1
@tom - tak, „wynik jest wypełniony spacjami”. Wydaje się więc, że nie jest to możliwe. Jak wspomniano, te same informacje są dostępne na stronie podręcznika. Ponadto, mimo że printfpowinien zachowywać się prawie tak samo, jeśli nie identycznie, jest to C, a nie C ++.
Victor Zamanian
1
@Zwycięzca. Przepraszam, myślałem, że odpowiadasz na moją odpowiedź, a nie kolejne pytanie Petera. Tak, możesz wybrać tylko pad z 0 lub z niczym innym.
Tom Leys,
42

Dla „C” istnieje alternatywne (bardziej złożone) użycie [s] printf, które nie wymaga żadnego malloc () ani wstępnego formatowania, gdy pożądane jest niestandardowe wypełnienie.

Sztuczka polega na użyciu specyfikatorów długości „*” (min i max) dla% s oraz łańcucha wypełnionego znakiem dopełniającym do maksymalnej potencjalnej długości.

"% *. * S" można umieścić przed lub po "% s", w zależności od potrzeby dopełnienia LEWEGO lub PRAWEGO.

[####Monkey] <-- Left padded, "%*.*s%s"
[Monkey####] <-- Right padded, "%s%*.*s"

Zauważyłem, że PHP printf ( tutaj ) obsługuje możliwość nadania niestandardowego znaku wypełnienia, używając pojedynczego cudzysłowu ('), po którym następuje niestandardowy znak wypełnienia , w formacie% s.
printf("[%'#10s]\n", $s); // use the custom padding character '#'
produkuje:
[####monkey]

J Jorgenson
źródło
Wygląda na to, że zduplikowałem opublikowaną tutaj odpowiedź kogoś
J Jorgenson
2

Musisz upewnić się, że ciąg wejściowy ma wystarczająco dużo miejsca, aby pomieścić wszystkie znaki wypełniające. Spróbuj tego:

Zauważ, że przydzieliłem 11 bajtów na hellołańcuch, aby uwzględnić terminator zerowy na końcu.

Greg Hewgill
źródło
1

Argument, który przekazałeś „Hello”, znajduje się w obszarze danych stałych. O ile nie przydzieliłeś wystarczającej ilości pamięci do char * string, przepełnia on inne zmienne.

Edycja: Poprawiono ze stosu do stałego obszaru danych.

Eugene Yokota
źródło
Nadal przekazujesz ciąg znaków ...: P
Jeremy Ruten
kopiujesz za dużo. Hello jest typu char [6], ale próbujesz skopiować z niego 1024 bajty. to może się tylko nie udać. zmień to, aby odczytać sizeof "Hello" zamiast drugiego sizeof (buffer)
Johannes Schaub - litb
1
strncpy (buffer, "Hello", sizeof (buffer)); już wypełnia cały bufor '\ 0', więc twój memset () jest zbędny.
Chris Young,
@litb, strncpy: Jeśli koniec źródłowego ciągu C (który jest sygnalizowany przez znak null) zostanie znaleziony przed skopiowaniem liczby znaków, miejsce docelowe jest dopełniane zerami, aż w sumie zostanie do niego zapisana liczba znaków.
Eugene Yokota,
@Chris, memset po buforze jest czymś zwyczajnym. Zostawię to tam.
Eugene Yokota
1

No dobra, ma sens. Więc zrobiłem to:

Dzięki!


źródło
1
Naga
źródło
Nie zapomnij zwolnić str1
Pierre-Louis Sauvage
1

Wynik:

Izya Budman
źródło
0

Sama funkcja wygląda dla mnie dobrze. Problem może polegać na tym, że nie przydzielasz wystarczającej ilości miejsca, aby twój ciąg mógł wypełnić tak wiele znaków. Możesz uniknąć tego problemu w przyszłości, przekazując size_of_stringargument do funkcji i upewnij się, że nie dopełniasz łańcucha, gdy długość ma być większa niż rozmiar.

Jeremy Ruten
źródło
0

Jedną rzeczą, która jest zdecydowanie błędna w funkcji, która tworzy oryginalne pytanie w tym wątku, o którym nikt nie wspominał, jest konkatenacja dodatkowych znaków na końcu literału ciągu, który został przekazany jako parametr. To da nieprzewidywalne rezultaty. W przykładowym wywołaniu funkcji ciąg znaków „Hello” zostanie na stałe zakodowany w programie, więc przypuszczalnie konkatenacja na jego końcu spowoduje niebezpieczny zapis w kodzie. Jeśli chcesz zwrócić ciąg, który jest większy niż oryginał, musisz upewnić się, że przydzielasz go dynamicznie, a po zakończeniu usuń go z kodu wywołującego.

user4478828
źródło
0
Ayodeji
źródło