Here are 6 scenarios where using C-style arrays has unexpected behavior (or simply doesn't work at all):
#include <cstddef>
#include <iostream>
#include <array>
#include <type_traits>
#define USE_STD_ARRAY 0
#if USE_STD_ARRAY
using array3i = std::array<int, 3>;
#else
using array3i = int[3];
#endif
#if USE_STD_ARRAY // these portions are disabled because they don't compile when using C-style arrays
// 1.
// C-style arrays cannot be returned from functions
array3i functionReturningArray() {
array3i a = {1, 2, 3};
return a;
}
#endif
// 2.
// Can C-style arrays be passed by value?
void fun(array3i array) {
array[0] = 42;
}
void test2() {
array3i a = {1, 2, 3};
fun(a);
std::cout << a[0] << std::endl; // wrong result
// The array a is now {42, 2, 3}, because the function operates
// on the actual array, not on a copy of it. C-style arrays
// can never be passed by value.
}
// 3.
// C-style arrays as function arguments look exactly the same
// as variables of array type, but they secretly are pointers:
int sum(array3i array) {
int sum = 0;
size_t size = sizeof(array) / sizeof(array[0]);
// Wrong: sizeof(array) is the same as sizeof(int*)
for (size_t i = 0; i < size; i++)
sum += array[i];
return sum;
}
void test3() {
array3i a = {1, 2, 3};
int res = sum(a);
std::cout << res << std::endl; // wrong result
}
#if USE_STD_ARRAY
// 4.
// C-style arrays cannot be assigned or copied like normal variables.
void test4() {
array3i a = {10, 20, 30};
array3i b = a; // error
}
#endif
#if USE_STD_ARRAY
// 5.
// C-style array members of a class or struct cannot be initialized
// in the constructor:
struct S {
array3i a;
S(const array3i &a)
: a(a) {} // error: array used as initializer
};
#endif
// 6.
// C-style arrays implicitly decay to pointers to the first element,
// they don't follow the usual value semantics.
void test6() {
array3i a = {1, 2, 3};
auto b = a;
if (std::is_same<decltype(b), int *>::value)
std::puts("b is a pointer to int?!");
}
int main() {
test2();
test3();
test6();
}
(Compile using g++ -std=c++11 file.cpp)
If you set #define USE_STD_ARRAY 1, everything works as expected.
What do you mean? Of course you can index a std::array:
#include <array>
#include <iostream>
int main() {
std::array<int, 3> arr = {1, 2, 3};
int third_element = arr[2];
std::cout << third_element << std::endl; // 3
arr[0] = 42;
std::cout << arr[0] << std::endl; // 42
}
An array is a common concept, and I would argue that std::array matches the array/list/vector types in other languages more closely than C-style arrays with their quirks.
To be absolutely clear, std::array is a drop-in replacement for C-style arrays, but without the weird behavior demonstrated in the code I posted at the top of this reply.