3

我基本上是在寻找某种将数组的大小/长度传递给函数的“动态”方式。


我努力了:

void printArray(int arrayName[])
{
    for(int i = 0 ; i < sizeof(arrayName); ++i)
    {
        cout << arrayName[i] << ' ';
    }
}

但我意识到它只考虑它的字节大小而不考虑数组上有多少元素。


并且:

void printArray(int *arrayName)
{
    while (*arrayName)
    {
        cout << *arrayName << ' ';
        *arrayName++;    
    }
}

这至少打印了我所有的东西,但超出了我的预期,所以它实际上并没有按照我想要的方式工作。我认为这是因为我没有准确地告诉它我需要它有多大,所以它会“安全”地播放它并给我一些大尺寸,并最终在数组中的最后一个元素之后开始打印非常奇数的整数。


所以我终于解决了这个问题,但我相信那里有更好的东西!:

void printArray(int *arrayName)
{
    while (*arrayName)
    {
        if (*arrayName == -858993460)
        {
            break;
        }
        cout << *arrayName << ' ';
        *arrayName++;
    }
    cout << '\n';
}

运行程序几次后,我意识到我输入的数组的最后一个元素之后的值总是:-858993460,所以一旦遇到这个值,我就让它中断while循环。


include <iostream>
include <conio.h>

using namespace std;

    // functions prototypes
void printArray (int arrayName[], int lengthArray);

    // global variables

    //main
int main ()
{
    int firstArray[] = {5, 10, 15};
    int secondArray[] = {2, 4, 6, 8, 10};
    printArray (firstArray,3);
    printArray (secondArray,5);

    // end of program
    _getch();
    return 0;
}

    // functions definitions
void printArray(int arrayName[], int lengthArray) 
{
    for (int i=0; i<lengthArray; i++)
    {
        cout << arrayName[i] << " ";
    }
    cout << "\n";
}

非常感谢。

4

8 回答 8

11

TL;DR 答案:使用std::vector.


但我意识到它 [ sizeof()] 只考虑它的字节大小而不是数组上有多少元素。

这本身不是问题:您仍然可以使用 获取数组的大小sizeof(array) / sizeof(array[0]),但问题是当传递给函数时,数组会衰减为指向其第一个元素的指针,因此您所能得到的只是sizeof(T *)(T是数组中元素的类型)。

关于*arrayName++

这至少打印了我所有的东西,但超出了我的预期

我什至不明白是什么激发了您以这种方式计算数组的大小。这段代码所做的只是递增数组中的第一个对象,直到它为零。

运行程序几次后,我意识到我输入的数组的最后一个元素之后的值始终是:-858993460

这是一个可怕的假设,它还依赖于未定义的行为。您无法确定数组的第一个元素之后内存中的内容,您甚至不应该访问它。


基本上,在 C++ 中,如果你想从函数中知道原始数组的大小,那么你必须手动跟踪它(例如添加一个额外的size_t size参数),因为数组传递给函数的方式(记住,他们“衰减”成一个指针)。如果您想要更灵活的东西,请考虑使用std::vector<int>C++ 标准库中的(或您想要存储的任何类型的对象)——它有一个size()方法,可以完全满足您的需求。

于 2013-05-19T18:19:37.550 回答
4

第一次尝试

当数组传递给函数时,它们会衰减为指针。通常,sizeof在数组上使用会给你它的字节大小,然后你可以除以每个元素的字节大小并得到元素的数量。但是现在,因为你有一个指针而不是一个数组,所以调用sizeof只会给你指针的大小(通常是 4 或 8 个字节),而不是数组本身,这就是失败的原因。

第二次尝试

此示例中的 while 循环假定您的数组以零结尾,这非常糟糕(除非您确实使用零作为终止符,例如以空字符结尾的字符串)。如果您的数组不以零结尾,则您可能正在访问不属于您的内存,因此会调用未定义的行为。可能发生的另一件事是您的数组中间有一个零元素,然后只会打印前几个元素。

第三次尝试

您发现潜伏在数组末尾的这个特殊值可以随时更改。这个值恰好在这一点上存在,下次它可能会有所不同,所以像这样硬编码它是非常危险的,因为同样,你最终可能会访问不属于你的内存。

你的最终代码

这段代码是正确的,并且将数组的长度与数组本身一起传递是通常所做的事情(尤其是在用 C 编写的 API 中)。只要您不传递实际上大于数组实际长度的长度,此代码就不会引起任何问题,并且有时会发生这种情况,因此也容易出错。

