ทำไมเราถึงใช้:
1) cin.ignore
2) cin.clear
เหรอ?
เพียงแค่:
1) เพื่อละเว้น (แยกและทิ้ง) ค่าที่เราไม่ต้องการในสตรีม
2) เพื่อล้างสถานะภายในของสตรีม หลังจากใช้ cin.clear internal state ถูกตั้งค่าอีกครั้งกลับไปที่ goodbit ซึ่งหมายความว่าไม่มี 'ข้อผิดพลาด'
เวอร์ชันยาว:
หากมีบางสิ่งอยู่ใน 'สตรีม' (cin) จะต้องถูกนำมาจากที่นั่น โดย 'taken' เราหมายถึง 'used', 'removed', 'extract' จากสตรีม กระแสมีการไหล ข้อมูลไหลบน cin เหมือนน้ำในสตรีม คุณไม่สามารถหยุดการไหลของน้ำได้)
ดูตัวอย่าง:
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
จะเกิดอะไรขึ้นถ้าผู้ใช้ตอบ: "Arkadiusz Wlodarczyk" สำหรับคำถามแรก
เรียกใช้โปรแกรมเพื่อดูตัวคุณเอง
คุณจะเห็นบนคอนโซล "Arkadiusz" แต่โปรแกรมจะไม่ถาม "อายุ" จากคุณ มันจะเสร็จทันทีหลังจากพิมพ์ "Arkadiusz"
และ "Wlodarczyk" ไม่ปรากฏ ดูเหมือนว่ามันจะหายไป (?) *
เกิดอะไรขึ้น? ;-)
เนื่องจากมีช่องว่างระหว่าง "Arkadiusz" และ "Wlodarczyk".
อักขระ "ช่องว่าง" ระหว่างชื่อและนามสกุลเป็นสัญญาณสำหรับคอมพิวเตอร์ว่ามีตัวแปรสองตัวที่รอการแยกออกจากสตรีม "อินพุต"
คอมพิวเตอร์คิดว่าคุณกำลังคาดว่าจะส่งไปยังอินพุตมากกว่าหนึ่งตัวแปร เครื่องหมาย "เว้นวรรค" นั้นเป็นสัญญาณให้เขาตีความแบบนั้น
ดังนั้นคอมพิวเตอร์จึงกำหนด "Arkadiusz" เป็น "name" (2) และเนื่องจากคุณใส่มากกว่าหนึ่งสตริงในสตรีม (อินพุต) คอมพิวเตอร์จะพยายามกำหนดค่า "Wlodarczyk" ให้กับตัวแปร 'age' (!) ผู้ใช้จะไม่มีโอกาสใส่อะไรใน 'cin' ในบรรทัดที่ 6 เนื่องจากคำสั่งนั้นได้ดำเนินการไปแล้ว (!) ทำไม? เพราะยังมีบางอย่างเหลืออยู่ในสตรีม และอย่างที่บอกไปก่อนหน้านี้สตรีมอยู่ในกระแสดังนั้นทุกอย่างจะต้องถูกลบออกโดยเร็วที่สุด และความเป็นไปได้เกิดขึ้นเมื่อคอมพิวเตอร์เห็นคำสั่งอายุ >>
คอมพิวเตอร์ไม่รู้ว่าคุณสร้างตัวแปรที่เก็บอายุของใครบางคน (บรรทัดที่ 4) "อายุ" เป็นเพียงป้ายกำกับ สำหรับ 'อายุ' ของคอมพิวเตอร์สามารถเรียกได้เช่นกันว่า 'afsfasgfsagasggas' และจะเหมือนกัน สำหรับเขามันเป็นเพียงตัวแปรที่เขาจะพยายามกำหนด "Wlodarczyk" ให้เพราะคุณสั่ง / สั่งให้คอมพิวเตอร์ทำในบรรทัดที่ (6)
มันผิดที่จะทำ แต่เดี๋ยวก่อนคุณเป็นคนทำ! มันเป็นความผิดของคุณ! อาจเป็นผู้ใช้ แต่ก็ยัง ...
เอาล่ะ แต่จะแก้ไขอย่างไร?!
มาลองเล่นกับตัวอย่างนั้นสักเล็กน้อยก่อนที่เราจะแก้ไขอย่างเหมาะสมเพื่อเรียนรู้สิ่งที่น่าสนใจเพิ่มเติม :-)
ฉันชอบที่จะหาแนวทางที่เราเข้าใจสิ่งต่างๆ แก้ไขบางอย่างโดยที่เราไม่รู้ว่ามันไม่ให้ความพึงพอใจได้อย่างไร? :)
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate();
หลังจากเรียกใช้โค้ดด้านบนคุณจะสังเกตเห็นว่าสถานะของสตรีม (cin) ของคุณมีค่าเท่ากับ 4 (บรรทัดที่ 7) ซึ่งหมายความว่าสถานะภายในจะไม่เท่ากับ goodbit อีกต่อไป มีบางอย่างเกิดความสับสน มันค่อนข้างชัดเจนใช่มั้ย? คุณพยายามกำหนดค่าประเภทสตริง ("Wlodarczyk") ให้กับตัวแปรประเภท int 'age' ประเภทไม่ตรงกัน ถึงเวลาแจ้งว่ามีบางอย่างผิดปกติ และคอมพิวเตอร์ทำได้โดยการเปลี่ยนสถานะภายในของสตรีม มันเหมือนกับ: "คุณ f **** ขึ้นมาโปรดแก้ไขฉันด้วยฉันแจ้งให้คุณทราบ 'กรุณา' ;-)"
คุณไม่สามารถใช้ 'cin' (สตรีม) ได้อีกต่อไป มันติด. เช่นถ้าคุณวางท่อนไม้ขนาดใหญ่บนลำธารน้ำ คุณต้องแก้ไขก่อนจึงจะใช้งานได้ ไม่สามารถรับข้อมูล (น้ำ) จากสตรีม (cin) ได้อีกต่อไปเนื่องจากบันทึกของไม้ (สถานะภายใน) ไม่อนุญาตให้คุณทำเช่นนั้น
อ้อถ้ามีสิ่งกีดขวาง (ท่อนไม้) เราก็เอามันออกโดยใช้เครื่องมือที่ทำขึ้นมาได้ไหม?
ใช่
สถานะภายในของ cin ตั้งค่าเป็น 4 เหมือนสัญญาณเตือนที่ส่งเสียงโหยหวนและส่งเสียงดัง
cin.clear ล้างสถานะกลับสู่ปกติ (goodbit) เหมือนกับว่าคุณมาแล้วปิดเสียงปลุก คุณเพียงแค่ถอดมันออก คุณรู้ว่ามีบางอย่างเกิดขึ้นดังนั้นคุณจึงพูดว่า: "ไม่เป็นไรถ้าจะหยุดส่งเสียงฉันรู้ว่ามีบางอย่างผิดปกติแล้วก็หุบปากซะ"
เอาล่ะมาทำ! มาใช้ cin.clear () กัน
เรียกใช้โค้ดด้านล่างโดยใช้ "Arkadiusz Wlodarczyk" เป็นอินพุตแรก:
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;
cin.clear();
cout << cin.rdstate()<< endl;
เราสามารถเห็นได้อย่างแน่นอนหลังจากรันโค้ดด้านบนว่าสถานะเท่ากับ goodbit
ดีมากเพื่อให้ปัญหาได้รับการแก้ไข?
เรียกใช้โค้ดด้านล่างโดยใช้ "Arkadiusz Wlodarczyk" เป็นอินพุตแรก:
string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;;
cin.clear();
cout << cin.rdstate() << endl;
cin >> age;
แม้ว่าสถานะจะถูกตั้งค่าเป็น goodbit หลังจากบรรทัดที่ 9 ผู้ใช้จะไม่ถูกถามถึง "อายุ" โปรแกรมจะหยุด
ทำไม?!
โอ้มนุษย์ ... คุณเพิ่งดับสัญญาณเตือนแล้วท่อนไม้ในน้ำล่ะ * กลับไปที่ข้อความที่เราพูดถึง "Wlodarczyk" ว่ามันหายไปได้อย่างไร
คุณต้องนำไม้ "Wlodarczyk" ออกจากลำธาร การปิดนาฬิกาปลุกไม่ช่วยแก้ปัญหา แต่อย่างใด คุณแค่ปิดเสียงและคุณคิดว่าปัญหาจะหมดไป? ;)
ถึงเวลาแล้วสำหรับเครื่องมืออื่น:
cin.ignore เปรียบได้กับรถบรรทุกพิเศษที่มีเชือกที่มาและเอาท่อนไม้ที่มีสตรีมติดอยู่ เป็นการเคลียร์ปัญหาที่ผู้ใช้โปรแกรมของคุณสร้างขึ้น
เราจะใช้มันก่อนที่เสียงปลุกจะดับลงได้ไหม?
ใช่:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n');
int age;
cout << "Give me your age:" << endl;
cin >> age;
"Wlodarczyk" จะถูกลบออกก่อนที่จะส่งเสียงดังในบรรทัดที่ 7
10,000 และ "\ n" คืออะไร
มันบอกว่าลบ 10,000 อักขระ (ในกรณี) จนกว่าจะพบ "\ n" (ENTER) BTW สามารถทำได้ดีกว่าโดยใช้ numeric_limits แต่ไม่ใช่หัวข้อของคำตอบนี้
สาเหตุหลักของปัญหาจึงหมดไปก่อนที่จะเกิดเสียงดัง ...
ทำไมเราต้อง 'ชัดเจน'?
จะเป็นอย่างไรหากมีคนถามคำถาม "ให้อายุของคุณ" ในบรรทัดที่ 6 เช่น "อายุยี่สิบปี" แทนที่จะเขียน 20
ประเภทไม่ตรงกันอีก คอมพิวเตอร์พยายามกำหนดสตริงให้กับ int และสัญญาณเตือนจะเริ่มขึ้น คุณไม่มีโอกาสแม้แต่จะตอบสนองต่อสถานการณ์เช่นนั้น cin.ignore จะไม่ช่วยคุณในกรณีเช่นนั้น
ดังนั้นเราต้องใช้ clear ในกรณีเช่นนั้น:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n');
int age;
cout << "Give me your age:" << endl;
cin >> age;
cin.clear();
cin.ignore(10000, '\n');
แต่คุณควรล้างสถานะ 'ในกรณี' หรือไม่?
ไม่แน่นอน
หากมีสิ่งผิดปกติ (cin >> age;) คำแนะนำจะแจ้งให้คุณทราบโดยส่งคืนเท็จ
ดังนั้นเราจึงสามารถใช้คำสั่งเงื่อนไขเพื่อตรวจสอบว่าผู้ใช้ใส่ผิดประเภทในสตรีมหรือไม่
int age;
if (cin >> age)
cout << "You put integer";
else
cout << "You bad boy! it was supposed to be int";
เอาล่ะเราสามารถแก้ไขปัญหาเริ่มต้นของเราได้เช่น:
string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n');
int age;
cout << "Give me your age:" << endl;
if (cin >> age)
cout << "Your age is equal to:" << endl;
else
{
cin.clear();
cin.ignore(10000, '\n');
cout << "Give me your age name as string I dare you";
cin >> age;
}
แน่นอนว่าสิ่งนี้สามารถปรับปรุงได้โดยตัวอย่างเช่นการทำสิ่งที่คุณมีปัญหาโดยใช้ loop while
โบนัส:
คุณอาจจะสงสัย แล้วถ้าฉันอยากได้ชื่อและนามสกุลในบรรทัดเดียวกันจากผู้ใช้ล่ะ? เป็นไปได้ไหมที่จะใช้ cin ถ้า cin ตีความแต่ละค่าที่คั่นด้วย "space" เป็นตัวแปรต่างกัน
แน่นอนว่าคุณทำได้สองวิธี:
1)
string name, surname;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin >> surname;
cout << "Hello, " << name << " " << surname << endl;
2) หรือโดยใช้ฟังก์ชัน getline
getline(cin, nameOfStringVariable);
และนั่นคือวิธีการ:
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
ตัวเลือกที่สองอาจย้อนกลับคุณในกรณีที่คุณใช้หลังจากที่คุณใช้ 'cin' ก่อนหน้า getline
มาดูกันเลย:
ก)
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endl;
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
หากคุณใส่ "20" ตามอายุคุณจะไม่ถูกถามถึงชื่อและนามสกุล
แต่ถ้าคุณทำอย่างนั้น:
ข)
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endll
ทุกอย่างปกติดี.
อะไร?!
ทุกครั้งที่คุณใส่บางสิ่งลงในอินพุต (สตรีม) คุณจะปล่อยให้อักขระสีขาวสิ้นสุดซึ่งก็คือ ENTER ('\ n') คุณต้องป้อนค่าลงในคอนโซล ดังนั้นจะต้องเกิดขึ้นหากข้อมูลมาจากผู้ใช้
b) ลักษณะของ cin คือการละเว้นช่องว่างดังนั้นเมื่อคุณอ่านข้อมูลจาก cin อักขระขึ้นบรรทัดใหม่ '\ n' จะไม่สำคัญ มันถูกละเลย
ก) ฟังก์ชัน getline ทำให้บรรทัดทั้งหมดขึ้นบรรทัดใหม่ ('\ n') และเมื่อถ่านขึ้นบรรทัดใหม่เป็นสิ่งแรกที่ฟังก์ชัน getline จะได้รับ '\ n' และนั่นคือทั้งหมดที่จะได้รับ คุณแยกอักขระขึ้นบรรทัดใหม่ที่เหลือในสตรีมโดยผู้ใช้ที่ใส่ "20" ในสตรีมในบรรทัดที่ 3
ดังนั้นในการแก้ไขก็คือต้องเรียก cin.ignore (); ทุกครั้งที่คุณใช้ cin เพื่อรับค่าใด ๆ หากคุณจะใช้ getline () ในโปรแกรมของคุณ
ดังนั้นรหัสที่ถูกต้องจะเป็น:
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cin.ignore();
cout << "Your age is" << age << endl;
string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);
cout << "Hello, " << nameAndSurname << endl;
ฉันหวังว่าสตรีมจะชัดเจนมากขึ้นสำหรับคุณที่รู้
ได้โปรดปิดปากเงียบ! :-)