【问题标题】:How to return an array from a function in c++如何从 C++ 中的函数返回数组
【发布时间】:2020-04-07 03:38:36
【问题描述】:

您好,我正在尝试从输入文件中获取数据并将其放入数组中。我能够完成我的一个功能并返回数组,如下所示:

string * animal_name_grab() 
{
        static string animal_name[SIZE];
        int cntr = 0;
        static string line_skip[SIZE];
    while (!input_animals.eof())
    {
        getline(input_animals, animal_name[cntr]);
        getline(input_animals, line_skip[cntr]);
        cntr++;
    }
    return (animal_name);
}

现在我正在尝试做同样的事情,但将数字的总和相加。我不知道它到底有什么问题。我以与上一个完全相同的方式调用函数,但我也将其插入以防万一。 声明双 *array_animal_total; 函数调用——array_animal_total = animal_total_grab();

double * animal_total_grab()
{
        static double animal_total[SIZE];
        static string line_skip[SIZE];
        int cntr = 0;
        double sum = 0;
        double total_count;
    while (!input_animals.eof())
    {
        getline(input_animals, line_skip[cntr]);

            for ( int i ; i < 10 ; i++)
            {
            input_animals >> total_count;
            sum = sum + total_count;    
            }
        animal_total[cntr] = sum;

        cntr++;
    }
    return (animal_total);
}

如果此处输入的代码过多,请告知我,以便我进行编辑。我只是想证明我理解这些材料,我只是遇到了一些麻烦。我是初学者,所以请善待。

【问题讨论】:

  • return 0;...?
  • 顺便说一句,while (!input_animals.eof()) 的这种用法和this 一样是错误的。
  • 看起来你制作数组static 是一种解决方法,以确保内存的范围在你的函数之外持续存在,这对我来说似乎很棘手。相反,为什么不将函数的签名更改为std::vector&lt;double&gt; animal_total_grab(),然后按值返回vector
  • 我的建议是不要。如果您知道编译时的大小,则返回 std::array,如果您知道运行时的大小,则返回 std::vector。 C++ 的值语义是一个非常好的特性,你应该尽可能地使用它(大多数时候)
  • @peschü 不要建议在 2019 年使用 auto_ptr。幸运的是,该标准已被删除。

标签: c++ arrays file-handling


【解决方案1】:

我能够完成我的一个功能并让数组返回如下所示:

string * animal_name_grab() 

你没有返回一个数组。您正在返回一个指针。指针指向数组的一个元素。

如何从 c++ 中的函数返回数组

实际上,在 C++ 中直接从函数返回数组是不可能的。但是,可以返回类的实例,并且类可以具有数组成员,因此如果将数组包装在类中,则可以返回该包装器对象。这种数组包装类有一个标准模板。它的名字是std::array。示例:

std::array<std::string, SIZE> animal_name_grab()
{
    std::array<std::string, SIZE> animal_name;
    ...
    return animal_name;
}

请注意,复制大型数组可能会很慢,并且您将依赖编译器优化来避免复制返回值。使用输出迭代器而不是返回数组有时更有效,而且通常更灵活。

【讨论】:

  • 如果大小太大以至于您不得不担心优化它,它可能大到足以粉碎您的堆栈,无论如何您都应该将其换成 std​​::vector。
  • @Sahsahae “堆栈太大”和“复制太大”的阈值不一定相同。无论如何,使用输出迭代器,函数不一定需要任何数据结构。如果调用者知道大小很小,他们可以使用数组。如果没有,他们可以使用向量。或者他们可以使用一组例如,如果这更适合他们。
【解决方案2】:

您要求提供建议,所以您来了: 如果您想让您的代码更像 C++ 和现代,请考虑使用 std::arraystd::vector 而不是原始数组。 这允许您使用 STL_functions,例如:

std::for_each(vector.begin(), vector.end(), [&] (int n) {
sum_of_elems += n;
});

获取元素的总和。 您可以返回向量,但我建议您先创建向量,然后通过引用传递它。

std::vector<std::string> input;
input.reserve(approxSpace); // Not necessary
getInput(&input); // Fill vector in external function

在你的情况下,还要避免使用像10 这样的“幻数”。如果您的项目变得更大,那么在不破坏代码的情况下进行更改会变得更加困难。

