scanf () meninggalkan karakter baris baru di buffer

92

Saya memiliki program berikut:

Seperti yang saya baca di buku C, penulis mengatakan bahwa scanf()meninggalkan karakter baris baru di buffer, oleh karena itu, program tidak berhenti di baris 4 bagi pengguna untuk memasukkan data, melainkan menyimpan karakter baris baru di c2 dan berpindah ke baris 5.

Apakah itu benar?

Namun, apakah ini hanya terjadi dengan chartipe data? Karena saya tidak melihat masalah ini dengan inttipe data seperti pada baris 1, 2, 3. Apakah benar?

ipkiss
sumber
Kadang-kadang disarankan agar fflush(stdin)dapat digunakan sebelum panggilan ke scanf()untuk satu karakter. Harap baca Menggunakanfflush(stdin) untuk diskusi tentang pro dan kontra serta alternatif metode tersebut (yang bekerja, kurang lebih, pada Windows, dan tidak berfungsi di sebagian besar tempat lain).
Jonathan Leffler
Bisakah Anda memberi tahu kami buku mana yang Anda maksud.?
surya kiran

Jawaban:

81

The scanf()melompat fungsi spasi terkemuka otomatis sebelum mencoba untuk mengurai konversi selain karakter. Format karakter (terutama %c; juga set scan %[…]- dan %n) adalah pengecualian; mereka tidak melewatkan spasi.

Gunakan " %c"dengan awalan kosong untuk melewati spasi kosong opsional. Jangan gunakan tanda kosong dalam scanf()format string.

Perhatikan bahwa ini masih tidak mengkonsumsi spasi kosong tertinggal di aliran input, bahkan tidak sampai akhir baris, jadi berhati-hatilah jika juga menggunakan getchar()atau fgets()pada aliran input yang sama. Kami baru saja mendapatkan scanf untuk melewati spasi sebelum konversi, seperti yang dilakukannya untuk %ddan konversi non-karakter lainnya.


Perhatikan bahwa "perintah" non-spasi putih (untuk menggunakan terminologi scanf POSIX ) selain konversi, seperti teks literal dalam scanf("order = %d", &order);juga tidak melewatkan spasi. Literal orderharus cocok dengan karakter berikutnya untuk dibaca.

Jadi, Anda mungkin menginginkannya " order = %d"jika Anda ingin melewati baris baru dari baris sebelumnya tetapi masih membutuhkan pencocokan literal pada string tetap, seperti pertanyaan ini .

Jeremiah Willcock
sumber
9
%c, %n, %[]Adalah 3 harapan tertentu yang tidak mengkonsumsi spasi terkemuka.
chux
@chux Jadi Apakah dalam Kasus Lain, scanf membersihkan semua spasi putih sebelumnya di buffer atau mengabaikannya untuk masukan tetapi masih ada?
Suraj Jain
@SurajJain Ya,
chux
3
Lihat Trailing blank dalam scanf()format string dan scanf()meminta input dua kali sementara saya mengharapkannya untuk meminta hanya sekali untuk diskusi tentang trailing blank dalam string format. Itu adalah ide yang buruk - sangat buruk jika Anda mengharapkan interaksi manusia dan buruk untuk interaksi program.
Jonathan Leffler
32

Gunakan scanf(" %c", &c2);. Ini akan menyelesaikan masalah Anda.

Shweta
sumber
8

Opsi lain (yang saya dapatkan dari sini ) adalah membaca dan membuang baris baru dengan menggunakan opsi penugasan-supresi . Untuk melakukan itu, kami hanya menempatkan format untuk membaca karakter dengan tanda bintang di antara %dan c:

scanf kemudian akan membaca karakter berikutnya (yaitu, baris baru) tetapi tidak menugaskannya ke penunjuk mana pun.

Pada akhirnya, bagaimanapun, saya akan mendukung opsi terakhir FAQ :

Atau, bergantung pada kebutuhan Anda, Anda juga bisa melupakan scanf () / getchar (), gunakan fgets () untuk mendapatkan sebaris teks dari pengguna dan menguraikannya sendiri.

brandizzi
sumber
3
Masalah dengan teknik ini adalah jika pengguna mengetik aspasi lalu baris baru, konversi karakter yang disembunyikan membaca spasi dan masih meninggalkan baris baru. Jika pengguna mengetik sesuai supercalifragilisticexpialidociousharapan a, Anda memiliki banyak karakter tambahan yang harus ditangani. Anda juga tidak akan pernah tahu apakah konversi tambahan yang ditutup-tutupi berhasil - konversi tidak dihitung sebagai imbalan dari scanf().
Jonathan Leffler
4

Gunakan getchar()sebelum menelepon kedua scanf().

Jiwon
sumber
1
Ini berfungsi asalkan pengguna tidak mengetik apa pun - membuntuti kosong, misalnya. Tapi itu tidak sebaik loop yang memindai ke baris baru berikutnya: int c; while ((c = getchar()) != EOF && c != '\n') ;(ditulis lebih dari tiga baris jika tidak ada dalam komentar). Seringkali cukup; ini tidak mudah (dan Anda harus ingat bahwa orang bodoh sangat pandai dalam menghancurkan sesuatu).
Jonathan Leffler