Załóżmy, że masz ciąg, który NIE jest nullzakończony i znasz jego dokładny rozmiar, więc jak możesz wydrukować ten ciąg printfw C? Pamiętam taką metodę, ale nie mogę się teraz dowiedzieć ...
Ale w każdym razie jest to niebezpieczne, ktoś kiedyś wydrukuje ten ciąg z% s
pmod
6
@Pmod: Niekoniecznie, jeśli bufor nie jest widoczny dla świata zewnętrznego. Bardzo przydatne jest również wypisanie po prostu części łańcucha (który oczywiście może być zakończony wartością null). Jeśli naprawdę chcesz zobaczyć to w akcji, spójrz na proxy OpenSER / Kamailio SIP, gdzie często unikają kopiowania rzeczy z powodu tej techniki (również przy użyciu sprintf).
DarkDust
6
kolejne +1. Uwielbiam, kiedy uczę się podstawowych rzeczy, jak printfnawet po ~ dekadzie ... :)
Hertzel Guinness
1
Dla mnie jest to bardzo przydatne, gdy otrzymuję ciąg znaków zakończony wartością niezerową z API (niektóre API Windows to robią!) I muszę go zwrócić w "rozsądny" sposób. A więc: long life to%. * S (lub%. * S, co spowoduje również konwersję UNICODE <-> SINGLE-BYTE
!;
3
@ user1424739: W twoim przypadku printfwydrukuje do 11 znaków lub do momentu napotkania wartości NULL, w zależności od tego, co nastąpi wcześniej; w twoim przykładzie NULL jest na pierwszym miejscu. Określenie maksymalnej długości nie powoduje, że NULL traci swoje znaczenie „końca łańcucha” dla printf.
DarkDust
29
Oto wyjaśnienie, jak %.*sdziała i gdzie jest określone.
Specyfikacje konwersji w ciągu szablonu printf mają ogólną postać:
%[ param-no $] flags width [. precision ] type conversion
lub
%[ param-no $] flags width .*[ param-no $] type conversion
Druga forma służy do uzyskania dokładności z listy argumentów:
Możesz również określić dokładność „*”. Oznacza to, że następny argument z listy argumentów (przed rzeczywistą wartością do wydrukowania) jest używany jako precyzja. Wartość musi być liczbą całkowitą i jest ignorowana, jeśli jest ujemna.
W przypadku %sformatowania ciągów precyzja ma specjalne znaczenie:
Można określić precyzję, aby wskazać maksymalną liczbę znaków do zapisania; w przeciwnym razie do strumienia wyjściowego zapisywane są znaki w ciągu do, ale bez kończącego znaku null.
Jeśli dobrze rozumiem, poniższe elementy będą wypełniać dane wyjściowe, ale nadal zapobiegną przepełnieniu ciągu? "%-*.*s", padding, str_view.size(), str_view.data()
W ten sposób wypisujesz pierwsze znaki (liczbę zdefiniowaną w zmiennej number_of_chars) do pliku, w tym przypadku na stdout (standardowe wyjście, twój ekran)!
Bardzo przydatne, gdy chcesz sprawdzić długi bufor zawierający ciągi znaków i zera!
Elist
13
printf("%.*s", length, string) nie będzie działać.
Oznacza to wydrukowanie do długości bajtów LUB bajtu zerowego, cokolwiek nastąpi wcześniej. Jeśli twoja tablica znaków zakończona wartością zerową zawiera bajty o wartości null PRZED długością, printf zatrzyma się na nich i nie będzie kontynuował.
jeśli nie jest zakończony znakiem null, to null jest prawidłowym znakiem, który ma zawierać ciąg. to nadal uważa, że tablica jest zakończona wartością zerową, po prostu traktuje ją jako dłuższą tablicę, z której jest wybierana podrzędnie - co oznacza, że jeśli masz łańcuch zawierający wartości null, spowoduje to problemy.
#include<string.h>int main(){/*suppose a string str which is not null terminated and n is its length*/int i;for(i=0;i<n;i++){
printf("%c",str[i]);}return0;}
Zredagowałem kod, oto inny sposób:
#include<stdio.h>int main(){
printf ("%.5s","fahaduddin");/*if 5 is the number of bytes to be printed and fahaduddin is the string.*/return0;}
Bardzo zła wydajność z powodu wielu niepotrzebnych odczytów bajtów (które wiążą się ze spadkiem wydajności, jeśli bajt nie znajduje się pod adresem wyrównanym do słów na większości procesorów), a także parsowanie formatowania i stosowanie jest wykonywane dla każdego znaku. Nie rób tego :-) Zobacz moją odpowiedź na rozwiązanie.
DarkDust
@DarkDust: tylko patologiczna maszyna karałaby odczyty bajtów nie wyrównane do granic słów. Czy myślisz o odczytach słów nie wyrównanych do granic słów? Albo jakieś stare bzdury, czy coś?
R .. GitHub STOP HELPING ICE
@R ..: Jeśli uważasz, że x86 ma uszkodzony mózg i jest przestarzały, absolutnie się zgadzam. Ponieważ x86 ma kary za czytanie i zapisywanie pamięci nie wyrównanej słowami. Tak samo działa ARM. Zobacz na przykład to pytanie lub to pytanie . Chodzi o to (jeśli dobrze to zrozumiałem), że dane są pobierane z pamięci w kawałkach wielkości słowa, a pobranie prawidłowego bajtu to kolejna mikrooperacja. Nic wielkiego, ale w wielkiej pętli może to mieć znaczenie.
DarkDust
@DarkDust: całkowicie się mylisz, jeśli chodzi o odczyty bajtów. Dlaczego nie pójdziesz do testu porównawczego? x86 ma całkowicie atomowe operacje bajtowe i zawsze tak było. Nie pobiera fragmentów wielkości słowa (z wyjątkiem poziomu pamięci podręcznej, który pobiera znacznie większe fragmenty, a wyrównanie jest nieistotne, ale mówię o danych już zapisanych w pamięci podręcznej).
R .. GitHub STOP HELPING ICE
@DarkDust: PS3 nie obsługuje odczytu lub zapisu niewyrównanych bajtów na SPU. W rzeczywistości nie obsługuje nawet typów skalarnych, istnieje tylko wektor, który należy wyrównać. Kompilator je emuluje. Wiele procesorów ARM nie obsługuje odczytu ani zapisu bajtów, a jedynie wykonuje odczyt lub zapis słów.
C
kontekście wszystkie ciągi są zakończone wartością null. Tablice znaków bez null w nich nie są łańcuchami ... są tablicami znaków :)Odpowiedzi:
Jest taka możliwość z printf, wygląda to tak:
Nie ma potrzeby kopiowania czegokolwiek, nie ma potrzeby modyfikowania oryginalnego ciągu lub bufora.
źródło
printf
nawet po ~ dekadzie ... :)printf
wydrukuje do 11 znaków lub do momentu napotkania wartości NULL, w zależności od tego, co nastąpi wcześniej; w twoim przykładzie NULL jest na pierwszym miejscu. Określenie maksymalnej długości nie powoduje, że NULL traci swoje znaczenie „końca łańcucha” dlaprintf
.Oto wyjaśnienie, jak
%.*s
działa i gdzie jest określone.Druga forma służy do uzyskania dokładności z listy argumentów:
- Składnia konwersji danych wyjściowych w podręczniku glibc
W przypadku
%s
formatowania ciągów precyzja ma specjalne znaczenie:- Inne konwersje danych wyjściowych w podręczniku glibc
Inne przydatne warianty:
"%*.*s", maxlen, maxlen, val
wyrówna do prawej, wstawiając spacje przed;"%-*.*s", maxlen, maxlen, val
uzasadni do lewej.źródło
"%-*.*s", padding, str_view.size(), str_view.data()
Możesz użyć fwrite () do wyjścia!
W ten sposób wypisujesz pierwsze znaki (liczbę zdefiniowaną w zmiennej number_of_chars) do pliku, w tym przypadku na stdout (standardowe wyjście, twój ekran)!
źródło
printf("%.*s", length, string)
nie będzie działać.Oznacza to wydrukowanie do długości bajtów LUB bajtu zerowego, cokolwiek nastąpi wcześniej. Jeśli twoja tablica znaków zakończona wartością zerową zawiera bajty o wartości null PRZED długością, printf zatrzyma się na nich i nie będzie kontynuował.
źródło
Długość struny będzie wynosić 5.
źródło
Zredagowałem kod, oto inny sposób:
źródło