【问题标题】:How Can i combine one while loop with a for loop?如何将一个while循环与一个for循环结合起来?
【发布时间】:2018-03-16 16:06:10
【问题描述】:

我正在尝试按照我的指示将这两个循环组合在一起,但我无法弄清楚我应该如何做这样的事情。因为我在 for 循环中的计数器 i 不能进入 while 循环条件。我的老师希望程序只做一个循环。提前致谢。该代码基本上是通过一个txt文件运行的,应该首先将值分配给一个数组,然后在for循环中我将它分配给一个指针。

这部分我有问题:

void fillArr(vector <student> &arr, vector <student *> &ptrels){
    student temp;

    ifstream inFile ("index.txt");
    while (!inFile.eof()) {
        inFile >> temp.fName >> temp.Lname >> temp.gpa >> temp.id >> temp.email;
        arr.push_back(temp);
    }
    for (unsigned i = 0; i < arr.size(); i++ ){
        ptrels.push_back(&arr[i]);
    }

//    combine the two above loops
}

这是整个代码:

> #include <string>
> #include <cstdio>
> #include <iostream>
> #include <vector>
> #include <fstream>
> #include <sstream> using namespace std;
> 
> struct student {
>     string fName, Lname, email, id;
>     double gpa; } ;
> 
> void input(); void fillArr(vector <student> &arr, vector <student *>
> &ptrels); void printFile(vector <student *> pointarray); void
> sortFile(vector <student> &arr, vector <student *> &pointarray);
> 
> int main() {
>     vector <student> elements;
>     vector <student *> ptrels;
>     
>     ifstream inFile;
>     inFile.open("index.txt");
>     
>     int answer;
>     fillArr(elements, ptrels);
>     cout << "Please select:" << endl
>     << "1 = Select All" << endl
>     << "2 = Order A-Z by Name"<<endl
>     << "3 = To exit"<< endl;
>     cin >> answer ;
>     if (answer == 1){
>         printFile(ptrels);
>         main();
>     }
>     if (answer ==2){
>         sortFile(elements, ptrels);
>         printFile(ptrels);
>         main();
>     }
>     if (answer ==3){
>         inFile.close();
>         exit(0);
>     }
>     else {
>         cout << "Invalid Try Again:"<< endl;
>         main();
>     }
>     return 0; }
> 
> void fillArr(vector <student> &arr, vector <student *> &ptrels){
>     student temp;
> 
>     ifstream inFile ("index.txt");
>     while (!inFile.eof()) {
>         inFile >> temp.fName >> temp.Lname >> temp.gpa >> temp.id >> temp.email;
>         arr.push_back(temp);
>     }
>     for (unsigned i = 0; i < arr.size(); i++ ){
>         ptrels.push_back(&arr[i]);
>     }
> 
> //    combine the two above loops }
> 
> 
> 
> void printFile(vector <student *> pointarray){
>     for (unsigned j = 0; j < pointarray.size(); j++){
>         cout << pointarray[j] -> fName << "    ";
>         cout << pointarray[j] -> Lname<< "    ";
>         cout << pointarray[j] -> gpa << "    ";
>         cout << pointarray[j] -> id << "    ";
>         cout << pointarray[j] -> email << "    ";
>         cout << endl;
>     } }
> 
> //swap the elements by pointer. you are swaping the record not the
> pointers. // only sorting by firstname, sort by all 5 void
> sortFile(vector <student> &arr, vector <student *> &pointarray){
>     for(unsigned i = 0; i < arr.size(); ++i){
>         for(unsigned j = i + 1; j < arr.size(); ++j) {
>             if(arr[i].fName > pointarray[j] -> fName) {
>                 swap(arr[i].fName,pointarray[j] ->fName);
>                 swap(arr[i].Lname,pointarray[j] ->Lname);
>                 swap(arr[i].gpa,pointarray[j] ->gpa);
>                 swap(arr[i].id,pointarray[j] ->id);
>                 swap(arr[i].email,pointarray[j] ->email);
>             }
>         }
>     } }

我也知道我应该在另一个问题中提出这个问题,但她也希望我进行排序,这是 sortFile 的最后一个函数,它不仅按 firstName 对所有值进行排序。加上不知何故,她讨厌交换功能,寻找替代品。任何提示将不胜感激。

【问题讨论】:

  • 我个人会通过完全删除第二个参数和第二个循环来解决它
  • 你在哪里读到这样使用while (!inFile.eof())
  • 永远不要使用eof 作为循环条件。测试流故障。而您需要为输入操作执行此操作。
  • @SombreroChicken 不能那样做; arr 可能会重新分配内存,留下浮动指针

标签: c++ for-loop while-loop


【解决方案1】:

一个简单的解决方案可能会将两个循环折叠成以下内容:

void fillArr(vector <student> &arr, vector <student *> &ptrels){
    student temp;

    ifstream inFile ("index.txt");
    while (!inFile.eof()) {
        inFile >> temp.fName >> temp.Lname >> temp.gpa >> temp.id >> temp.email;
        arr.push_back(temp);
        ptrels.push_back(&arr.back());
    }
//    combine the two above loops
}

假设arr.empty() 是该函数的前提条件(如果不是,则语义无论如何都会被破坏),这几乎是做同样的事情。

差不多了。

问题是,每个arr.push_back(temp) 都可能导致arr 的扩展,从而使您迄今为止在ptrels 中放入的所有指针都无效。最初的解决方案使用了第二个循环,这样您就知道arr 已经完成并在您开始使用指针之前进行了除尘。

我们仍然可以使用单循环解决方案,只要我们通过reserveing 向量中的空间来防止重新分配。为此,您需要提前知道需要多少元素。为此,您需要使用两次"index.txt",然后返回到两个循环。

所以,基本上,不,你不能这样做。

真正的解决方案是拒绝该要求。希望这就是您的老师希望您报告的内容。无论如何,在像这样的简单案例中,我想不出任何“索引”向量的实际用例。

另外,watch your I/O methodology

【讨论】:

  • 我想说的是,老师显然不想要这种幼稚的解决方案......但是看着这里经常发布的问题让我对老师失去了信心。
  • @UKMonkey:没错?
  • 只是一个荒谬的想法:您可以获取文件的大小(使用库或系统特定的 API)并为最坏的情况保留向量 size_of_file / 5
  • @bolov:你可以
  • 我现在尝试获取值的地址,而不是值本身。我添加了整个代码供您查看。?
【解决方案2】:

因此,随着您发布整个代码;解决方案是完全消除对指针向量的需要。

通过尝试以您的方式处理 2 个向量,您的排序功能变得更加困难;并且您的 printFile() 使用指针并不比使用对向量的引用更简单。

我不明白为什么你一开始就有这个指针向量;除了有时它们用于尝试对组执行排序而不改变原始组的顺序。既然你确实改变了顺序,那就是痛苦的载体。

摆脱它;让生活变得简单。

除此之外: 您的 sortFile() 可以使用 std::sort 并且变得不仅更快而且更易于阅读。

【讨论】:

    【解决方案3】:

    C++17 代码(我将 sort 函数体留空,以便为家庭作业留下一些事情要做,我认为这部分应该是 Main Thing™):

    // Source encoding: utf-8 with BOM ∩
    #include <string>               // std::(string)
    #include <iostream>             // std::(cout, cerr)
    #include <optional>             // std::(optional)
    #include <utility>              // std::(move)
    #include <vector>               // std::(vector)
    #include <fstream>              // std::(ifstream)
    #include <sstream>              // std::(istringstream)
    #include <stdexcept>            // std::(exception, runtime_error)
    using namespace std;
    
    auto hopefully( bool const e ) -> bool { return e; }
    [[noreturn]] auto fail( string const& s ) -> bool { throw runtime_error( s ); }
    
    auto optional_line_from( istream& stream )
        -> optional<string>
    {
        string result;
        return getline( stream, result )? result : optional<string>{};
    }
    
    struct Student_info
    {
        string first_name;
        string last_name;
        double gpa;
        string id;
        string email;
    };
    
    // Originally
    // void fillArr(vector <Student_info> &arr, vector <Student_info *> &ptrels):
    
    auto data_from( string const& filename )
        -> vector<Student_info>
    {
        ifstream in_file{ "index.txt" };
        hopefully( not in_file.fail() )
            or fail( "Failed to open “index.txt” for reading." );
    
        vector<Student_info> result;
        while( optional<string> line = optional_line_from( in_file ) )
        {
            Student_info temp;
            istringstream items{ *line };
            items >> temp.first_name >> temp.last_name >> temp.gpa >> temp.id >> temp.email;
            hopefully( not items.fail() )
                or fail( "Failed to parse input line: “" + *line + "”." );
            result.push_back( move( temp) );
        }
        return result;
    }
    
    auto operator<<( ostream& stream, Student_info const& item )
        -> ostream&
    {
        stream
            << item.first_name << "    "
            << item.last_name<< "    "
            << item.gpa << "    "
            << item.id << "    "
            << item.email;
        return stream;
    }
    
    // Originally
    // void printFile(vector <student *> pointarray):
    
    void print( vector<Student_info const*> const& pointers )
    {
        for( auto const p : pointers ) { cout << *p << endl; }
    }
    
    // Originally
    // void sortFile(vector <student> &arr, vector <student *> &pointarray):
    
    void sort( vector<Student_info const*>& pointarray )
    {
        // TODO:
        // Using std::sort is a good idea, if you're allowed to do that.
        // std::tuple instances can be lexicographically compared with `<`, and
        // `std::tie` produces a tuple. That's great for the current job.
    }
    
    // Originally
    // int main():
    
    void cpp_main()
    {
        vector<Student_info> const data = data_from( "index.txt" );
    
        vector<Student_info const*> pointers;
        for( Student_info const& item : data ) { pointers.push_back( &item ); }
    
        for( ;; )
        {
            cout << "Please select\n"
                 << "1 = Select All\n"
                 << "2 = Order A-Z by Name\n"
                 << "3 = To exit"
                 << endl;
            try
            {
                switch( stoi( *optional_line_from( cin ) ) )
                {
                    case 1:
                    {
                        print( pointers );
                        break;
                    }
                    case 2:
                    {
                        sort( pointers );
                        print( pointers );
                        break;
                    }
                    case 3:
                    {
                        return;
                    }
                    default:
                    {
                        fail( "" );
                    }
                }
            }
            catch( ... )
            {
                // Avoid infinite loop on input failure:
                if( cin.fail() )
                {
                    fail( "Failed reading standard input." );
                }
                cout << "Invalid Try Again:" << endl;
            }
        }
    }
    
    auto main()
        -> int
    {
        try
        {
            cpp_main();
            return EXIT_SUCCESS;
        }
        catch( exception const& x ) 
        {
            cerr << "!" << x.what() << endl;
        }
        return EXIT_FAILURE;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-12
      • 1970-01-01
      • 2014-09-17
      • 1970-01-01
      • 2013-07-06
      • 1970-01-01
      相关资源
      最近更新 更多