【问题标题】:c++ shuffling contents of dynamic array?c ++改组动态数组的内容?
【发布时间】:2012-03-02 00:03:11
【问题描述】:

嘿,伙计们,我正在尝试洗牌我的动态数组的内容,但它不起作用。我想知道你们是否有任何可以帮助我的建议或链接/资源。我正在尝试使用 std::randomshuffle 但我的测试吐出 0 而不是正确的数据。

Songs *ptr;
ptr = new Songs[25];

ifstream fin;
fin.open("input.txt");

while (fin.good())                   //my input 
{
      getline(fin, song[num].title);    
      getline(fin, song[num].artist);
      fin >> song[num].mem;
      num++;
      fin>>ws;
}
fin.close();

这是我尝试使用随机播放的函数

void shuffle (char choice, Songs song[], Songs *ptr, string title, string artist, int  mem, int num)
{
    if (choice == '4')
    {  
        std::random_shuffle(ptr, ptr + num);             //shuffle
    }
    for (int i = 0; i<num; i++)    //test
    {
        cout << ptr[i].title << ptr[i].artist << ptr[i].mem << endl;   
    }
}

【问题讨论】:

  • 为什么shuffle()函数的所有参数?您只使用ptrnum。是否进行洗牌的逻辑实际上不应该在洗牌函数中完成。
  • 这些是我的 ptr 数组的内容,所以我想我也必须包含这些内容
  • @gamergirl22 绝对不需要也不应该这样做。稍后你必须考虑如何有效地设计代码:这个 shuffle 函数的重点是 shuffle 歌曲并打印出来。所以我们只需要歌曲和 num(不是“song”和“ptr”)也是多余的。
  • @gamergirl22 至于洗牌,假设你为“ptr”和“num”传递了正确的参数,你如何洗牌这些歌曲并没有错。我怀疑您的程序失败的地方在于阅读歌曲。您可能希望在从文件中读取歌曲后立即输出歌曲,或者更好的是,学习如何使用调试器,您可以在跟踪代码时查看所有变量的值。
  • 并且不要在没有理由的情况下使用new。请改用std::vector,它会自行调整大小并适应文件中的歌曲数量。

标签: c++ arrays pointers shuffle


【解决方案1】:

切勿使用istream::good()istream::eof() 作为循环条件。它几乎总是会产生错误的代码(就像在这种情况下一样。)

试试:

while (std::getline(fin, song[num].title) &&
       std::getline(fin, song[num].artist) &&
       fin >> song[num].mem) 
{
      num++;
      fin>>ws;
}

正如 stinky 指出的那样,您的 shuffle 是正确的,尽管风格很糟糕。试试:

void shuffle (char choice, Songs *ptr, int num)
{
    if (choice == '4')
    {  
        std::random_shuffle(ptr, ptr + num);             //shuffle
    }
    for (int i = 0; i<num; i++)    //test
    {
        std::cout << ptr[i].title << ptr[i].artist << ptr[i].mem << "\n";   
    }
}

【讨论】:

    【解决方案2】:

    请考虑以下问题,这是一种更现代的 C++ 方法来解决您的问题。您创建了流运算符,因此您不必在每次希望读取时手动解析对象。

    #include <algorithm>
    #include <string>
    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <iterator>
    
    struct song {
            std::string title, artist;
            int mem;
    };
    
    std::ostream& operator<<(std::ostream& os, const song& s) {
            return os << s.title << "\t" << s.artist << "\t" << s.mem;
    }
    
    std::istream& operator>>(std::istream& is, song& s) {
            std::getline(is, s.title);
            std::getline(is, s.artist);
            return is >> s.mem;
    }
    
    int main()
    {
            std::ifstream file("input.txt"); 
    
            if(!file.is_open()) return 1;
    
            std::vector<song> songs((std::istream_iterator<song>(file)),
                                     std::istream_iterator<song>());
            std::random_shuffle(songs.begin(), songs.end());
    
            std::copy(songs.begin(), songs.end(), 
                      std::ostream_iterator<song>(std::cout, "\n"));
            return 0;
    }
    

    编译但未经测试您的文件格式

    没有矢量(但请学习)这个:

           std::vector<song> songs((std::istream_iterator<song>(file)),
                                     std::istream_iterator<song>());
    

    可以写成:

     const size_t sz=20;
     song songs[sz];
     for(unsigned i=0; i!=sz && file; ++i)
         file >> songs[i];
    

    函数调用的其余部分将像这样工作

    std::random_shuffle(songs, songs+sz);
    

    但现在认真学习向量(然后是其他容器)。数组基本上被认为不适合您的任务,原因的一个例子是,如果文件中有超过 20 个元素,您会遇到缓冲区溢出并且会发生坏事。

    http://en.cppreference.com/w/cpp/container/vector

    此外,由于 RAII,您不需要显式打开和关闭文件(在大多数情况下,您更有可能引入错误):

    http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization

    【讨论】:

    • 这看起来很不错,但不幸的是我还没有学过向量,所以我不知道如何将它合并到我的函数调用等中。哈哈。非常好的工作,我投票给你。
    • 立即学习向量!认真的
    猜你喜欢
    • 1970-01-01
    • 2013-10-20
    • 1970-01-01
    • 2016-09-25
    • 2016-02-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-29
    • 2012-04-17
    相关资源
    最近更新 更多