C ++:在函数内部声明数组时,表达式必须具有常量值

时间:2016-05-24 22:25:03

标签: c++ arrays pointers const

我查看过所有其他类似主题的帖子,没有任何帮助,所以请不要标记为重复。

我在main()const int SIZE = 20;中定义。然后,我将此作为参数传递给我的函数Mode:

int* Mode(int* numbers, int & mode, const int SIZE)
 {
     int occurences[SIZE];

     // Calcualte mode
 }

但是,我收到错误expression must have a constant value

我的函数调用(在main中)看起来像这样:

int* occurencesPtr = Mode(numbersPtr, mode, SIZE);

在文字SIZE的开头定义20

我理解错误是因为SIZE的函数版本仅在调用函数时获取其值(?),但我不知道如何解决此问题

我甚至试过传递给const int * const SIZEPtr = &SIZE这个函数,但那也没有用。帮助

编辑:我尝试使用可变大小!!请注意,我到处都SIZE const了!我只想使用相同的SIZE常量来声明我的数组。

编辑:动态数组不是我需要的。我只想要一个普通的,命名的数组,用传递给函数的常量大小值定义。

4 个答案:

答案 0 :(得分:6)

const的含义存在误解,可能是因为这有点令人困惑:

const int SIZE = 20;
int array[SIZE];

但这不是:

void foo(const int SIZE) {
    int array[SIZE];
    // ...
}

const int SIZE = 20;
foo(SIZE);

问题是数组声明中的数组大小必须是核心常量表达式。简化,这意味着在编译时可评估的表达式是常量。在第一种情况下也是如此(您可以看到SIZE是整数常量20)但在第二种情况下为真。在那里,SIZE函数参数只是const - 在某种意义上它是不可修改的 - 而不是核心常量表达式。您可以看到区别在于我可以使用在运行时之前明显不可知的内容调用foo()

int x;
if (std::cin >> x) {
    foo(x);
}

为了将参数传递给foo,并将该参数用作数组绑定,仅使其为const是不够的 - 实际的积分值必须编码到类型(除非你将foo()称为constexpr,我假设这不是这里的情况)。在这种情况下,您必须执行以下操作:

template <int SIZE>
void foo() { ... }

const int SIZE = 20;
foo<SIZE>();

或:

template <int SIZE>
void foo(std::integral_constant<int, SIZE > ) { ... }

const int SIZE = 20;
foo(std::integral_constant<int, SIZE>{} );

或简单地让SIZE成为全局常量,或以foo()以其他方式与其参数无关的方式访问。

或者,总是有一个简单的选项:使用std::vector

void foo(const int SIZE) {
    std::vector<int> v(SIZE);
    ...
}

答案 1 :(得分:4)

  

我理解错误是因为函数的SIZE版本只在调用函数时获取了它的值(?),但我不知道如何解决这个问题。

选项1

不是在SIZE中定义main,而是添加constexpr函数。使用constexpr功能而不是传递大小。

constexpr int getSize()
{
   return 20;
}

int* Mode(int* numbers, int & mode)
{
   int occurences[getSize()];

   // ...

}

选项2

使用std::vector代替数组。

int* Mode(int* numbers, int & mode, int size)
{
   std::vector<int> occurences[size];

   // ...

}

选项3

使用功能模板。

template <size_t SIZE>
int* Mode(int* numbers, int & mode, int size)
{
   int occurences[SIZE];

   // ...

}

选项4

使用功能模板和std::array

template <size_t SIZE>
int* Mode(int* numbers, int & mode, int size)
{
   std::array<int, SIZE> occurences;

   // ...

}

答案 2 :(得分:3)

你让事情变得混乱。 constant expressionconst无关(至少没有那么多);)。

让我们认为我们是编译器并面对这个功能:

void foo(const int SIZE) { }

const只是说&#34;我们无法更改函数体内的函数局部变量SIZE。 我们需要编译它而不假设SIZE是编译时常量。为什么?

因为没有人阻止我们做类似的事情:

int i{};
std::cin >> i;
foo(i);

您可以将任何(匹配/可转换)值传递给值const函数参数。

当编译器假定传递给foo的值是编译时常量表达式时会发生什么?

如果您想传递编译时常数,请使用模板,当您使用模板时,请使用std::array代替T[N]

template<std::size_t N>
void foo()
{
    std::array<int, N> occurences;
}

答案 3 :(得分:0)

const并未执行您认为在Mode函数中执行的操作。

在函数定义中使用const时,const只是告诉编译器该函数不会在其函数范围内更改声明为const的参数。 。 但是这不会使参数成为常量,它实际上被称为常量表达式。有些编译器强制执行此操作,其他编译器则不执行此操作,因此将允许您更改const表达式(通过参数)使用const关键字)。

为了使用可以使用的全局可访问的常量值,如SIZE,您需要在调用函数之前声明一个全局常量;可以在main()之外声明,或者至少在main()之外的所有其他函数的范围之外声明,如果你必须在main内部声明所有函数。将全局常量传递给Mode函数就像使用任何其他变量一样。

哦,main()需要返回类型。

我已编辑代码以满足您的特定限制。

以下是原始代码的变体:

int main(){
    //Declare constants first.
    const int SIZE = 20; /*Could declare here instead.*/

    //Declare variables next.
    int *intPtr = 0; // to hold the pointer passed from Mode.
    int *numbersPointer = 0;
    int mode = 0;

    //Define Mode (using OP's code.)
    int* Mode(int* numbers, int & mode, const int size){
        int occurences[size];
         // Calculate mode
    }

    /*Now use constants, variables, and functions.*/

    intPtr = Mode(numbersPointer, mode, SIZE); //Call mode.

    return 0;
}