Omitting Array Size in C++
Implicit Size Determination
C++ allows omitting the array size when an initializer list is provided. The compiler counts the elements and sets the size automatically.
// Compiler sets size = 5
int primes[] = {2, 3, 5, 7, 11};
// Compiler sets size = 3
std::string words[] = {"apple", "banana", "cherry"};
Technical Implementation Details
When the size is omitted:
1. The compiler creates a complete array type with N elements
2. The element count becomes part of the array type
3. The size is fixed at compile time
4. The array cannot be resized or reassigned later
// This declaration:
int arr[] = {1, 2, 3};
// Is equivalent to:
int arr[3] = {1, 2, 3};
Aliases and Typedefs
You can simplify array declarations with aliases, but the bound must be part of the type; alternatively, prefer std::array for safer, modern code.
// Fixed-bound alias
using Row3 = int[3];
Row3 data = {10, 20, 30}; // Size = 3
// std::array (preferred in modern C++)
#include <array>
std::array<float, 2> temps = {98.6f, 99.2f};
Common Use Cases
Use Case | Example | Benefit |
---|---|---|
Lookup tables | const char* colors[] = {"red", "green", "blue"}; | Easier to extend |
Test data | float testCases[] = {1.1, 2.2, 3.3}; | No need to count elements |
String arrays | std::string messages[] = {"Hello", "World"}; | Clear and concise |
Binary buffers | unsigned char header[] = {0x89, 'P', 'N', 'G'}; | Exact binary specification |
Limitations and Considerations
Restrictions when omitting array size:
- An initializer must be provided at the point of declaration
- In function parameters, arrays decay to pointers; 'void func(int param[])' is allowed but size info is lost—use 'void func(int (¶m)[N])' to retain the bound
- Not valid for class member declarations without an explicit size
- Cannot be used with 'new[]' (size must be specified)
- Does not work with 'auto' (use 'std::array' or 'std::to_array')
// Invalid examples:
int arr[]; // Missing initializer
auto arr2[] = {1, 2, 3}; // 'auto' cannot deduce array bound
// Function parameter behavior:
void f(int param[]); // Valid, but decays to int*
void g(int (¶m)[3]); // Keeps bound of 3
Real-World Example: Error Message Lookup
Practical use case: storing error messages without manually specifying array size.
#include <iostream>
using namespace std;
const char* errorMessages[] = {
"Success",
"Invalid input",
"File not found",
"Permission denied",
"Out of memory"
};
const char* getErrorMessage(int code) {
size_t count = sizeof(errorMessages) / sizeof(errorMessages[0]);
if (code >= 0 && code < count) {
return errorMessages[code];
}
return "Unknown error";
}
int main() {
cout << "Error 2: " << getErrorMessage(2) << endl;
return 0;
}
Error 2: File not found