scanf () ออกจากอักขระบรรทัดใหม่ในบัฟเฟอร์


93

ฉันมีโปรแกรมต่อไปนี้:

ตามที่ฉันอ่านในหนังสือ C ผู้เขียนบอกว่าscanf()ทิ้งอักขระบรรทัดใหม่ไว้ในบัฟเฟอร์ดังนั้นโปรแกรมจึงไม่หยุดที่บรรทัดที่ 4 เพื่อให้ผู้ใช้ป้อนข้อมูล แต่จะเก็บอักขระบรรทัดใหม่ใน c2 และย้ายไปที่ บรรทัดที่ 5.

นั่นถูกต้องใช่ไหม?

อย่างไรก็ตามสิ่งนี้เกิดขึ้นเฉพาะกับcharประเภทข้อมูลหรือไม่ เพราะฉันไม่พบปัญหานี้กับintชนิดข้อมูลในบรรทัดที่ 1, 2, 3 ใช่หรือไม่


บางครั้งมีการแนะนำว่าfflush(stdin)สามารถใช้ก่อนการเรียกใช้scanf()สำหรับอักขระเดี่ยว โปรดอ่านการใช้fflush(stdin)เพื่ออภิปรายข้อดีข้อเสียและทางเลือกอื่น ๆ ของวิธีการนั้น (ซึ่งใช้ได้ผลไม่มากก็น้อยบน Windows และใช้ไม่ได้กับที่อื่น ๆ ส่วนใหญ่)
Jonathan Leffler

โปรดแจ้งให้เราทราบว่าคุณกำลังอ้างอิงถึงหนังสือเล่มใด
surya kiran

คำตอบ:


82

scanf()ข้ามช่องว่างฟังก์ชั่นที่นำโดยอัตโนมัติก่อนที่จะพยายามแปลงแยกอื่น ๆ นอกเหนือจากตัวอักษร รูปแบบอักขระ (โดยหลัก%cคือชุดสแกน%[…]- และ%n) เป็นข้อยกเว้น พวกเขาไม่ข้ามช่องว่าง

ใช้" %c"กับช่องว่างนำหน้าเพื่อข้ามช่องว่างเพิ่มเติม อย่าใช้ช่องว่างต่อท้ายในscanf()สตริงรูปแบบ

โปรดทราบว่าสิ่งนี้ยังไม่ใช้ช่องว่างต่อท้ายใด ๆ ที่เหลืออยู่ในสตรีมอินพุตไม่ถึงจุดสิ้นสุดของบรรทัดดังนั้นโปรดระวังสิ่งนั้นหากใช้getchar()หรือfgets()ในอินพุตสตรีมเดียวกัน เราเพิ่งได้รับ scanf เพื่อข้ามช่องว่างก่อนการแปลงเช่นเดียวกับการแปลงที่%dไม่ใช่อักขระอื่น ๆ


โปรดทราบว่า "คำสั่ง" ที่ไม่ใช่ช่องว่าง (เพื่อใช้คำศัพท์ POSIX scanf ) นอกเหนือจากการแปลงเช่นข้อความตามตัวอักษรในscanf("order = %d", &order);จะไม่ข้ามช่องว่างเช่นกัน ลิเทอรัลorderต้องตรงกับอักขระถัดไปที่จะอ่าน

ดังนั้นคุณอาจต้องการที่" order = %d"นั่นหากคุณต้องการข้ามขึ้นบรรทัดใหม่จากบรรทัดก่อนหน้า แต่ยังต้องการการจับคู่ตามตัวอักษรบนสตริงคงที่เช่นคำถามนี้


9
%c, %n, %[]มี 3 ความคาดหวังที่ระบุว่าไม่กินช่องว่างชั้นนำ
chux - คืนสถานะ Monica

@chux ดังนั้นในกรณีอื่น scanf จะล้างช่องว่างทั้งหมดก่อนหน้านี้ในบัฟเฟอร์หรือเพิกเฉยต่อการป้อนข้อมูล แต่ยังอยู่ที่นั่น?
Suraj Jain


3
ดูต่อท้ายว่างในscanf()สตริงรูปแบบและscanf()ขออินพุตสองครั้งในขณะที่ฉันคาดว่าจะถามเพียงครั้งเดียวสำหรับการอภิปรายเกี่ยวกับช่องว่างต่อท้ายในสตริงรูปแบบ เป็นความคิดที่ไม่ดี - แย่มากหากคุณคาดหวังว่าจะมีปฏิสัมพันธ์กับมนุษย์และไม่ดีต่อการโต้ตอบในโปรแกรม
Jonathan Leffler


8

อีกตัวเลือกหนึ่ง (ที่ผมได้จากที่นี่ ) คือการอ่านและยกเลิกการขึ้นบรรทัดใหม่โดยใช้ตัวเลือกที่ได้รับมอบหมาย-ปราบปราม ในการทำเช่นนั้นเราเพียงแค่ใส่รูปแบบเพื่ออ่านอักขระที่มีเครื่องหมายดอกจันอยู่ระหว่าง%และc:

scanf จากนั้นจะอ่านอักขระถัดไป (นั่นคือขึ้นบรรทัดใหม่) แต่จะไม่กำหนดให้กับตัวชี้ใด ๆ

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

หรือขึ้นอยู่กับความต้องการของคุณคุณอาจลืม scanf () / getchar () ใช้ fgets () เพื่อรับบรรทัดข้อความจากผู้ใช้และแยกวิเคราะห์ด้วยตัวเอง


3
ปัญหาเกี่ยวกับเทคนิคนี้คือถ้าผู้ใช้พิมพ์aเว้นวรรคแล้วขึ้นบรรทัดใหม่การแปลงอักขระที่ถูกระงับจะอ่านช่องว่างและยังคงออกจากบรรทัดใหม่ หากผู้ใช้พิมพ์ตามที่supercalifragilisticexpialidociousคุณคาดหวังaคุณจะมีตัวละครพิเศษมากมายให้จัดการ คุณไม่สามารถบอกได้ว่าต่อท้ายปราบปรามการแปลงประสบความสำเร็จอย่างใดอย่างหนึ่ง - scanf()พวกเขาไม่ได้นับรวมอยู่ในผลตอบแทนจาก
Jonathan Leffler

4

การใช้งานก่อนที่จะเรียกสอง getchar()scanf()


1
วิธีนี้ใช้ได้ผลโดยที่ผู้ใช้ไม่ได้พิมพ์อย่างอื่นเช่น แต่มันไม่ดีเท่าลูปที่สแกนไปยังบรรทัดใหม่ถัดไป: int c; while ((c = getchar()) != EOF && c != '\n') ;(เขียนเกินสามบรรทัดเมื่อไม่อยู่ในความคิดเห็น) มักจะเพียงพอ มันไม่สามารถเข้าใจผิดได้ (และคุณต้องจำไว้ว่าคนโง่ฉลาดมากในการทำสิ่งต่างๆล้มเหลว)
Jonathan Leffler
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.