Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is an array of constant pointers in C?

Isn't the address of an array and thus of all its elements as well constant anyway?

And if so, in a declaration like:

char *const argv[] 

isn't the const qualifier redundant?

like image 349
Lavya Avatar asked Mar 31 '14 13:03

Lavya


2 Answers

No, the const in char *const argv[] is not redundant.

First, const and "constant" are actually two different things in C, even though the const keyword is obviously derived from the word "constant". A constant expression is one that can be evaluated at compile time. const really means "read-only". For example:

const int r = rand();

is perfectly legal.

Yes, the address of an array -- like the address of any object -- is read-only. But that doesn't mean that the value of the array (which consists of the values of its elements) is read-only, any more than any other object is necessarily read-only.

Consider these three declarations:

char *arr1[10];
char *const arr2[10];
const char *arr3[10];

arr1 is a 10-element array of pointers to char. You can modify the char* elements and you can modify the objects that those elements point to.

arr2 is an array of const (read-only) pointers to char. That means that you can't modify the char* elements of the array (once they're initialized) -- but you can still modify the char objects or arrays that those elements point to.

And arr3 is an array of pointers to const char; you can modify the array elements, but you can't modify what they point to.

Now the fact that you used the name argv suggests that you're talking about the second parameter to main, which has some huge effects on this. The language specifies that main's second parameter is

char *argv[]

or, equivalently,

char **argv

There is no const. You can probably get away with adding one, but it's best to follow the form specified by the standard. (Update: I see from your comment that you're asking about the argv parameter of getopt(), which is defined as char * const argv[].)

And since it's a parameter defined as an array, another rule comes into play: a parameter defined as an array of some type is "adjusted" to a pointer to that type. (This rule applies only to parameters.) This isn't a run-time conversion. A function cannot have a parameter of array type.

The relationship between arrays and pointers in C can be confusing -- and there's a lot of misinformation out there. The most important thing to remember is that arrays are not pointers.

Section 6 of the comp.lang.c FAQ is an excellent explanation of the details.

like image 96
Keith Thompson Avatar answered Oct 02 '22 14:10

Keith Thompson


Isn't the address of an array and thus of all its elements as well constant anyway?

Yes, and it is true for any object in C. Recall that by object here, we mean a location in memory having a value and referenced by an identifier. The identifier is bound to a fixed memory location throughout its scope and you cannot change it. You can change the value of the object though.

int a = 4;
a = 6;  // legal. you can change the value of the object
&a = 23456; // illegal. you cannot change the address of the object

Similarly, an array is also an object and each of its elements will have a fixed memory address. However, the value held by an element of the array has nothing to do with the address of the element.

Note that if the declaration appears in a function parameter list, then the following are equivalent

char *const argv[]
char *const *argv

which means that argv is a pointer to an object which is of type char *const, i.e., a constant pointer to a character. It's obvious that char *const *argv and char **argv are different. So let's take another example.

char *const argv[10];

The above statement defines argv to be an array of 10 constant pointers to a character. This means that you have to initialize the array and cannot later change the pointers to point to a different character. However, this has nothing to do with the address of the array elements.

char c = 'A';
char d = 'B';
char *const argv[2] = {&c, &d}; 

argv = &c; // illegal. you cannot the change the address of an object
argv[0] = &d; // illegal. you cannot change the value of the array element
*argv[0] = 'C'; // legal. you change the value pointed to by the element

Without the const qualifier, char *argv[2] means an array of 2 pointers to characters. This is clearly different from the case when we have the const qualifier as explained above. Therefore, to answer your second question, no, the const qualifier is not redundant. That's because the const qualifier qualifies the type of the array elements.

like image 38
ajay Avatar answered Oct 02 '22 14:10

ajay