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

C++: Expression must have a constant value when declaring array inside function

本问题已经有最佳答案,请猛点这里访问。

我看了所有其他主题相似的帖子,没有帮助,所以请不要标记为重复。

我在main()中定义了const int SIZE = 20;。然后,我把它作为参数传递给我的函数,模式:

1
2
3
4
5
6
int* Mode(int* numbers, int & mode, const int SIZE)
 {
     int occurences[SIZE];

     // Calcualte mode
 }

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

我的函数调用(在主函数中)如下所示:

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

SIZE在文字20的开头被定义时。

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

我甚至尝试过传递函数a const int * const SIZEPtr = &SIZE,但这也不起作用。帮助?

编辑:我不想使用可变大小!!注意,我已经把SIZE变成了const!我只想使用相同的大小常量来声明数组。

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


这里对const的含义有一个误解,可能是因为它的工作有点令人困惑:

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

但这并不是:

1
2
3
4
5
6
7
void foo(const int SIZE) {
    int array[SIZE];
    // ...
}

const int SIZE = 20;
foo(SIZE);

问题是数组声明中的数组大小必须是核心常量表达式。简化,这意味着在编译时可以计算为常量的表达式。在第一种情况下是这样的(你可以看到SIZE是积分常数20但在第二种情况下不是这样的。在这里,SIZE函数参数只是const——在某种意义上说,它是不可修改的——而不是核心常量表达式。您可以看到不同之处,我可以用一些在运行时之前显然不知道的东西来调用foo()

1
2
3
4
int x;
if (std::cin >> x) {
    foo(x);
}

为了将一个参数传递到foo中,并将该参数用作数组绑定,不足以将其作为const—实际的整数值必须编码到类型中(除非您将foo()称为constexpr,我假设这里不是这种情况)。在这种情况下,您必须执行以下操作:

1
2
3
4
5
template <int SIZE>
void foo() { ... }

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

或:

1
2
3
4
5
template <int SIZE>
void foo(std::integral_constant<int, SIZE > ) { ... }

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

或者简单地让SIZE是一个全局常量,或者让foo()以一种与它的参数无关的方式访问它。


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

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


0

选项1

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

1
2
3
4
5
6
7
8
9
10
11
12
constexpr int getSize()
{
   return 20;
}

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

   // ...

}

选项2

std::vector代替array。

1
2
3
4
5
6
7
int* Mode(int* numbers, int & mode, int size)
{
   std::vector<int> occurences[size];

   // ...

}

选项3

使用函数模板。

2

选项4

使用函数模板和std::array

1
2
3
4
5
6
7
8
template <size_t SIZE>
int* Mode(int* numbers, int & mode, int size)
{
   std::array<int, SIZE> occurences;

   // ...

}


你把事情搞混了。constant expressionconst无关(至少没有那么多);。

让我们假设我们是编译器,面对这个函数:

1
void foo(const int SIZE) { }

const只说"我们不能改变函数体内部的函数局部变量SIZE"。我们需要在不假设SIZE是编译时间常数的情况下编译它。为什么?

因为没有人阻止我们做这样的事情:

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

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

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

如果要传递编译时间常量,请使用模板,在传递时使用std::array,而不是T[N]

1
2
3
4
5
template<std::size_t N>
void foo()
{
    std::array<int, N> occurences;
}

const并没有像你认为的那样在你的Mode功能中发挥作用。

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

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

噢,还有,main()需要一个返回类型。

我已经编辑了代码以满足您的特定约束。

以下是原始代码的变体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;
}