ใช้ printf กับสตริงที่สิ้นสุดที่ไม่ใช่ค่าว่าง


108

สมมติว่าคุณมีสตริงที่ไม่nullถูกยกเลิกและคุณรู้ขนาดที่แน่นอนแล้วคุณจะพิมพ์สตริงนั้นด้วยprintfภาษา C ได้อย่างไร? ฉันจำวิธีการดังกล่าวได้ แต่ตอนนี้หาคำตอบไม่ได้ ...


9
ในCบริบทสตริงทั้งหมดจะสิ้นสุดด้วยค่าว่าง อาร์เรย์ของถ่านที่ไม่มีโมฆะไม่ใช่สตริง ... เป็นอาร์เรย์ของถ่าน :)
pmg


คำตอบ:


176

มีความเป็นไปได้กับ printf มันจะเป็นดังนี้:

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

ไม่จำเป็นต้องคัดลอกอะไรไม่จำเป็นต้องแก้ไขสตริงหรือบัฟเฟอร์ต้นฉบับ


10
แต่อย่างไรก็ตามมันอันตรายสักวันใครสักคนจะพิมพ์สตริงนี้ด้วย% s
pmod

6
@Pmod: ไม่จำเป็นถ้าบัฟเฟอร์ไม่ได้สัมผัสกับโลกภายนอก นอกจากนี้ยังมีประโยชน์มากในการพิมพ์เพียงบางส่วนของสตริง (ซึ่งอาจถูกยกเลิกด้วยค่าว่าง) หากคุณต้องการเห็นสิ่งนี้จริงให้ดูที่พร็อกซี OpenSER / Kamailio SIP ที่พวกเขาหลีกเลี่ยงการคัดลอกสิ่งต่างๆเนื่องจากเทคนิคนี้เป็นจำนวนมาก (ใช้ sprintf ด้วย)
DarkDust

6
อีก +1 ฉันชอบเวลาที่ฉันได้เรียนรู้สิ่งต่างๆเกี่ยวกับสิ่งพื้นฐานเช่นprintfแม้จะผ่านไป ~ ทศวรรษ ... :)
Hertzel Guinness

1
สำหรับฉันมันมีประโยชน์มากเมื่อฉันได้รับสตริงที่สิ้นสุดที่ไม่ใช่ null จาก API (API ของ windows บางตัวทำสิ่งนี้!) และต้องส่งคืนด้วยวิธีที่ 'สมเหตุสมผล' ดังนั้น: อายุการใช้งานยาวนานถึง% * s (หรือ%. * S ซึ่งจะทำให้การแปลง UNICODE <-> SINGLE-BYTE สำหรับคุณ!;))
FrizzTheSnail

3
@ user1424739: ในกรณีของคุณprintfจะพิมพ์ได้สูงสุด 11 ตัวอักษรหรือจนกว่าจะพบ NULL แล้วแต่ว่ากรณีใดจะเกิดขึ้นก่อน ในตัวอย่างของคุณ NULL มาก่อน ระบุความยาวสูงสุดไม่ได้ทำให้เป็นโมฆะสูญเสีย "สิ้นสุดของสตริง" printfมันมีความหมายสำหรับ
DarkDust

31

นี่คือคำอธิบายวิธีการ%.*sทำงานและตำแหน่งที่ระบุ

ข้อกำหนดการแปลงในสตริงเทมเพลต printf มีรูปแบบทั่วไป:

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

หรือ

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

รูปแบบที่สองคือการรับความแม่นยำจากรายการอาร์กิวเมนต์:

คุณยังสามารถระบุความแม่นยำของ "*" ซึ่งหมายความว่าอาร์กิวเมนต์ถัดไปในรายการอาร์กิวเมนต์ (ก่อนค่าจริงที่จะพิมพ์) ถูกใช้เป็นค่าความแม่นยำ ค่าต้องเป็น int และจะถูกละเว้นหากเป็นลบ

ไวยากรณ์การแปลงเอาต์พุตในคู่มือ glibc

สำหรับการ%sจัดรูปแบบสตริงความแม่นยำมีความหมายพิเศษ:

สามารถระบุความแม่นยำเพื่อระบุจำนวนอักขระสูงสุดที่จะเขียน มิฉะนั้นอักขระในสตริงสูงสุด แต่ไม่รวมอักขระ null ที่สิ้นสุดจะถูกเขียนไปยังสตรีมเอาต์พุต

การแปลงเอาต์พุตอื่น ๆในคู่มือ glibc

ตัวแปรที่มีประโยชน์อื่น ๆ :

  • "%*.*s", maxlen, maxlen, val จะจัดชิดขวาแทรกช่องว่างก่อน
  • "%-*.*s", maxlen, maxlen, val จะจัดชิดซ้าย

ถ้าฉันเข้าใจถูกต้องสิ่งต่อไปนี้จะเพิ่มผลลัพธ์ แต่ยังคงป้องกันไม่ให้สตริงล้น? "%-*.*s", padding, str_view.size(), str_view.data()
scx

