Array

Array is a collection of individual data with two characteristics:
  1. homogeneous (same type)
  2. referenced by common name and accessed by index (ordered)

If the dimension size is greater than the number of listed elements, the array elements not explicitly initialized are set to 0.
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).

Be aware of bug:
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):

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