Comparing C arrays with std::array
from C++. Both are fundamental types used for storing sequences of objects, but they have some key differences:
-
Basic Definition: A C array is a collection of items of the same type, stored in contiguous memory locations. It is a low-level construct with no built-in bounds checking or safety features.
-
Size Flexibility: The size of a C array must be known at compile time if it's a static array, or it can be dynamically allocated. However, the size is not a part of the type.
-
Memory Management: Requires manual management if dynamically allocated (using
malloc
/free
). No automatic memory management is provided. -
Safety and Convenience: Provides minimal safety. It does not keep track of its own size, leading to potential buffer overflows and related issues. There's also no direct support for high-level operations like iteration, copying, comparison, etc.
-
Performance: Very efficient in terms of performance as it is a simple data structure with direct memory access.
-
Basic Definition:
std::array
is a container that encapsulates fixed size arrays. It’s part of the C++ Standard Library. -
Size Flexibility: The size of
std::array
must be known at compile time and is part of its type. This makes it safer but less flexible in terms of size variability. -
Memory Management: As part of the C++ Standard Library, it handles memory automatically and is typically stack-allocated.
-
Safety and Convenience: Provides more safety features like bounds checking (when using
.at()
method), size awareness, and compatibility with C++ Standard Library algorithms. It supports iterators, range-based for loops, and can be easily copied or compared. -
Performance: Offers performance comparable to raw arrays but with added benefits of modern C++ features.
- Use C Array when: You need minimal overhead, are working in a C or low-level context, or when dynamic size arrays are necessary.
- Use std::array when: You are working in C++ and need a fixed-size array with modern language features, safety, and ease of use.
While std::array
brings many advantages of modern C++, especially in terms of safety and ease of use, C arrays are still relevant for low-level or performance-critical tasks where the overhead of higher-level abstractions is undesirable.
int array[] = { 1, 2, 3, 4, 5 };
std::cout << "sizeof(array)="<<sizeof(array)<<std::endl; // prints 20 (5 elements * 4 bytes each)
const int number_of_elemenets = sizeof(array)/sizeof(int);
std::cout << "number of elemenets = "<<number_of_elemenets<<std::endl;
These are equal:
array<=>&array[0]
array+index<=>&array[index]
getting elements:
std::cout<<"*array="<< *array<<std::endl;
std::cout<<"*(array+2)="<< *(array+2)<<std::endl;
for (int* p = array; p != array+number_of_elemenets; p++)
{
std::cout << *p << std::endl;
}
C
does not have true multidimensional arrays. you can have arrays of arrays, so like
int first2DArray[3][5] ={
{ 1, 2, 3, 4, 5, }, // row 0
{ 6, 7, 8, 9, 10, }, // row 1
{ 11, 12, 13, 14, 15 } // row 2
};
Two-dimensional arrays with initializer lists can omit (only) the first size dimension(the most left one):
int second2DArray[][5] ={{ 1, 2, 3, 4, 5, },{ 6, 7, 8, 9, 10, },{ 11, 12, 13, 14, 15 }};
or
int **array;
array=new int *[3];
array[0]=new int[2];
array[1]=new int[4];
array[2]=new int[3];
array[0][0]=1;
array[0][1]=0;
array[1][0]=5;
array[1][1]=4;
std::cout<<array[1][1] <<std::endl;
delete[] array[0];
delete[] array[1];
delete[] array[2];
delete[] array;
int my3DArray[2][3][2] ={
{{1, 2},{3, 4},{5, 6}},
{{7, 8}, {9, 10}, {11, 12}}
};
- Fixed Size: it works for automatic (usually stack-living) arrays only i.e. the dimensions should be known at compile time.
The parameter is a 2D array, you have to specify the size of all dimension except the first one.
this one expect exactly 3x4:
void foo(int a[4][3])
{
}
we can omit (only) the first size dimension(the most left one)
void foo(int a[][3], int size)
{
}
- Variable Size
a pointer to the decayed type:
void foo(int *a[10], int size)
{
}
int *array[10];
for(int i = 0; i < 10; i++)
array[i] = new int[10];
void foo(int *a[10])
{
}
foo(array);
pointer to a pointer:
void foo(int **a, int m, int n)
{
}
int **pp_array;
int m, n;
m=4;
n=5;
pp_array = new int *[n];
for(int i = 0; i <m; i++)
pp_array[i] = new int[n];
or
int first2DArray[3][5] ={
{ 1, 2, 3, 4, 5, }, // row 0
{ 6, 7, 8, 9, 10, }, // row 1
{ 11, 12, 13, 14, 15 } // row 2
};
foo((int**)&first2DArray[0][0], 3, 5);
Refs: 1
std::array
is a container that encapsulates fixed size arrays.
std::array<int, 3> a2 = {1, 2, 3};
std::array<std::string, 2> a3 = { std::string("a"), "b" };
container operations are supported:
std::sort(a2.begin(), a2.end());
std::reverse_copy(a2.begin(), a2.end(), std::ostream_iterator<int>(std::cout, " "));
to_array:
std::to_array("foo"); // creates std::array<char, 4>{ 'f', 'o', 'o', '\0' }
std::array{"foo"}; // creates std::array<const char*, 1>{ +"foo" }
checking is array:
char *s = "Behnam";
std::cout << std::boolalpha;
std::cout << std::is_array<Foo>::value << '\n';
std::cout << std::is_array<Foo[]>::value << '\n';
std::cout << std::is_array<Foo[3]>::value << '\n';
std::cout << std::is_array<float>::value << '\n';
std::cout << std::is_array<int>::value << '\n';
std::cout << std::is_array<int[]>::value << '\n';
std::cout << std::is_array<int[3]>::value << '\n';
std::cout << std::is_array<std::array<int, 3>>::value << '\n';