Co oznacza „%. * S” w printf?

113

Mam fragment kodu, w którym znajduje się plik

printf("%.*s\n")

co to %.*sznaczy

Shaobo Wang
źródło
26
Bez dodatkowych argumentów nie jest to prawidłowe printfpołączenie.
Andrew Marshall

Odpowiedzi:

121

Możesz użyć gwiazdki ( *), aby przekazać specyfikator szerokości / precyzję do printf(), zamiast zakodować go na stałe w ciągu formatu, tj.

void f(const char *str, int str_len)
{
  printf("%.*s\n", str_len, str);
}
AusCBloke
źródło
4
Należy zauważyć, że str_lenargument musi mieć typ int(lub węższy typ całkowity, do którego zostałby podwyższony int). Byłoby błędem, aby przejść long, size_titp
MM
10
Warto wspomnieć, że prawdopodobnym celem tego kodu, szczególnie gdy jest używany z %s, jest wydrukowanie podłańcucha oryginalnego ciągu. W tym przypadku, strwskazywałoby gdzieś wewnątrz oryginalnego łańcucha (prawdopodobnie na początku) i str_lenokreślił długość podłańcucha, który powinien zostać wydrukowany.
Sonic Atom
2
Określając długość, możemy obejść drukowanie (lub sprintf) łańcucha, który nie ma terminatora zerowego, na przykład ciąg, który jest wprowadzany z dowolnego źródła opartego na strumieniu lub pliku. Co jest znacznie częstszym przypadkiem użycia, z którym się spotkałem, niż zwykłe drukowanie ładunków.
Conrad B
23

Więcej szczegółów tutaj .

wartość całkowita lub *określająca minimalną szerokość pola. Wynik jest uzupełniany znakami spacji (domyślnie), jeśli jest to wymagane, po lewej stronie, gdy jest wyrównany do prawej, lub po prawej, jeśli jest wyrównany do lewej. W przypadku użycia * szerokość jest określana przez dodatkowy argument typu int. Jeśli wartość argumentu jest ujemna, wynikiem jest określona flaga - i dodatnia szerokość pola. (Uwaga: jest to szerokość minimalna: wartość nigdy nie jest obcinana).

.po którym następuje liczba całkowita lub *, lub żadna z tych wartości nie określa precyzji konwersji. W przypadku użycia * precyzja jest określana przez dodatkowy argument typu int. Jeśli wartość tego argumentu jest ujemna, jest ignorowana. Jeśli nie jest używana ani liczba, ani *, dokładność przyjmuje się jako zero. W poniższej tabeli przedstawiono dokładne efekty precyzji.

Więc jeśli spróbujemy obu specyfikacji konwersji

#include <stdio.h>

int main() {
    int precision = 8;
    int biggerPrecision = 16;
    const char *greetings = "Hello world";

    printf("|%.8s|\n", greetings);
    printf("|%.*s|\n", precision , greetings);
    printf("|%16s|\n", greetings);
    printf("|%*s|\n", biggerPrecision , greetings);

    return 0;
}

otrzymujemy wynik:

|Hello wo|
|Hello wo|
|     Hello world|
|     Hello world|
Ondrej
źródło
12

Nie sądzę, aby powyższy kod był poprawny, ale (zgodnie z tym opisem printf()) .*oznacza

Szerokość nie jest określona w ciągu formatu, ale jako dodatkowy argument wartości całkowitej poprzedzający argument, który ma zostać sformatowany. '

Jest to więc łańcuch o dopuszczalnej szerokości jako argument.

ponownie odtwarzać
źródło
2
Dodałem odsyłacz do adresu URL, aby uniknąć zarzutów plagiatu. Oczywiście poprawny cytat mówi „ Dokładność nie wynosi…”, a nie „ Szerokość nie jest…”.
Jonathan Leffler
Jak zauważył @MattMcNabb, każde odwołanie do tej strony musi podkreślać, że „ wartość całkowita ” jest dokładnie int(lub jej podzbiorem) - a nie zwykłą wartością całkowitą, jak bardziej intuicyjna, size_tlub jej możliwymi aliasami std::string::size_type. Jest to jeszcze bardziej zagmatwane, biorąc pod uwagę, że strona, do której istnieje odwołanie, jest wymieniona size_tjako jeden z obsługiwanych specyfikatorów typu.
Anton Samsonov