0

我最近在 USACO 在线培训计划注册,我目前正在处理问题 2。我已经完成了编码并且一切都正确编译。但是当我提交代码时,我不断收到以下错误:

运行 1:执行错误:您的程序出现此运行时错误:打开了非法文件 (/dev/tty)。程序在出错前运行了 0.011 CPU 秒。它使用了 3348 KB 的内存。

我试图寻找问题是徒劳的。但是,我认为这是一个内存管理问题,因为我使用了指针向量。在 USACO 常见问题解答中,他们说:

运行我们的评分系统的 Linux 在内存访问方面比 Windows 更加挑剔。因此,Windows 上允许的无效数组索引和错误指针取消引用可能会导致您的程序在 Linux 下崩溃。或者,它们会破坏内部数据结构并给出最神秘的错误消息,例如“无法打开 /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

问题是您没有正确测试文件结尾。使用fin.eof()是错误的,因为eof()只有在您尝试读取并失败后才变为真,它并不能预测下一次读取是否会失败。难以置信有多少初学者会犯这个错误。

这是一个更好的方法

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

你的错误的结果是你比你应该多循环一次。在最后一次循环中,循环name不包含有效值,并且您的调用find_if失败并且程序在不久之后崩溃。

于 2012-07-29T13:05:28.083 回答
0

我在这里猜测,但是在网上查找该文件描述时,我发现 /dev/tty 是 UNIX 上用于将文本发送到进程的控制终端窗口的特殊文件(请参阅:What is special about /dev/ tty?)。

奇怪的是,提交机制是一项服务,并且没有用于输出文本的父终端窗口,因此肯定有一些东西试图输出到标准输出,从而导致了这个问题。

当它试图将错误发送到屏幕时,很可能在某个地方隐藏了一个错误。如果您在 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 回答