int ia1[5] = { 0, 1, 2 }; // ia1 = { 0, 1, 2, 0, 0 };
int ia2[4][3] = { 0, 3, 6, 9 };
// ia2 = { { 0, 3, 6 }, { 9, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } };
int ia3[4][3] = { {0}, {3}, {6}, {9} };
// ia3 = { { 0, 0, 0 }, { 3, 0, 0 }, { 6, 0, 0 }, { 9, 0, 0 } };
ia[1, 2] is a legal construct, but is equivalent to
ia[2] because 1,2 is evaluated as a comma
expression.
The array name by itself stands for a constant
pointer to its first element,
array = &(array[0]). So array name itself only has
rvalue: refers to address of beginning of array and cannot be
changed. Pointer also has an lvalue: it is allocated and
can be set to address of other memory content with same
data type.
rvalue is variable's data value, might think as meaning read value; lvalue is variable's memory address value, might think as meaning location value. In general, the left-hand side of an assignment operator always requires an lvalue.
sizeof array return number of bytes of the whole
array, but sizeof pointer means
sizeof(pointertype*). Idiom for determining
number of elements in an array does not work for pointer:
arraytype array[ARRAYNUM]; size_t arraynum = sizeof array / sizeof array[0];Accesing each element of multi-dimensional array
tabletype table[ROWNUM][COLNUM];
size_t rownum = sizeof table / sizeof table[0];
size_t colnum = sizeof table[0] / sizeof table[0][0];
// This do not work when tested, will revise later
// if each row is aligned with unknown padding
for (tabletype **row=table, size_t i=0; i<rownum; i++, row++)
{
for (tabletype *elem=*row, size_t j=0; j<colnum; j++, elem++)
{
// access each element as *elem
}
}
// if no padding (contiguous)
for (tabletype *elem=&table[0][0], size_t i=0; i<rownum; i++)
{
for (size_t j=0; j<colnum; j++, elem++)
{
// access each element as *elem
}
}
An exception in C/C++, passing array is by reference by default.
Array is not pointer, but array decays to pointer when passed as
parameter to a function. No bound checking for array parameter,
returntype Function(arraytype array[ARRAYNUM]) is
equal to returntype Function(arraytype array[]) or
returntype Function(arraytype *array).
int GetLoginNameFromUser(char buffer[])
{
int result = 0;
if (fgets(buffer, sizeof buffer, stdin) == NULL)
result = -1;
return result;
}
The bug occurs because sizeof buffer becomes
sizeof(char*) but not length of array as expected,
as char buffer[] decays to char *buffer.
This is why need to pass length of array as extra argument to
function for manipulating the array.
arraytype array[ARRAYNUM]; // ARRAYNUM is allocated size // arraynum can be ARRAYNUM, or <ARRAYNUM if array is not // fully utilized, which is effective size returntype Function(arraytype array[], size_t arraynum);To pass array to function without extra argument (but limit to fixed type and fixed size array):
typedef struct {
arraytype a[ARRAYNUM];
} Array;
returntype Function(Array *array)
{
// statements ...
for (int i=0; i<(sizeof array->a / sizeof array->a[0]); i++)
{
// access array element as array->a[i]
}
// statements ...
}
returntype Function(arraytype (&a)[ARRAYNUM])
{
// statements ...
for (int i=0; i<ARRAYNUM; i++)
{
// access array element as a[i]
}
// statements ...
}
Using template to eliminate predefined constant,
but introduce code bloat (different definition
for different type and size of array)
template <typename arraytype, int arraynum>
returntype Function(arraytype (&a)[arraynum])
{
// statements ...
for (int i=0; i<arraynum; i++)
{
// access array element as a[i]
}
// statements ...
}
// usage in application
int ia[] = { 10, 7, 14, 3, 25 };
returntype r = Function(ia); // arraytype=>int, arraynum=>5
template <typename arraytype, int arraynum>
class Array {
public:
Array(arraytype* array)
: arraynum_(arraynum)
{
for (int i=0; i<arraynum; i++)
array_[i] = array[i];
}
private:
arraytype array_[arraynum];
int arraynum_;
};
// usage in application
int ia[] = { 10, 7, 14, 3, 25 };
Array<int, sizeof(ia)/sizeof(int)> iA(ia);
The best way is defining array as a class, which can also
provide bound checking, IO and many other features
(actually no need the arraynum template
argument, example above is for illustration only).
#include <iostream>
const int LineLength = 12; // elements to a line
void PrintArray(const arraytype *a, size_t size)
{
cout << "( " << size << " ) < ";
for (int i=0; i<size; i++)
{
if (i%LineLength == 0 && i != 0)
cout << "\n";
cout << a[i];
if (i%LineLength != LineLength-1 && i != size-1)
cout << ", ";
}
cout << " >";
}
Index