0

最近、USACO のオンライン トレーニング プログラムに登録しました。現在、問題 2 に取り組んでいます。コーディングを終了し、すべてが正しくコンパイルされました。しかし、コードを送信すると、次のエラーが発生し続けます。

実行 1: 実行エラー: プログラムで次のランタイム エラーが発生しました: Illegal file open (/dev/tty)。プログラムは、エラーが発生する前に 0.011 CPU 秒間実行されました。3348 KB のメモリを使用しました。

問題を探してみましたが無駄でした。ただし、ポインターのベクトルを使用したため、これはメモリ管理の問題だと思います。USACO faq では、次のように述べています。

私たちの採点システムが実行されている Linux は、Windows よりもメモリ アクセスに関して非常にうるさいです。したがって、Windows で許可されている無効な配列インデックスと不適切なポインター逆参照により、プログラムが Linux でクラッシュする可能性があります。または、内部データ構造を破壊し、"Can't open /dev/[mumble]" のような最も不可解なエラー メッセージを表示します。

コードは次のとおりです。

/*
ID: freebie1
PROG: gift1
LANG: C++
*/
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <fstream>
using namespace std;


class Person {
    public:
    Person():m_volatile(0) {}

    void setName(string name) { m_name = name; }
    string getName() { return m_name; }
    void setMoney(int money){ m_sMoney = money; }
    int getMoney() { return m_volatile; }
    void receive(int money) { m_volatile += money; }
    void giveGifts(vector<Person*> fTab){
        int splitMoney = m_sMoney/fTab.size();
        for(vector<Person*>::iterator it=fTab.begin();it!=fTab.end();it++) {
            (*it)->receive(splitMoney);
        }
        m_volatile-=splitMoney*fTab.size();
    }

    private:
    string m_name;
    int m_sMoney; // starting money
    int m_volatile;
};

.

class FindFriend {
    public:
    FindFriend(string query):m_query(query){}
    bool operator()(Person &individu){
        if(individu.getName()==m_query) { return true; }
        else { return false; }
    }
    private:
    string m_query;
};

vector<Person*> setFriends(vector<string> &namesTab,vector<Person> &personsTab){
    vector<Person*> tab;
    for(vector<string>::iterator it=namesTab.begin();it!=namesTab.end();it++) {
        FindFriend f(*it);
        vector<Person>::iterator trouve=find_if(personsTab.begin(),personsTab.end(),f);
        tab.push_back(&*trouve);
    }
    return tab;
}

int main() {
    ofstream fout("gift1.out");
    ifstream fin("gift1.in");

    if(fin) {
        int np(0);
        fin>>np; // Number of persons

        // Each one is assigned a name...
        vector<Person> personsTab(np);
        for(vector<Person>::iterator it=personsTab.begin();it!=personsTab.end();it++){
            string namePerson;
            fin>>namePerson;
            it->setName(namePerson);
        }
        // ...money and the friends we'll give the money to
        while(!fin.eof()){
            string name;
            int money(0),nFriends(0);
            fin>>name;
            FindFriend g(name);
            vector<Person>::iterator trouve=find_if(personsTab.begin(),personsTab.end(),g);
            fin>>money>>nFriends;
            trouve->setMoney(money); // Somme de depart
            // Amis
            if(nFriends!=0 || money!=0) {
                vector<string> friendsTab;
                for(int i(0);i<nFriends;i++) {
                    string chaine;
                    fin>>chaine;
                    friendsTab.push_back(chaine);
                }
                // We create a vector of pointers to his friends
                vector<Person*> pFriends(nFriends);
                pFriends=setFriends(friendsTab,personsTab);
                trouve->giveGifts(pFriends); // Each person share the money among his friends
            }
        }

        // We output the net loss/profit for each one
        for(vector<Person>::iterator it=personsTab.begin();it!=personsTab.end();it++) {
            string name=it->getName();
            int money=it->getMoney();
            fout<<name<<" "<<money<<endl;
        }
    }
    return 0;
}

そして、これが入力ファイルgift1.inです

5
dave
laura
owen
vick
amr
dave
200 3
laura
owen
vick
owen
500 1
dave
amr
150 2
vick
owen
laura
0 2
amr
vick
vick
0 0
4

2 に答える 2

2

問題は、ファイルの終わりを正しくテストしていないことです。読み取りを試みて失敗した後にのみ true になるため、次の読み取りが失敗するかどうかを予測しないため、使用fin.eof()は間違っています。信じられないほど多くの初心者がこれを間違えています。eof()

ここにそれを行うためのより良い方法があります

   string name;
   while(fin >> name){
        int money(0),nFriends(0);
        ...
   }

エラーの結果、必要以上に while ループを回ってしまいます。最後のラウンドでは、ループnameに有効な値が含まれておらず、への呼び出しがfind_if失敗し、プログラムは直後にクラッシュします。

于 2012-07-29T13:05:28.083 に答える
0

私はここで推測を投げかけていますが、そのファイルの説明をオンラインで探していると、 /dev/tty がプロセスの制御端末ウィンドウにテキストを送信するために UNIX で使用される特別なファイルであることがわかりました (次を参照してください: /dev/ の特別な点についてティ?)。

おそらく、送信メカニズムはサービスであり、テキストを出力する親端末ウィンドウがないため、標準出力に出力しようとしている何かがこの問題を引き起こしているに違いありません。

画面にエラーを送信しようとするため、これによって隠されているエラーがどこかにある可能性があります。Windows マシンで作業している場合は、VMware プレーヤー (無料) を入手し、Linux VM を構築することをお勧めします (無料のディストリビューションをダウンロードして、VMware プレーヤーをそれにポイントするだけで非常に簡単です)、その環境でプログラムをコンパイルして実行します。どのように振る舞うかを見ることができます。このようにして、それがあなたに伝えようとしたことを確認し、そこから作業することができます。

ボンチャンス。

PS: 私は Linux マシンを持っており、しばらくしてから自分で試してみますが、この問題が再び発生する可能性が高いため、他の問題については Linux VM を作成する演習を行う必要があります。

Linux でプログラムをそのまま実行すると、出力ファイルは次のようになりました。

dave 302
laura 66
owen -359
vick 141
amr -150

この例外をスローしました:

*** glibc detected *** ./test.out: free(): invalid pointer: 0x0000000001b43510 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7a6e6)[0x7f3dfaa846e6]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x6c)[0x7f3dfaa889cc]
/usr/lib/x86_64-linux-gnu/libstdc++.so.6(_ZNSsD1Ev+0x23)[0x7f3dfb0641e3]
./test.out[0x401ece]
./test.out[0x404808]
./test.out[0x40439d]
./test.out[0x403d40]
./test.out[0x403269]
./test.out[0x40249c]
./test.out[0x4019ae]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f3dfaa2b30d]
./test.out[0x401169]
...

gdb を使用して行ごとにステップ実行すると、「personsTab」変数が範囲外になり破棄されると例外が発生します。

于 2012-07-29T13:15:06.483 に答える