The const modifier is always a confusing keyword. Here are some of them.

 
const char *
char const *
const char * const
const char * const *
const char * * const
const char * const * const
 

const char * and char const *

They are equivalent, the const modifies the left element, if the const has no left element, means the const is the first key word, then it modifies the right element.

const char * const

Both the pointer and the content pointed by pointer are constant.

const char * const *

This should be divided to two parts:"const char * const" and "*". The first part is the same with the above type.

The second part is a normal pointer, its not constant.

 
#include<iostream>
 
using namespace std;
 
int main () {
    char * str[] = {"hello", "world"};
    const char * const *   parray = str;
 
    parray += 1;// ok
    // parray[0][0] = 'c'; //error
    //parray[0] = "hola";//error
    cout << parray[0] << endl;
    return 0;
}
 

const char * * const

Lets divide it to two parts: "const char * " and " * const". The pointer in the pointer array is mutable, but the content pointed by it is constant.

The pointer to the pointer array is also constant.

 
#include<iostream>
 
using namespace std;
 
int main () {
    char * str[] = {"hello", "world"};
    const char * * const parray = ( const char * * const ) str;
 
    //parray += 1;// error
    // parray[0][0] = 'c'; //error
    parray[0] = "hola";// ok
    cout << parray[0] << endl;
    return 0;
}
 

const char * const * const

The first part is "const char * const", the second part: "* const". All the things are constants.

 
#include<iostream>
 
using namespace std;
 
int main () {
    char * str[] = {"hello", "world"};
    const char * const * const parray = ( const char * const * const ) str;
 
    //parray += 1;// error
    // parray[0][0] = 'c'; //error
    //parray[0] = "hola";// ok
    cout << parray[0] << endl;
    return 0;
}