我可以在不用硬编码的情况下确定C ++中数组的大小/长度吗?

时间:2013-05-19 18:16:07

标签: c++ arrays

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


我试过了:

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";
}

非常感谢。

8 个答案:

答案 0 :(得分:11)

TL; DR回答:使用std::vector


  

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

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

关于*arrayName++

  

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

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

  

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

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


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

答案 1 :(得分:4)

第一次尝试

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

第二次尝试

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

第3次尝试

您发现潜伏在阵列末尾的这个特殊值可以随时更改。这个值恰好就在那时,它可能会在另一个时间不同,所以硬编码就像这样非常危险,因为再次,你最终可能会访问不属于你的内存。

您的最终代码

这段代码是正确的,并且传递数组的长度以及数组本身是常见的事情(特别是在用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;
}

值得一试的有用链接

未定义的行为:Undefined, unspecified and implementation-defined behavior

数组衰减:What is array decaying?

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

答案 2 :(得分:3)

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

另一种方法是在数组末尾放置一个sentinel元素(一个你确定它不会在数组中的值)。在打印功能中,您可以循环浏览元素,当您找到哨兵时,就会停止。

答案 3 :(得分: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所以你的数组可以转换为实例,在衰减到指针之前捕获大小

NB。显示的包装器不适合拥有动态大小的数组,仅适用于方便地处理静态大小的数组。为简洁起见,它还缺少各种运算符和默认构造函数。一般而言,首选使用std::vectorstd::array作为一般用途。


...... OP自己的尝试在别处完全解决了......

答案 4 :(得分:2)

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

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

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

更重要的是,在C ++中,你可能会发现有利于了解std::vectorstd::array并且更喜欢这些而不是原始数组 - 除非你正在做一个需要的家庭作业你要了解原始数组。 size()成员函数将为您提供向量中元素的数量。

答案 7 :(得分:0)

在C / C ++中,本机数组一传递到函数就会降级为指针。因此,“length”参数必须作为函数的参数传递。

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);

    ...
}