1

I have looked at all the other posts with a similar topic, and none help, so please don't flag as a duplicate.

I am defining in main() a const int SIZE = 20;. Then, I pass this as an argument to my function, Mode:

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

     // Calcualte mode
 }

However, I get the error, expression must have a constant value.

My function call (in main) looks like this:

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

With SIZE being defined at the beginning to the literal 20.

I understand that the error is because the function's version of SIZE only acquires its value when the function is called (?), but I don't know how I could work around this.

I have even tried passing to the function a const int * const SIZEPtr = &SIZE, but that didn't work either. Help?

EDIT: I am not trying to use a variable size!! Notice that I have made SIZE a const everywhere! I just want to use that same SIZE constant to declare my array.

EDIT: Dynamic arrays are not what I need. I just want a normal, named, array, defined with a constant size value passed to the function.

vasilescur
  • 240
  • 2
  • 5
  • 16
  • 100% duplicate. use the search with your exact title. Look for "dynamic" in the answers. – Marcus Müller May 24 '16 at 22:27
  • Variable Length Arrays are not Standard C++. While they are supported by some compilers as an extension there is no guarantee it will be available when switching to a different toolchain. – Captain Obvlious May 24 '16 at 22:27
  • int *occurences = new int[SIZE]; .... ; delete(occurences); – reuns May 24 '16 at 22:37
  • What you want in the way you want it is not possible in Standard C++. – Captain Obvlious May 24 '16 at 22:37
  • (the reason being that new int[SIZE]; allocates the array in the heap, while int occurences[SIZE]; allocates it into the stack (i.e. in the middle of the local variables of the function)) – reuns May 24 '16 at 22:39
  • Thank you, @user1952009, that worked. – vasilescur May 24 '16 at 22:43
  • The size *is* variable because it is passed as a function parameter, and "constant" != "const". Read the error as saying "must have a fixed value". It must be known at the time of definition, not at run time, otherwise it's a dynamic array. – kfsone May 24 '16 at 23:26

4 Answers4

9

There is a misconception here with what const means, probably because it's a little confusing that this works:

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

but this doesn't:

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

const int SIZE = 20;
foo(SIZE);

The issue is that the array size in an array declaration must be a core constant expression. Simplified, that means an expression that's evaluatable at compile time to be a constant. That is true in the first case (you can see that SIZE is the integral constant 20) but that is not true in the second case. There, the SIZE function parameter is just const - in the sense that it is nonmodifiable - and not a core constant expression. You can see the difference in that I can call foo() with something that is clearly unknowable until runtime:

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

In order to pass an argument into foo, and have that argument be used as an array bound, it is not enough to have it be const - the actual integral value must be encoded into the type (unless you call foo() as constexpr which I'm assuming is not the case here). In which case, you'd have to do something like:

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

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

or:

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

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

or simply have SIZE be a global constant or otherwise accessible to foo() in a way that doesn't have to do with its arguments.


Or, there's always the simple option: use std::vector:

void foo(const int SIZE) {
    std::vector<int> v(SIZE);
    ...
}
Barry
  • 286,269
  • 29
  • 621
  • 977
  • Thanks, that cleared a lot of things up. I'm very new to C++, and I actually have no idea what a template is or what it does, but it works :) – vasilescur May 24 '16 at 22:51
5

I understand that the error is because the function's version of SIZE only acquires its value when the function is called (?), but I don't know how I could work around this.

Option 1

Instead of defining SIZE in main, add a constexpr function. Use the constexpr function instead of passing the size.

constexpr int getSize()
{
   return 20;
}

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

   // ...

}

Option 2

Use std::vector instead of array.

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

   // ...

}

Option 3

Use a function template.

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

   // ...

}

Option 4

Use a function template and std::array.

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

   // ...

}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
3

You're confusing things. A constant expression has nothing to do with const (at least not that much) ;).

let's think we are the compiler and face this function:

void foo(const int SIZE) { }

The constmerely says "we are not able to change the function-local variable SIZE inside the function body. We need to compile it without assuming that SIZE is compile time constant. Why?

Because there is noone stoping us from doing something like:

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

You can pass any (matching/convertible) value to a by value const function argument.

What should happen when the compiler assumed the value passed to foo was a compile time constant expression?

If you want to pass compile time constants, use templates and while you're at it use std::array instead of T[N]:

template<std::size_t N>
void foo()
{
    std::array<int, N> occurences;
}
Pixelchemist
  • 24,090
  • 7
  • 47
  • 71
1

const isn't doing what you think it's doing in your Mode function.

When const is used in function definition, const is simply telling the compiler that the function will not change the argument declared const inside of the scope of it's function. But that does not make the argument a constant, it is actually called a constant expression. Some compilers enforce this, others do not, and so will allow you to change const expressions (arguments passed with const keyword).

In order to use a globally accessible constant value which you can use, like SIZE, you'll need to declare a global constant before the function is called; which could be declared outside of main(), or at least outside the scope of all other functions but main(), if you must declare all inside main. Pass the global constant to the Mode function just as you would any other variable.

Oh, and, main() needs a return type.

I've edited the code to meet your specific constraints.

Here is a variation on your original code:

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;
}
NonCreature0714
  • 5,744
  • 10
  • 30
  • 52
  • 1
    Thanks, but this program is for an assignment, and my teacher's policy is no global constants or variables, so I won't be able to use this. Useful for future reference, though :) – vasilescur May 24 '16 at 22:59
  • No problem, always glad to help a fellow student! I've modified the code to meet your needs better. PM me if you need help. – NonCreature0714 May 24 '16 at 23:08
  • It is strange your teacher won't allow global constants - those are safe to use. I've not known a teacher yet to discourage them, even in beginning classes. Certainly global variables are unsafe though, and should rarely be used, if ever. I'd ask for some clarification from your teacher on global constants. – NonCreature0714 May 24 '16 at 23:13
  • woah woah woah... How did you declare a function inside of Main()? – vasilescur May 24 '16 at 23:24
  • It's possible (but not recommended) to declare a function inside of main in C++. It's better to declare functions outside of main, so other functions can access each other, but so long as all functions share the same scope, it's okay. – NonCreature0714 May 24 '16 at 23:28