Reputation: 177
For below sample code;
char* g_commands[]={
"abcd",
NULL
};
int main()
{
g_commands[1] = "efg";
char ** tmp = &g_commands[0];
for(; *tmp != NULL; tmp++){
printf("%s", *tmp);
}
return 0;
}
since tmp is pointing to the pointers in g_commands array in a loop, after I assign "efg" to g_commands[1], I expect the loop create a segmentation fault since the last element of g_commands is not null anymore. But the program finishes without exception and prints abcdefg successfully.
Why is it so? Does the compiler add NULL to the end of char* array as well?
Upvotes: 1
Views: 1397
Reputation: 311048
The program has undefined behavior. In particular it means that a program can produce as an expected or as unexpected result.
I expect the loop create a segmentation fault since the last element of g_commands is not null anymore
The program works without a segmentation fault because the array g_commands
char* g_commands[]={
"abcd",
NULL
};
is defined in the global namespace and there is no other definition of an object after the array. Such a declaration has static storage duration and compilers usually set this memory to zeroes.
If you will move the definition in main like
#include <stdio.h>
/*
char* g_commands[]={
"abcd",
NULL
};
*/
int main()
{
char* g_commands[]={
"abcd",
NULL
};
g_commands[1] = "efg";
char ** tmp = &g_commands[0];
for(; *tmp != NULL; tmp++){
printf("%s", *tmp);
}
return 0;
}
then the probability that a segmentation fault will occur is very high.
Upvotes: 2
Reputation: 15062
I expect the loop create a segmentation fault since the last element of g_commands is not null anymore. But the program finishes without exception and prints abcdefg successfully.
Why is it so? Does the compiler add NULL to the end of char* array as well?
You invoke undefined behavior as you dereference the pointer to pointer tmp
pointing past the end of the array and attempt to printing an indeterminate string with printf("%s", *tmp)
.
Undefined behavior does not need to provide wrong results. It is a misconception to think that things be right when they appear to be right.
You can't expect anything. It also makes no big sense to explain the reasons and ways of undefined behavior as it is plain irrelevant for you writing production code.
I know some people which like to investigate these and seeing the implementation's behavior, but generally seen these aren't things to focus on deeper if you're interested about writing insusceptible, portable and reliable code.
Upvotes: 3
Reputation: 162289
Let's go through it step by step.
char* g_commands[]={
"abcd",
NULL
};
int main()
{
g_commands[1] = "efg";
At this point g_commands
was altered as if you'd initilaized it in the following way:
// char* g_commands[]={
// "abcd",
// "efg"
// };
Note, that there's no longer a terminating null pointer in g_commands
from this point on.
The following
char ** tmp = &g_commands[0];
could have as well been written as
// char ** tmp = g_commands;
Now when you iterate over the elements of g_commands
, you're testing for tmp
dereferencing to a null pointer. Unfortunately you did overwrite the last element of g_commands
with a non-null pointer previously, so this
for(; *tmp != NULL; tmp++){
printf("%s", *tmp);
}
is running beyond the bounds of the array and invoking undefined behavior.
return 0;
}
Upvotes: 0