另一种解决方案

另一种解决方案是使用std::vector,一个容器,它在跟踪其大小的同时,还允许您添加任意数量的元素,即在运行时不需要知道大小。所以你可以做这样的事情:

#include <iostream>
#include <vector>
#include <cstddef>

void print_vec(const std::vector<int>& v)
{
    std::size_t len = v.size();

    for (std::size_t i = 0; i < len; ++i)
    {
        std::cout << v[i] << std::endl;
    }
}

int main()
{
    std::vector<int> elements;

    elements.push_back(5);
    elements.push_back(4);
    elements.push_back(3);
    elements.push_back(2);
    elements.push_back(1);

    print_vec(elements);

    return 0;
}

有用的链接值得一试

未定义行为:未定义、未指定和实现定义的行为

阵列衰减:什么是阵列衰减?

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

于 2013-05-19T18:44:17.330 回答
3

正如所有其他答案所说,您应该使用std::vector或者像您已经做过的那样,将数组元素的数量传递给打印函数。

另一种方法是在数组末尾放置一个哨兵元素(您确定它不会在数组中的值)。然后在打印功能中循环遍历元素,当找到哨兵时停止。

于 2013-05-19T18:22:16.893 回答
3

一个可能的解决方案:您可以使用模板来推断数组长度:

template <typename T, int N>
int array_length(T (&array)[N]) {
    return N;
}

请注意,您必须在数组衰减为指针之前执行此操作,但您可以直接使用该技术或在包装器中使用该技术。

例如,如果您不介意滚动自己的数组包装器:

template <typename T>
struct array {
    T *a_;
    int n_;

    template <int N> array(T (&a)[N]) : a_(a), n_(N) {}
};

你可以这样做:

void printArray(array<int> a)
{
    for (int i = 0 ; i < a.n_; ++i)
        cout << a.a_[i] << ' ';
}

并称它为

int firstArray[] = {5, 10, 15};
int secondArray[] = {2, 4, 6, 8, 10};
printArray (firstArray);
printArray (secondArray);

关键是模板化构造函数不是explicit这样,因此您的数组可以在衰减为指针之前转换为实例,捕获大小。

注意。所示的包装器不适用于拥有动态大小的数组,仅用于方便地处理静态大小的数组。为简洁起见,它还缺少各种运算符和默认构造函数。一般来说,更喜欢std::vectorstd::array代替一般用途。


... OP自己的尝试在其他地方完全解决了...

于 2013-05-19T18:25:17.880 回答
2

使用 -858993460 值非常不可靠,实际上是不正确的。

您可以通过两种方式传递数组的长度:将附加参数(例如size_t length)传递给您的函数,或者将特殊值放在数组的末尾。第一种方式是首选,但第二种方式用于,例如,通过 char* 传递字符串。

于 2013-05-19T18:21:53.897 回答
0

在 C/C++ 中,本机数组在传递给函数后立即降级为指针。因此,“长度”参数必须作为函数的参数传递。

C++ 提供了 std::vector 集合类。确保将它传递给函数时,通过引用或指针传递它(以避免在传递数组时复制数组)。

#include <vector>
#include <string>

void printArray(std::vector<std::string> &arrayName)
{
    size_t length = arrayName.size();
    for(size_t i = 0 ; i < length; ++i)
    {
        cout << arrayName[i] << ' ';
    }
}

int main()
{
    std::vector<std::string> arrayOfNames;
    arrayOfNames.push_back(std::string("Stack"));
    arrayOfNames.push_back(std::string("Overflow"));
    printArray(arrayOfNames);

    ...
}
于 2013-05-19T18:27:34.733 回答
0

在 C/C++ 中,不可能在运行时知道数组的大小。如果需要,您可以考虑使用一个std::vector类,它还有其他优点。

于 2013-05-19T18:18:46.480 回答
0

当您将数组的长度传递给 时printArray,您可以使用sizeof(array) / sizeof(array[0]),也就是说,整个数组的大小(以字节为单位)除以单个元素的大小(以字节为单位),即可得出数组本身元素的大小。

更重要的是,在 C++ 中,您可能会发现学习并更喜欢这些而不是原始数组对您有利std::vector——std::array当然,除非您正在做一项要求您了解原始数组的家庭作业。成员函数将为您提供向量中元素的size()数量。

于 2013-05-19T18:20:05.923 回答