注册 登录
编程论坛 C++教室

【stack】为什么读取文件时候最后一个字符总是会读两遍?

蚕头燕尾 发布于 2014-01-12 14:47, 1063 次点击
代码:
    do
    {
        char tempChar;
        sourceFile>>tempChar;
        cout<<"读入的字符:"<<tempChar<<endl;
        ElemType tElem;
        tElem.changeElem(tempChar);
        if((tempChar=='(')||(tempChar==')')||(tempChar=='{')||(tempChar=='}')||(tempChar=='[')||(tempChar==']'))
        {
            if(stack.isEmpty())
            {
                stack.push(tElem);

                cout<<"isEmpty   in"<<endl;/////////
                continue;
            }

            if(isMatch(tempChar,stack.peek().getElem()))
            {
                stack.pop();
                cout<<"out"<<endl;/////
            }
            else
            {
                stack.push(tElem);
                cout<<"different   in"<<endl;/////////
            }

        }
    } while(!sourceFile.eof());



目的:判断文件中括号是否配对。

测试:

输入文件名:test.txt
读入的字符:(
isEmpty   in
读入的字符:(
different   in
读入的字符:(
different   in
读入的字符:{
different   in
读入的字符:}
out
读入的字符:[
different   in
读入的字符:[
different   in
读入的字符:[
different   in
读入的字符:]
out
读入的字符:]
out
读入的字符:]
out
读入的字符:)
out
读入的字符:)
out
读入的字符:)
out
读入的字符:)
isEmpty   in
0请按任意键继续. . .


test.txt文本内容:
((({}[[[]]])))


其他参考定义内容:

class Stack
{
public:
    Stack(){top=0;}
    ~Stack(){}
    void initStack(){top=0;}
    void push(ElemType item)
    {
        if(top==MaxSize)
        {
            cout<<"栈溢出!"<<endl;
            return;
        }
        top++;
        elem[top]=item;
    }
    ElemType pop()
    {
        ElemType tempElem;
        if(top==0)
        {
            cout<<"栈已空!"<<endl;
            return tempElem;
        }
        tempElem=elem[top];
        top--;
        return tempElem;
    }
    ElemType peek(){return elem[top];}
    bool isEmpty(){return !top;}
    void ClearStack(){top=0;}
private:
    int top;
    ElemType elem[MaxSize+1];
};
11 回复
#2
TonyDeng2014-01-12 16:09
你不會寫一小段程序測試自己讀文件的方式有沒有問題嗎?
#3
TonyDeng2014-01-12 16:51
知不知道C/C++編譯器要求源代碼文件最後要有一個回車(即空行)是什麽原因?
#4
蚕头燕尾2014-01-12 17:34
#include<iostream>
#include<fstream>
using namespace std;

int main()
{
    ifstream f;
    f.open("test.txt",ios::in);

    do
    {
        char c;
        f>>c;
        cout<<c<<endl;
    } while (!f.eof());

    f.close();


    f.open("test.txt",ios::in);

    while (!f.eof())
    {
        char c;
        f>>c;
        cout<<c;
    }
    return 0;
}


实验证明我写的文件读取方式确实有问题

可是这是为什么呢?


还真不知道为什么要有空行。。。头一次听说。
#5
蚕头燕尾2014-01-12 17:36
百度了一下:编译器需要文件最后有一个回车,作为文件结尾。

我在文件后加了回车,可是情况依然是这样的,最后一个字符会读两遍。
#6
TonyDeng2014-01-12 17:44
eof,是要在讀寫指針越過之後還繼續讀取時才反饋回來的,這個時候你已經多讀了一次數據,而由於實際上越不過文件末尾,所以讀入的往往是最後一次讀取時殘留的數據。所以在讀文件的時候,循環不要用eof來檢測,直接用讀數據的語句讀,讀完之後馬上檢查是否已經遇到eof,這個時候才決定是否跳出循環,在讀到有效數據之後,才開始進行數據處理的語句,不要放到處理之後再檢查(你的方法就是先處理再檢測)。

當用fgets()之類函數讀取文件的時候,若末尾沒有遇到'\n',這個函數是不會返回出錯標志的,而在下一次再fgets()的時候,就會再讀一遍,原理也是這樣。基本上,所有諸如getchar()、gets()這類靠回車才開始生效的流讀寫函數,機制都是這樣,C/C++編譯器也用這種函數讀源代碼,故此要求在最後有一空行,確保不會出問題——在某些編譯器上會提示,有的不會。

[ 本帖最后由 TonyDeng 于 2014-1-12 17:45 编辑 ]
#7
蚕头燕尾2014-01-12 17:46
#include<iostream>
#include<fstream>
using namespace std;

int main()
{
    ifstream f;
    f.open("test.txt",ios::in);

    do
    {
        char c;
        //f>>c;
        f.get(c);
        cout<<c;
    } while (!f.eof());

    f.close();


    f.open("test.txt",ios::in);

    while (!f.eof())
    {
        char c;
        //f>>c;
        f.get(c);
        cout<<c;
    }
    return 0;
}


代码经修改如上是正确的。
注:test.txt内容如下:
hello world
------>  一个空行

输出如下:
hello world!

hello world!

请按任意键继续. . .


依然不太明白为什么get是对的,直接f>>就是会把最后一个字符读两遍的。
#8
蚕头燕尾2014-01-12 17:48
“eof,是要在讀寫指針越過之後還繼續讀取時才反饋回來的”------》原来这样~

谢谢斑竹~
#9
TonyDeng2014-01-12 17:49
看明白了6樓所説的,就知道7樓的修改爲什麽有效。通常寫的循環可以形如這樣:while(get() && !feof())
#10
蚕头燕尾2014-01-12 17:55
while(get() && !feof())

嗯,学习了~

#11
TonyDeng2014-01-12 17:57
有的文件沒有FEOF字符,不要靠檢查字符内容的辦法來做,但無論如何,函數都會適當處理feof()的返回,即不要管它是怎麽知道文件結束的(這也是不需要知道太多内部細節的佐證之一)。爲了及時檢測到文件結束(在沒把握別人提供的文件在末尾是否有空行時),最好的辦法是逐個字符讀getchar(),馬上檢查,確實讀入後愛怎麽處理就怎麽處理,使用太多綜合函數要做多方面的測試才行。

編譯器要求程序員的源代碼文件最後有一個空行是偷懶的行爲,這個特性其實在業界早有微詞,不過一向如此罷了(很多語言的編譯器實際上沒那麽“低能”,人家能處理沒空行的情況)。
#12
蚕头燕尾2014-01-12 18:05
在处理二进制文件的时候,就一再被警告不要使用eof来检验文件尾。

还真不知道这里面还有这么多讲究。

1