Interview Questions

What is the difference between const char *p, char const *p, and char * const p?

C Interview Questions and Answers


(Continued from previous question...)

What is the difference between const char *p, char const *p, and char * const p?

The first two are interchangeable; they declare a pointer to a constant character (you can't change any pointed-to characters). char * const p declares a constant pointer to a (variable) character (i.e. you can't change the pointer).

The first part of this question can be answered in at least three ways:
1. char *(*(*a[N])())();

2. Build the declaration up incrementally, using typedefs:
typedef char *pc; /* pointer to char */
typedef pc fpc(); /* function returning pointer to char */
typedef fpc *pfpc; /* pointer to above */
typedef pfpc fpfpc(); /* function returning... */
typedef fpfpc *pfpfpc; /* pointer to... */
pfpfpc a[N]; /* array of... */


3. Use the cdecl program, which turns English into C and vice versa. You provide a longhand description of the type you want, and cdecl responds with the equivalent C declaration:
cdecl> declare a as array of pointer to function returning
pointer to function returning pointer to char

char *(*(*a[])())()
cdecl can also explain complicated declarations (you give it a complicated declaration and it responds with an English description), help with casts, and indicate which set of parentheses the parameters go in (for complicated function definitions, like the one above).

C's declarations can be confusing because they come in two parts: a base type, and a declarator which contains the identifier or name being declared, perhaps along with *'s and []'s and ()'s saying whether the name is a pointer to, array of, or function returning the base type, or some combination. For example, in

char *pc;

the base type is char, the identifier is pc, and the declarator is *pc; this tells us that *pc is a char (this is what ``declaration mimics use'' means).

One way to make sense of complicated C declarations is by reading them ``inside out,'' remembering that [] and () bind more tightly than *. For example, given

char *(*pfpc)();

we can see that pfpc is a pointer (the inner *) to a function (the ()) to a pointer (the outer *) to char. When we later use pfpc, the expression *(*pfpc)() (the value pointed to by the return value of a function pointed to by pfpc) will be a char.

Another way of analyzing these declarations is to decompose the declarator while composing the description, maintaining the ``declaration mimics use'' relationship:

*(*pfpc)() is a char
(*pfpc)() is a pointer to char
(*pfpc) is a function returning pointer to char
pfpc is a pointer to function returning pointer to char

If you'd like to make things clearer when declaring complicated types like these, you can make the analysis explicit by using a chain of typedefs as in option 2 above.

The pointer-to-function declarations in the examples above have not included parameter type information. When the parameters have complicated types, declarations can really get messy. (Modern versions of cdecl can help here, too.)

(Continued on next question...)

Other Interview Questions