Recent Changes - Search:

Coding C++

Computing

Container: Native C Array

Trail Index | References and Pointers | C Array

The array is a native C construct, not a proper C++ container. Because of this, it is tightly integrated in the language, is slightly faster than std::vector, and is often used in plain C libraries. The flip side of the coin is that it does not offer the ease, flexibility and safety that std::vector gives.

You will also see some inconsistencies in behaviour, which arise from the underlying implementation. In fact, an array is nothing but a pointer to a memory block, and array indexing is just pointer arithmetics.

/*
 * Containers: Native C Array
 */


#include <iostream>
#include <cstdlib> //this gives you memset and memcpy

/**
 * A simple container for x,y,error
 */

struct DataPoint {
    double x,y,e;
    DataPoint(double _x, double _y, double _e):
        x(_x),y(_y),e(_e) {}
    DataPoint():x(0),y(0),e(0) {}
};

/*
 * a function that uses an array
 */

void listArray(const double array[],int len) {
    for (int i=0;i<len;i++) {
        std::cout<< " "<<i<<") "<<array[i] <<std::endl;
    }
}

/*
* Very badly written function for array,
* that hardcodes the length of the array.
* If the array length is increased, it will
* fail to operate on all of it.
* If the length is decreased, it may cause
* a fatal segfault, or operate on invalid data.
* Never do this!!
*/

void badArrayFunction(double array[]) {
    for (int i=0;i<5;i++) {
        std::cout<< array[i] <<std::endl;
    }
}


/*
 * sizeof() gives the size in memory of a variable
 * but something funny happens in a subroutine,
 * because array[] is actually just a pointer!
 */

void badSize(double array[], int trueLen) {
    std::cout << "badSize: n: "<<trueLen << " sizeof:"<< sizeof(array)
              << " sizeof/sizeof(double):" << sizeof(array)/sizeof(double)<<std::endl;
}

int main() {
        using std::cout;
        using std::endl;
       
    /*
     * basic array declaration:
     * type name[length]
     */

    double valueArray[20];

    /*
     * it is strongly suggested that you put the length
     * of the array in a variable; make sure that it is constant.
     */

    const int nValues=5;
    double values[nValues];

    /*
     * Pay attention: native types like double
     * are not initialized automatically, since they don't have a constructor!
     * You can use memset, but ONLY with zeros!
     * If you put anything else there it will give you something very odd
     * (try and see yourself).
     */

    memset(values,0,sizeof(values));

    /*
     * sizeof() gives the size in memory of a variable
     */

    cout << "main: n: "<<nValues << " sizeof:"<< sizeof(values)
         << " sizeof/sizeof(double):" << sizeof(values)/sizeof(double)<<endl;

    /*
     * but what happens in a subroutine ?
     */

    badSize(values,nValues);


    /*
     * the array does not know how long it is,
     * it's up to you to keep track of that
     */

    cout<< "array size: "<< nValues <<endl;

    for (int i=0;i<nValues;i++) {
        cout<< " "<<i<<") "<<values[i] <<endl;
    }

    /*
     * Calling a function that uses an array
     * you to also need to pass the length information.
     */

    listArray(values,nValues);

    /*
     * very badly written function for array,
     * don't do this
     */

    badArrayFunction(values);


    const int nPoints=10;
    /**
     * the declaration of an array of structure
    * is not different from the declaration for simple types
    */

    DataPoint points[nPoints];
    for (int i=0;i<nPoints;i++) {
        cout<<"point "<<i<<") "<< points[i].x <<endl;
    }

    /*
     * Copying an array.
     * Here it becomes evident what a C array is:
     * just a convention on using pointers
     */


    // first try:
    //double values2[]=values; // error: invalid initializer, initializer fails to determine size of 'values2'

    // second try:
    //double values2[nValues]=values; // error: invalid initializer

    // ok, another try: use a pointer (?)
    double* values2=values;
    // I can use it just like values
    cout<< values2[3] << endl;
    // now modify the original array
    values[3]=4;
    // bad surprise: values2 is not a copy, it's just another name
    // for the same data
    cout<< values2[3] << endl;

    /*
     * so, to copy an array I have to do it explicitly
     */

    double value3[nValues];
    for (int i=0;i<nValues;i++) {
        value3[i]=values[i];
    }
    /*
     * memcpy is a faster way to do it,
     * but see the comments above on sizeof()
     */

    memcpy(value3,values,sizeof(values));
    listArray(value3,nValues);
}

Beware of sizeof(). While it is extremely useful in providing information on the memory size of objects, the logic can be extremely counterintuitive for a beginner.

< References and Pointers | Trail Index | C String >

Edit - History - Print - Recent Changes - Search
Page last modified on February 26, 2009, at 01:23 pm