I have the following program.
#include <stdio.h>
int main(int argc, char const * const argv[], char const * const * envp) {
for (int i = 0; i < argc; i++) {
printf("argv[%d]: %s\n", i, argv[i]);
}
printf("\n");
for (int i = 0; *envp != NULL; i++, envp++) {
printf("envp[%d]: %s\n", i, *envp);
}
return 0;
}
This compiles as expected with no warnings.
If I make the envp pointer const, by changing its declaration to the following.
char const * const * const envp
Then compilation fails as follows.
$ gcc -Wall main.c
main.c: In function ‘main’:
main.c:9:45: error: increment of read-only parameter ‘envp’
9 | for (int i = 0; *envp != NULL; i++, envp++) {
|
This makes sense to me: In this program we can declare that the (first and only first?) character value of each environment string is a constant, we can declare that each pointer to each environment string is constant, but we cannot declare that the char** envp is a constant.
Now, my question is, how could I declare the array variable argv a constant in a similar way, so that argv cannot be reassigned?
That is, I want to declare argv in a such a way that the following would produce a similar compilation error to the "read-only parameter ‘envp’" error above. I want the following to fail to compile. As is, the following compiles.
#include <stdio.h>
int main(int argc, char const * const argv[], char const * const * envp) {
char const * const argvbad[1] = { NULL };
argv = argvbad; // I want this to be impossible
for (int i = 0; i < argc; i++) {
printf("argv[%d]: %s\n", i, argv[i]);
}
printf("\n");
for (int i = 0; *envp != NULL; i++, envp++) {
printf("envp[%d]: %s\n", i, *envp);
}
return 0;
}
This is a question about array variables in general. I want to learn how to declare array variables as constant, so that the array that they refer to cannot be reassigned.
In a parameter declaration, an array can be declared with qualifiers such as
constinside the brackets,[and]:When the declaration is automatically adjusted to make the declared identifier be a pointer, the qualifiers will be applied to it. The above is equivalent to
void foo(const char * const * const argv).Note that
int main(int argc, char const * const argv[], char const * const * envp)is not generally appropriate formainbecause the C standard specifies the forms that the declaration ofmainshould take, in C 2018 5.1.2.2.1 1. Its specification is flexible in that it allows implementations to accept additional forms, but I am not aware of any implementation documenting thatmainmay have that form, with the additional qualifiers.An additional complication is that qualifiers on parameters, directly, are irrelevant for function compatibility. For example, these are compatible declarations:
This is because C 2018 6.7.6.3 15 says:
However, these would not be compatible:
since the above passage applies only to qualifiers directly on the parameters. This raises the possibility that
int main(int argc, char *argv[const])is a satisfactory declaration ofmainper C 2018 5.1.2.2.1 1, since it is compatible withint main(int argc, char *argv)and hence may satisfy its allowance of “equivalent” declarations.