[英]When and why do I need to use cin.ignore() in C++?
我用 C++ 編寫了一個非常基本的程序,它要求用戶輸入一個數字,然后輸入一個字符串。 令我驚訝的是,在運行程序時,它從未停止請求字符串。 它只是跳過了它。 在對 StackOverflow 進行了一些閱讀后,我發現我需要添加一行內容:
cin.ignore(256, '\n');
在獲取字符串輸入的行之前。 添加它解決了問題並使程序運行。 我的問題是為什么 C++ 需要這個cin.ignore()
行,我如何預測何時需要使用cin.ignore()
?
這是我寫的程序:
#include <iostream>
#include <string>
using namespace std;
int main()
{
double num;
string mystr;
cout << "Please enter a number: " << "\n";
cin >> num;
cout << "Your number is: " << num << "\n";
cin.ignore(256, '\n'); // Why do I need this line?
cout << "Please enter your name: \n";
getline (cin, mystr);
cout << "So your name is " << mystr << "?\n";
cout << "Have a nice day. \n";
}
忽略正是顧名思義。
它不會“丟棄”您不需要的東西,而是會忽略您在調用它時指定的字符數量,直到您指定為斷點的字符。
它適用於輸入和輸出緩沖區。
本質上,對於std::cin
語句,您在執行getline
調用之前使用 ignore ,因為當用戶使用std::cin
輸入某些內容時,他們按回車鍵並且'\\n'
字符進入cin
緩沖區。 然后,如果您使用getline
,它會獲取換行符而不是您想要的字符串。 所以你做了一個std::cin.ignore(1000,'\\n')
並且應該清除緩沖區直到你想要的字符串。 (將 1000 放在那里是為了在指定的斷點之前跳過特定數量的字符,在本例中為 \\n 換行符。)
你正在以錯誤的方式思考這個問題。 每次使用cin
或getline
時,您都在按邏輯步驟進行思考。 前任。 先問號碼,再問名字。 這是考慮cin
的錯誤方式。 因此,您遇到了競爭條件,因為您每次請求輸入時都假設流是暢通的。
如果您編寫程序純粹是為了輸入,您會發現問題:
void main(void)
{
double num;
string mystr;
cin >> num;
getline(cin, mystr);
cout << "num=" << num << ",mystr=\'" << mystr << "\'" << endl;
}
在上面,你在想,“先得到一個數字”。 所以你輸入123
按回車鍵,你的輸出將是num=123,mystr=''
。 這是為什么? 這是因為在流中您有123\\n
並且123
被解析為num
變量,而\\n
仍在流中。 默認情況下,讀取getline
函數的文檔它將在istream
查找,直到遇到\\n
。 在這個例子中,由於\\n
在流中,看起來它“跳過”了它,但它工作正常。
要使上述工作正常運行,您必須輸入123Hello World
才能正確輸出num=123,mystr='Hello World'
。 那,或者您在cin
和getline
之間放置一個cin.ignore
,以便它分解為您期望的邏輯步驟。
這就是您需要ignore
命令的原因。 因為您是以邏輯步驟而不是流形式考慮它,所以您遇到了競爭條件。
再舉一個學校常見的代碼示例:
void main(void)
{
int age;
string firstName;
string lastName;
cout << "First name: ";
cin >> firstName;
cout << "Last name: ";
cin >> lastName;
cout << "Age: ";
cin >> age;
cout << "Hello " << firstName << " " << lastName << "! You are " << age << " years old!" << endl;
}
以上似乎是合乎邏輯的步驟。 首先詢問名字,姓氏,然后是年齡。 因此,如果您輸入John
,然后輸入Doe
,然后輸入19
,則應用程序會在每個邏輯步驟中工作。 如果您在“流”中考慮它,您可以簡單地在“名字:”問題上輸入John Doe 19
,它也會起作用並且似乎跳過其余問題。 為了使上述內容按邏輯步驟工作,您需要ignore
問題中每個邏輯中斷的剩余流。
請記住將您的程序輸入視為從“流”中讀取而不是按邏輯步驟讀取。 每次調用cin
它都會從流中讀取。 如果用戶輸入錯誤,這將創建一個相當錯誤的應用程序。 例如,如果您輸入了一個需要cin >> double
的字符,應用程序將產生一個看似奇怪的輸出。
簡答
為什么? 因為輸入流中仍有空格(回車、制表符、空格、換行符)。
什么時候? 當您使用某些不獨立的函數時,會忽略前導空格。 Cin 默認會忽略並刪除前導空格,但 getline 不會自行忽略前導空格。
現在詳細解答。
您在控制台中輸入的所有內容都是從標准流 stdin 中讀取的。 當您輸入某些內容時,假設您的情況為 256 並按 Enter,流的內容將變為256\\n
。 現在 cin 選取 256 並將其從流中刪除, \\n
仍保留在流中。 現在,當您輸入您的姓名時,假設為Raddicus
,流的新內容是\\nRaddicus
。
現在問題來了。 當您嘗試使用 getline 讀取一行時,如果沒有提供任何分隔符作為第三個參數,getline 默認讀取直到換行符並從流中刪除換行符。 因此,在調用新行時,getline 從流中讀取並丟棄\\n
並導致在 mystr 中讀取一個空字符串,這看起來像 getline 被跳過(但事實並非如此),因為流中已經有一個換行符,getline 不會提示輸入輸入,因為它已經讀取了它應該讀取的內容。
現在,cin.ignore 在這里有什么幫助?
根據來自cplusplus.com的忽略文檔摘錄 -
istream& ignore (streamsize n = 1, int delim = EOF);
從輸入序列中提取字符並丟棄它們,直到提取了 n 個字符,或者一個比較等於 delim。
如果到達文件尾,該函數也會停止提取字符。 如果過早地達到了這一點(在提取 n 個字符或找到 delim 之前),該函數將設置 eofbit 標志。
所以, cin.ignore(256, '\\n');
, 忽略前 256 個字符或所有字符,直到遇到分隔符(在您的情況下為 \\n ),以先到者為准(此處 \\n 是第一個字符,因此它會忽略直到遇到 \\n )。
僅供參考,如果您不確切知道要跳過多少個字符,而您的唯一目的是清除流以准備使用 getline 或 cin 讀取字符串,您應該使用cin.ignore(numeric_limits<streamsize>::max(),'\\n')
。
快速解釋:它忽略等於流的最大大小的字符或直到遇到 '\\n' ,以先發生的情況為准。
當您想手動從輸入流中丟棄特定數量的字符時。
一個非常常見的用例是使用它來安全地忽略換行符,因為 cin 有時會留下換行符,您必須轉到下一行輸入。
長話短說,它在處理流輸入時為您提供了靈活性。
忽略功能用於跳過(丟棄/丟棄)輸入流中的字符。 忽略文件與文件 istream 相關聯。 考慮下面的函數,例如:cin.ignore(120,'/n'); 特定函數跳過下一個 120 個輸入字符或跳過這些字符直到讀取換行符。
正如許多其他用戶所指出的那樣。 這是因為可能有空格或換行符。
考慮下面的代碼,它從給定的字符串中刪除所有重復的字符。
#include <bits/stdc++.h>
using namespace std;
int main() {
int t;
cin>>t;
cin.ignore(); //Notice that this cin.ignore() is really crucial for any extra whitespace or newline character
while(t--){
vector<int> v(256,0);
string s;
getline(cin,s);
string s2;
for(int i=0;i<s.size();i++){
if (v[s[i]]) continue;
else{
s2.push_back(s[i]);
v[s[i]]++;
}
}
cout<<s2<<endl;
}
return 0;
}
因此,您明白它會忽略那些不需要的輸入並完成工作。
在 c++ 中使用 scanf(" %[^\\n]",str) 比在 cin>> 語句之后使用 cin.ignore() 更好。要做到這一點,首先必須包含 < cstdio > 標頭。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.