Apa artinya "%. * S" di printf?

113

Saya mendapat cuplikan kode yang berisi file

printf("%.*s\n")

apa %.*smaksudnya

Shaobo Wang
sumber
26
Tanpa argumen tambahan, itu bukan printfpanggilan yang valid .
Andrew Marshall

Jawaban:

120

Anda dapat menggunakan tanda bintang ( *) untuk meneruskan penentu lebar / presisi printf(), daripada mengkodekannya secara langsung ke dalam format string, yaitu

void f(const char *str, int str_len)
{
  printf("%.*s\n", str_len, str);
}
AusCBloke
sumber
4
Perlu dicatat bahwa str_lenargumen harus memiliki tipe int(atau tipe integral yang lebih sempit, yang akan dipromosikan menjadi int). Ini akan menjadi bug untuk lulus long, size_t, dll
MM
10
Perlu disebutkan bahwa kemungkinan tujuan kode ini, terutama bila digunakan dengan %s, adalah untuk mencetak sub-string dari string asli. Dalam kasus penggunaan ini, strakan menunjuk ke suatu tempat di dalam string asli (mungkin di awal), dan str_lenakan menentukan panjang sub-string yang harus dicetak.
Sonic Atom
2
Dengan menentukan panjangnya, kita bisa menyelesaikan pencetakan (atau sprintf) string yang tidak memiliki terminator null, misalnya string yang dimasukkan dari sumber berbasis aliran atau file. Yang jauh lebih sering merupakan kasus penggunaan yang saya temui, daripada sekadar print prettines.
Conrad B
23

Lebih detail di sini .

nilai integer atau *yang menentukan lebar bidang minimum. Hasilnya diisi dengan karakter spasi (secara default), jika diperlukan, di kiri saat rata kanan, atau di kanan jika rata kiri. Dalam kasus ketika * digunakan, lebarnya ditentukan oleh argumen tambahan bertipe int. Jika nilai argumennya negatif, hasilnya adalah bendera - ditentukan dan lebar bidang positif. (Catatan: Ini adalah lebar minimum: Nilainya tidak pernah dipotong.)

.diikuti dengan bilangan bulat atau *, atau tidak satu pun yang menentukan presisi konversi. Dalam kasus ketika * digunakan, presisi ditentukan oleh argumen tambahan bertipe int. Jika nilai argumen ini negatif, argumen ini diabaikan. Jika tidak ada angka atau * yang digunakan, presisi dianggap nol. Lihat tabel di bawah untuk mengetahui efek presisi yang tepat.

Jadi jika kita mencoba kedua spesifikasi konversi tersebut

#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;
}

kami mendapatkan hasilnya:

|Hello wo|
|Hello wo|
|     Hello world|
|     Hello world|
Ondrej
sumber
12

Menurut saya kode di atas tidak benar tetapi (menurut uraian ini printf()) .*artinya

Lebar tidak ditentukan dalam format string, tetapi sebagai argumen nilai integer tambahan sebelum argumen yang harus diformat. '

Jadi ini adalah string dengan lebar yang bisa dilewati sebagai argumen.

memutarkan lagi
sumber
2
Saya telah menambahkan referensi silang URL sehingga Anda dapat menghindari tuduhan plagiarisme. Tentu saja, kutipan yang benar mengatakan " Presisinya bukan…" bukan " Lebarnya bukan…".
Jonathan Leffler
Seperti yang ditunjukkan @MattMcNabb, setiap referensi ke halaman tersebut harus menyoroti bahwa " nilai integer " adalah persis int( size_tatau bagiannya ) - bukan sembarang nilai integral seperti yang lebih intuitif atau kemungkinan aliasnya, seperti std::string::size_type. Ini bahkan lebih membingungkan, dengan mempertimbangkan bahwa halaman yang direferensikan menyebutkan size_tsebagai salah satu penentu jenis yang didukung.
Anton Samsonov