20

คุณสามารถใช้ fwrite () เพื่อ stdout!

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

ด้วยวิธีนี้คุณจะส่งออกตัวอักษรแรก (ตัวเลขที่กำหนดในตัวแปร number_of_chars) ไปยังไฟล์ในกรณีนี้เป็น stdout (เอาต์พุตมาตรฐานหน้าจอของคุณ)!


2
มีประโยชน์มากเมื่อคุณต้องการตรวจสอบบัฟเฟอร์แบบยาวที่มีสตริงและศูนย์!
Elist

13

printf("%.*s", length, string) จะไม่ทำงาน.

ซึ่งหมายถึงการพิมพ์ไบต์ความยาวสูงสุดหรือไบต์ว่างแล้วแต่ว่าอะไรจะเกิดขึ้นก่อน หากอาร์เรย์ของชาร์ที่ไม่สิ้นสุดที่ไม่มีค่าว่างของคุณมีไบต์ว่างก่อนความยาว printf จะหยุดที่สิ่งเหล่านั้นและไม่ดำเนินการต่อ


4
และนี่คือคำตอบสำหรับคำถามของ OP อย่างไร?
Shahbaz

12
หากไม่สิ้นสุดด้วยค่า null ดังนั้น null เป็นอักขระที่ถูกต้องสำหรับสตริงที่จะมี สิ่งนี้ยังคงคิดว่าอาร์เรย์นั้นถูกยกเลิกด้วย null มันก็ถือว่าเป็นอาร์เรย์ที่ยาวขึ้นซึ่งมีการเลือกย่อยซึ่งหมายความว่าหากคุณมีสตริงที่มี null อยู่สิ่งนี้จะทำให้เกิดปัญหา
lahwran


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

ฉันแก้ไขรหัสนี่เป็นอีกวิธีหนึ่ง:

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

}

ประสิทธิภาพแย่มากเนื่องจากมีการอ่านไบต์ที่ไม่จำเป็นจำนวนมาก (ซึ่งมาพร้อมกับการลงโทษด้านประสิทธิภาพหากไบต์ไม่ได้อยู่ในแอดเดรสที่จัดแนวคำในซีพียูส่วนใหญ่) และยังมีการจัดรูปแบบการแยกวิเคราะห์และการใช้สำหรับอักขระแต่ละตัว อย่าทำอย่างนั้น :-) ดูคำตอบของฉันสำหรับวิธีแก้ปัญหา
DarkDust

@DarkDust: มีเพียงเครื่องจักรทางพยาธิวิทยาเท่านั้นที่จะลงโทษไบต์ที่อ่านไม่สอดคล้องกับขอบเขตของคำ คุณกำลังคิดถึงคำที่อ่านไม่ตรงกับขอบเขตของคำใช่หรือไม่? หรือ mips โบราณบางอย่างหรืออะไร?
R .. GitHub STOP HELPING ICE

@R .. : ถ้าคุณพิจารณา x86 สมองเสียหายและล้าสมัยฉันเห็นด้วยอย่างยิ่ง เนื่องจาก x86 มีโทษสำหรับการอ่านและเขียนหน่วยความจำที่ไม่ใช่คำ ARM ก็เช่นกัน ดูตัวอย่างคำถามนี้หรือคำถามนี้ สิ่งนี้คือ (ถ้าฉันเข้าใจถูกต้อง) ข้อมูลนั้นถูกดึงมาเป็นชิ้นขนาดคำจากหน่วยความจำและการได้รับไบต์ที่ถูกต้องคือไมโครออปอื่น ไม่ใช่เรื่องใหญ่ แต่ในวงกว้างมันอาจสร้างความแตกต่างได้
DarkDust

@DarkDust: คุณคิดผิดอย่างสิ้นเชิงเกี่ยวกับเรื่องนี้สำหรับการอ่านไบต์ ทำไมคุณไม่ไปทำเกณฑ์มาตรฐาน? x86 มีการดำเนินการไบต์อะตอมอย่างสมบูรณ์และมักจะมี. มันไม่ดึงชิ้นส่วนขนาดคำ (ยกเว้นที่ระดับแคชซึ่งดึงชิ้นส่วนที่ใหญ่กว่ามากและการจัดตำแหน่งไม่เกี่ยวข้อง แต่ฉันกำลังพูดถึงข้อมูลที่แคชไว้แล้ว)
R .. GitHub STOP HELPING ICE

@DarkDust: PS3 ไม่รองรับการอ่านหรือเขียนไบต์ที่ไม่ตรงแนวบน SPU ในความเป็นจริงมันไม่รองรับประเภทสเกลาร์ด้วยซ้ำมีเพียงเวกเตอร์ที่ต้องจัดแนว คอมไพเลอร์เลียนแบบพวกเขา และโปรเซสเซอร์ ARM จำนวนมากไม่รองรับการอ่านหรือเขียนแบบไบต์ แต่ดำเนินการอ่านหรือเขียนคำเท่านั้น
Sylvain Defresne
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.