【讨论】:

  • 标准算法也可以用于数组。此外,还有std::accumulate 表示总和。
【解决方案3】:

您可以分解它并为animalanimal_collection 定义您自己的类型,并添加一些函数以按照您的意愿使用它们。您显然想从流中读取animal,所以让我们为此创建一个函数。您还想阅读animals 的完整集合,所以让我们为此添加一个函数。

演练:

#include <iostream>
#include <vector>  // std::vector - a dynamically growing container
                   //               that you can store objects in
#include <sstream> // std::istringstream for demo purposes

// A type to store the characteristics of an animal in. Let's start with a name.
struct animal {
    std::string name;
};

// A function to read one "animal" from std::cin or some other istream.
//
// It's functions like these that makes "cin >> variable;" work in your everyday program.
std::istream& operator>>(std::istream& is, animal& a) {
    std::getline(is, a.name);
    return is;
}

// A function to write one "animal" to std::cout or some other ostream.
std::ostream& operator<<(std::ostream& os, const animal& a) {
    return os << a.name;
}

// A collection of animals.
struct animal_collection {
    // std::vector - This std::vector stores objects of the type "animal".
    //               It has a lot of good features and is often prefered as a container
    //               when the exact number of elements to store is unknown.
    std::vector<animal> creatures;

    // return the number of "animal" objects there are in this "animal_collection"
    size_t size() const { return creatures.size(); }

    // iterator support functions so that you can loop over an animal_collection.
    // In this case, they are mearly proxy functions for the functions in std::vector
    // that we need exposed.

    // const iterators
    auto cbegin() const { return creatures.cbegin(); }
    auto cend() const { return creatures.cend(); }

    auto begin() const { return cbegin(); }
    auto end() const { return cend(); }

    // non-const iterators
    auto begin() { return creatures.begin(); }
    auto end() { return creatures.end(); }
};

// A function to read one "animal_collection" from std::cin or some other istream,
// like a file / ifstream.
std::istream& operator>>(std::istream& is, animal_collection& ac) {
    animal tmp;
    while(is >> tmp) { // use operator>> for "animal"
        // push_back() is a function in std::vector. Since this vector stores "animal"
        // objects and "tmp" is an "animal" object, this works:
        ac.creatures.push_back(tmp);
    }
    return is;
}

// A function to write one "animal_collection" to std::cout or some other ostream,
// like a file / ifstream.
std::ostream& operator<<(std::ostream& os, const animal_collection& ac) {
    // use the iterator support functions added to the "animal_collection" type
    // and loop over all the animal objects inside
    for(const animal& a : ac) {
        os << a << '\n'; // use operator<< that was added for "animal"
    }
    return os;
}

// using the two types created above
int main() {
    std::istringstream cin(
        "Tiger\n"
        "Lion\n"
        "Zebra\n"
        "Dalek\n");

    animal_collection ac;

    // read all "animal" objects into the "animal_collection"
    //
    // emulating reading animals from cin - replace with any istream,
    // like an open file

    cin >> ac; // use operator>> defined for "animal_collection"

    // use the size() function in the "animal_collection":
    std::cout << "there are " << ac.size() << " animal(s):\n";

    // output the whole "animal_collection"
    std::cout << ac;
}

当您需要向animal 添加特征时,您只需更改与该类型相关的内容。 animal_collection 不需要更改。 animal_collection 中的 std::vector&lt;animal&gt; 具有 a lot of other nice functions,您也可以通过代理函数公开​​它们,就像 size()begin() / end() 系列函数一样。

【讨论】:

    【解决方案4】:

    如果你不想使用 std 库中的任何东西,你总是可以在堆上声明数组,这样当你返回时它不会被破坏。

    例如:

    double * func(){
       double * someArray = new double[3]; //declaring 'someArray' on the heap
    
       for(int i = 0; i < 3; i++)   //Filling the array with data
          someArray[i] = i;         //filling the array with data
    
       return someArray;            //since 'someArray' is on the heap it wont be destructed when you return
    }
    

    虽然在完成后不要忘记删除数组。

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-17
      • 2015-02-09
      • 2020-02-14
      • 2020-05-31
      • 2015-09-12
      相关资源
      最近更新 更多