Menggunakan printf dengan string diakhiri non-null

107

Misalkan Anda memiliki string yang TIDAK nulldiakhiri dan Anda tahu ukuran pastinya, jadi bagaimana Anda bisa mencetak string itu dengan printfdalam C? Saya ingat metode seperti itu tetapi saya tidak dapat mengetahuinya sekarang ...

whoi
sumber
9
Dalam Ckonteks, semua string diakhiri null. Array char tanpa null di dalamnya bukanlah string ... mereka adalah array char :)
pmg
stackoverflow.com/questions/2239519/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Jawaban:

174

Ada kemungkinan dengan printf, seperti ini:

printf("%.*s", stringLength, pointerToString);

Tidak perlu menyalin apa pun, tidak perlu mengubah string atau buffer asli.

DarkDust
sumber
10
Tapi bagaimanapun itu berbahaya, seseorang suatu hari nanti akan
mencetak
6
@Pmod: Belum tentu jika buffer tidak diekspos ke dunia luar. Ini juga sangat berguna untuk hanya mencetak bagian dari string (yang mungkin diakhiri null, tentu saja). Jika Anda benar-benar ingin melihat ini beraksi, lihat proxy SIP OpenSER / Kamailio di mana mereka menghindari penyalinan barang karena teknik ini banyak (juga menggunakan sprintf).
DarkDust
6
+1 lainnya. Saya suka ketika saya mempelajari hal-hal dasar seperti printfbahkan setelah ~ dekade ... :)
Hertzel Guinness
1
Bagi saya ini sangat berguna ketika saya menerima string yang diakhiri non-null dari API (beberapa API windows melakukan ini!) Dan harus mengembalikannya dengan cara yang 'masuk akal'. Jadi: umur panjang hingga%. * S (atau%. * S yang juga akan membuat konversi UNICODE <-> SINGLE-BYTE untuk Anda
!;
3
@ user1424739: Dalam kasus Anda printfakan mencetak hingga 11 karakter atau sampai menemukan NULL, mana saja yang lebih dulu; dalam contoh Anda, NULL lebih dulu. Menentukan panjang maksimum tidak membuat NULL kehilangan arti "end-of-string" -nya printf.
DarkDust
29

Berikut adalah penjelasan tentang cara %.*skerjanya, dan di mana ditentukan.

Spesifikasi konversi dalam string template printf memiliki bentuk umum:

% [ param-no $] flags width [ . precision ] type conversion

atau

% [ param-no $] flags width . * [ param-no $] type conversion

Bentuk kedua adalah untuk mendapatkan ketepatan dari daftar argumen:

Anda juga dapat menentukan presisi '*'. Ini berarti bahwa argumen berikutnya dalam daftar argumen (sebelum nilai aktual dicetak) digunakan sebagai presisi. Nilainya harus berupa int, dan diabaikan jika negatif.

Output sintaks konversi di manual glibc

Untuk %spemformatan string, presisi memiliki arti khusus:

Presisi dapat ditentukan untuk menunjukkan jumlah karakter maksimum untuk ditulis; jika tidak, karakter dalam string hingga tetapi tidak termasuk karakter null yang mengakhiri ditulis ke aliran keluaran.

Konversi keluaran lainnya di manual glibc

Varian bermanfaat lainnya:

  • "%*.*s", maxlen, maxlen, val akan membenarkan, menyisipkan spasi sebelumnya;
  • "%-*.*s", maxlen, maxlen, val akan membenarkan kiri.
Tobu
sumber
Jika saya mengerti dengan benar, berikut ini akan pad output namun masih mencegah string overflow? "%-*.*s", padding, str_view.size(), str_view.data()
scx
20

Anda dapat menggunakan fwrite () untuk stdout!

fwrite(your_string, sizeof(char), number_of_chars, stdout);

Dengan cara ini Anda akan menampilkan karakter pertama (angka ditentukan dalam variabel number_of_chars) ke file, dalam hal ini ke stdout (output standar, layar Anda)!

Pedro Sousa
sumber
2
Sangat membantu ketika Anda ingin memeriksa buffer panjang yang berisi string dan nol!
Elist
13

printf("%.*s", length, string) tidak akan berfungsi.

Ini berarti mencetak HINGGA byte panjang ATAU byte nol, mana saja yang lebih dulu. Jika array-of-char non-null-terminated Anda berisi byte null SEBELUM panjangnya, printf akan menghentikannya, dan tidak melanjutkan.

Todd Freed
sumber
4
Dan bagaimana ini merupakan jawaban atas pertanyaan OP?
Shahbaz
12
jika tidak diakhiri null, maka null adalah karakter yang valid untuk memuat string. ini masih menganggap array itu dihentikan null, itu hanya memperlakukannya sebagai array yang lebih panjang dari sub-pemilihannya - yang berarti bahwa jika Anda memiliki string dengan null di dalamnya, ini akan menimbulkan masalah.
lahwran
3
printf("%.5s", pointerToNonNullTerminatedString);

Panjang senar akan menjadi 5.

codeDom
sumber
1
#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]);
 }
 return 0;
}

Saya mengedit kodenya, dengan cara lain:

#include<stdio.h>
int main()
{
printf ("%.5s","fahaduddin");/*if 5 is the number of bytes to be printed and fahaduddin is the string.*/

return 0;

}
fuddin
sumber
Kinerja yang sangat buruk karena banyak pembacaan byte yang tidak perlu (yang disertai dengan penalti kinerja jika byte tidak berada pada alamat yang selaras dengan kata di sebagian besar CPU) dan juga penguraian dan penerapan pemformatan dilakukan untuk setiap karakter. Jangan lakukan itu :-) Lihat jawaban saya untuk solusinya.
DarkDust
@DarkDust: hanya mesin patologis yang akan menghukum pembacaan byte tidak selaras dengan batas kata. Apakah Anda berpikir tentang pembacaan kata yang tidak sesuai dengan batasan kata? Atau semacam sampah kuno atau semacamnya?
R .. GitHub STOP HELPING ICE
@R ..: Jika Anda menganggap x86 rusak otak dan ketinggalan zaman, saya sangat setuju. Karena x86 memang memiliki penalti untuk membaca dan menulis memori non-word aligned. Begitu pula ARM. Lihat misalnya pertanyaan ini atau pertanyaan ini . Masalahnya adalah (jika saya memahaminya dengan benar) bahwa data diambil dalam potongan ukuran kata dari memori dan mendapatkan byte yang benar adalah operasi mikro lain. Bukan masalah besar, tetapi dalam lingkaran besar itu mungkin membuat perbedaan.
DarkDust
@DarkDust: Anda sepenuhnya salah tentang itu untuk pembacaan byte. Mengapa Anda tidak pergi melakukan benchmark? x86 memiliki operasi byte atom sepenuhnya dan selalu memiliki. Itu tidak mengambil potongan ukuran kata (kecuali pada tingkat cache, yang mengambil potongan yang jauh lebih besar dan penyelarasan tidak relevan, tapi saya berbicara tentang data yang sudah di-cache).
R .. GitHub STOP HELPING ICE
@DarkDust: PS3 tidak mendukung pembacaan atau penulisan byte yang tidak selaras pada SPU. Bahkan tidak mendukung jenis scalar, hanya ada vektor yang harus disejajarkan. Kompilator meniru mereka. Dan banyak prosesor ARM tidak mendukung baca atau tulis byte, tetapi hanya melakukan baca atau tulis kata.
Sylvain Defresne