簡體   English   中英

何時以及為何需要在 C++ 中使用 cin.ignore()?

[英]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 換行符。)

你正在以錯誤的方式思考這個問題。 每次使用cingetline時,您都在按邏輯步驟進行思考。 前任。 先問號碼,再問名字。 這是考慮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' 那,或者您在cingetline之間放置一個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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM