Type Safety and Const ===================== In C and C++ you can declare variables as constants. Such variables must be initialized. After initialization they can never be changed. int x = 42; // Initialize. The value of 'x' can change later. int y; // Uninitialized! y = 42; // Give 'y' a value later. Now with const: const int x = 42; // Constants must be initialized. const int y; // Error! y = 42; // Error! Can't modify a constant. A 'constant expression' is an expression the compiler can evaluate. However, constants don't need to be initialized with constant expressions. On the other hand, a constant that is initialized with a constant expression can be used in other constant expressions. // Define this in one place for easy modification. #define MAX_LINE_SIZE 100 int f( int a ) { const int x = a + 1; // Initialized differently each time 'f' is called. const int y = 42/2 + 1; // Initialized with a constant expression. const int z = y + 1; // Initialized with a constant expression. const int w = x + 1; // Okay... but 'w' is not a constant expression. const int v = MAX_LINE_SIZE/2 + 1; // Initialized with a constant expression. // Arrays are dimensioned using constant expressions (no variable sized arrays). int array1[y]; // Okay. Compiler knows the value of y. int array2[x]; // Error! Compiler does not know the value of x. int array3[z]; // Okay. Compiler knows the value of z. int array4[w]; // Error! Compiler does not know the value of w. int array5[v]; // Okay. Compiler knows the value of v. // But you should be using vectors anyway!! } Const interacts with pointers in a rich way: const char *p1; // Pointer to a const. The pointer is not a constant! char *const p2 = ...; // Constant pointer to a non-constant. This must be initialized! const char *const p3 = ...; // Constant pointer to a constant. p1 = ... // Okay to change p1 (it's not constant). *p1 = ... // Error! Can't modify a constant. p2 = ... // Error! Can't modify a constant. *p2 = ... // Okay to change *p2 (it's not a constant). Now consider this: char *a; const char *b; ... b = a; // Okay! a = b; // Error! Can't copy a (pointer to constant) to a (pointer to non-constant) *a = 'x'; // Otherwise... this would compile, but would be modifying a constant! References work in an analogous way: int max( const int &x, const int &y ) { // 'x' and 'y' are constants here. Can't be modified. if( x > y ) return x; else return y; } int main( ) { const int a = 10, b = 20; int c = 10, d = 20; int z; z = max( a, b ); // Okay. Types match. z = max( c, d ); // Okay. Can bind a reference-to-const to a non-constant. } But now look at this: void swap( int &x, int &y ) { int temp = x; x = y; y = temp; } int main( ) { const int a = 10, b = 20; int c = 10, d = 20; swap( c, d ); // Okay. Types match. swap( a, b ); // Error. Can't bind a reference-to-non-const to a constant object. } If the last line was allowed, swap would be modifying constants! Consider the following function from the C standard library char *strchr( const char *s, int ch ); This function takes a pointer to a null terminated string of characters and a specific character. It searches the string pointed at by s looking for ch and returns a pointer to the first occurrence of ch in the string. It returns the null pointer if ch can't be found. The problem with this function is that it takes a pointer to const and it returns a pointer to non-const. Consider this example: void f( ) { const char s[] = "Hello"; char *p; p = strchr( s, 'e' ); // Search s for 'e'. *p = 'x'; // Replace 'e' with 'x'. } Code like this compiles! All the types match just fine. Yet the program is attempting to modify a constant character since the array 's' is an array of constants. By the way, the initialization of 's' shows no size for the array. The compiler counts the number of characters in the initializer and uses that size (plus one for the terminating null byte). You might say the problem here is that the C standard library declaration of strchr is wrong. It should have been const char *strchr( const char *s, int ch ); This preserves the "const-ness" of the parameter in the return value. In fact, this fixes the example above. The assignment to p is flagged as an error since p is a plain char*. You need to declare p like this: const char *p; But then the assignment to *p is flagged as an error because it attempts to modify a constant. By the way in the declaration above it is not necessary to initialize p because it is not p that is constant. It's the thing p points at that is constant. If you want to declare a const pointer (as opposed to a pointer to const) you need to say char *const p = // ... must initialize a constant. And, yes, you can declare const pointers to const: const char *const p = // ... must initialize a constant. Anyway, the problem with putting const in the return type of strchr is that it causes this perfectly reasonable program to become illegal void f( char *s ) { char *p = strchr( s, 'e' ); if( p != NULL ) { *p = 'x'; // Replace 'e' with 'x' } } In this case I'm trying to modify a character in a non-const array of characters. Yet if strchr returned a pointer to const this would not be possible. C has no solution to this problem. The declaration in the library is a type safety hole. It is possible to use strchr to accidentally strip off const-ness from a character and then subsequently attempt to modify a constant. In C++ this problem is fixed using function overloading. In C++ you can declare multiple functions with the same name in the same scope provided they have "sufficiently" different parameter lists. So in the C++ library there is char *strchr( char *s, int ch ); const char *strchr( const char *s, int ch ); The only difference in the parameter lists is the use of const in the second case but it turns out this is different enough. Notice also that the return type uses const in a corresponding way. Even though it is permitted to pass a pointer to non-const where a pointer to const is expected, the compiler will still favor the first function above for pointers to non-const. It will only use the second function when necessary: when the argument is a pointer to a const. In that case the return type is also a pointer to const and the const-ness is not lost. This is a nice example of how C++ features work in combination to provide a stricter, safer programming environment than C does.