3

I am trying to write a program in C++ that will accept a message from a client on a server. But first of all the client sends the size of the message and using this value the server will create an array of chars to store the message when it is finally sent. When I try to initialise the array using the message size value the compiler says that there is an error as the messageSize integer must be a constant value - I was wondering why this is happening, because as far as I understand it is quite acceptable to initialise the length of an array with an integer type:

//Deal with data in DNS style
int dnsStyle()
{   
    recv(clientSocket, bufferSize, 1, MSG_WAITALL);
    return bufferSize[0];
}

//Communicate in the DNS style of addressing
char DNS()
{
    int messageSize = dnsStyle();
    printf("The message buffer has been tailoured to this size: '%d'", messageSize);
    char bufferMessDNS[messageSize];
    //Then recieve the actual message itself
    recv(clientSocket, bufferMessDNS, messageSize, MSG_WAITALL);
    //Then send the message back to client
    send(clientSocket, bufferMessDNS, messageSize, 0);

    //std::string returnMess = "OK";
    //send(clientSocket, sendBack.c_str(), sendBack.size(),0);
}
crashmstr
  • 28,043
  • 9
  • 61
  • 79
Enchanter
  • 117
  • 1
  • 10

5 Answers5

3

In C++ -- and, mind you we're talking about conformant C++ with no extensions -- an automatic array is allocated with a size known at compile time, because the size of the array must be known at compile time.

Therefore, this code:

char bufferMessDNS[messageSize];

Is ill-formed because messageSize can change.

If you need an array of varying size, use a vector <char>.

You can make the code above work if you make messageSize a so-called Integral Constant Expression, like this:

const size_t messageSize = 256;
char bufferMessDNS[messageSize];

But here the size of the buffer is always exactly 256 bytes -- which I'm sure will almost never be the right size.

You can also, if you must, use a dynamically-sized array using new[]:

char* bufferMessDNS = new char [messageSize]

But this opens up a whole kettle of new problems, not the least of which is managing ownership of the memory you just allocated. Now you have to delete that:

delete [] bufferMessDNS;
John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • I think I will go with the dynamically-sized array as it uses the same structure and means only minor changes have to made to the code. Thanks. – Enchanter Oct 14 '13 at 18:25
2

To expand on John Diblings answer, you should use an std::vector<char> as your buffer. This is how it works:

char DNS()
{
    std::vector<char>::size_type messageSize = dnsStyle(); // use correct type
    printf("The message buffer has been tailoured to this size: '%d'", messageSize);
    std::vector<char> bufferMessDNS(messageSize); // create vector with correct size
    //Then recieve the actual message itself
    recv(clientSocket, &bufferMessDNS[0], messageSize, MSG_WAITALL);
    //Then send the message back to client
    send(clientSocket, &bufferMessDNS[0], messageSize, 0);

    //std::string returnMess = "OK";
    //send(clientSocket, sendBack.c_str(), sendBack.size(),0);
}

The most important part here is to initialize the std::vector with the correct size by calling the constructor that takes a size_type as parameter. To pass the buffer to revc you just have to take the address of the first element of the std::vector.

Community
  • 1
  • 1
Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • +1 - Thanks. I'm not going to incorporate your answer in to mine because I'd just be plagarizing & you deserve the rep for it. – John Dibling Oct 11 '13 at 19:49
  • Why not just `size_t messageSize`? That's what recv/send want anyway. – Roddy Oct 11 '13 at 21:17
  • The constructor of `std::vector` expects an `std::vector::size_type`. – Björn Pollex Oct 11 '13 at 21:20
  • It is good to be reminded of the felxibility of vectors compared to arrays - the only issue with this and correct me if I'm wrong but when the message is recieved and then again sent, you are putting the whole message in the first position of the vector so I suppose is there any point in creating a vector of length messageSize when you only really to make it length 1? – Enchanter Oct 14 '13 at 18:28
  • You misunderstand. A `vector` with size `n` holds `n` chars contiguously in memory. Since C-APIs like `recv` and `send` only accept a `char *` we pass in the address of the first element of the vector. This works because `vector` guarantees that the memory layout is the same like that of a plain array. – Björn Pollex Oct 15 '13 at 07:10
0

You should declare an array only with a size that can be interpreted at compile time. i.e, it should be a int literal (char bufferMessDNS [100]) or using a macro (like #define MSG_SIZE 100) or a const int.

For your purpose, since you;ll know the size only during run time you can go for

char *bufferMessDNS = new char[messageSize];
....
delete []bufferMessDNS
theAlias
  • 396
  • 1
  • 14
0

The problem is, that the compiler needs to know the size of all variables created on the stack at compile time -> you can only allocate array of size known at compile time

If the size is known during runtime only, you can use dynamic memory allocation. I.e:

char bufferMessDNS[messageSize];
// replace with
char* bufferMessDNS = new char[messageSize];

// and at the end of your function don't forget to release the memory
delete[] bufferMessDNS;

For detailed answer why the compiler must know the size of stack variables at compile time, see this post: Why does a C/C++ compiler need know the size of an array at compile time?

Community
  • 1
  • 1
jozef
  • 1
  • 1
-1

Is this a very strict C compiler? maybe you simply need to separate your declaration from your initialization?

int messageSize;
messageSize = dnsStyle();
Rob Latham
  • 5,085
  • 3
  • 27
  • 44