While coding a simple function to remove a particular character from a string, I fell on this strange issue:
void str_remove_chars( char *str, char to_remove)
{
if(str && to_remove)
{
char *ptr = str;
char *cur = str;
while(*ptr != '\0')
{
if(*ptr != to_remove)
{
if(ptr != cur)
{
cur[0] = ptr[0];
}
cur++;
}
ptr++;
}
cur[0] = '\0';
}
}
int main()
{
setbuf(stdout, NULL);
{
char test[] = "string test"; // stack allocation?
printf("Test: %s\n", test);
str_remove_chars(test, ' '); // works
printf("After: %s\n",test);
}
{
char *test = "string test"; // non-writable?
printf("Test: %s\n", test);
str_remove_chars(test, ' '); // crash!!
printf("After: %s\n",test);
}
return 0;
}
What I don't get is why the second test fails?
To me it looks like the first notation char *ptr = "string";
is equivalent to this one: char ptr[] = "string";
.
Isn't it the case?
is proper code and creates a mutable string. str is assigned a memory in the heap, the value 'test' filled in it.
Good answer @codaddict.
Also, a
sizeof(ptr)
will give different results for the different declarations.The first one, the array declaration, will return the length of the array including the terminating null character.
The second one,
char* ptr = "a long text...";
will return the length of a pointer, usually 4 or 8.Strictly speaking a declaration of
char *ptr
only guarantees you a pointer to the character type. It is not unusual for the string to form part of the code segment of the compiled application which would be set read-only by some operating systems. The problem lies in the fact that you are making an assumption about the nature of the pre-defined string (that it is writeable) when, in fact, you never explicitly created memory for that string yourself. It is possible that some implementations of compiler and operating system will allow you to do what you've attempted to do.On the other hand the declaration of
char test[]
, by definition, actually allocates readable-and-writeable memory for the entire array of characters on the stack in this case.char *test = "string test";
is wrong, it should have beenconst char*
. This code compiles just because of backward comptability reasons. The memory pointed byconst char*
is a read-only memory and whenever you try to write to it, it will invoke undefined behavior. On the other handchar test[] = "string test"
creates a writable character array on stack. This like any other regualr local variable to which you can write.The two declarations are not the same.
char ptr[] = "string";
declares a char array of size7
and initializes it with the characterss
,t
,r
,i
,n
,g
and\0
. You are allowed to modify the contents of this array.char *ptr = "string";
declaresptr
as a char pointer and initializes it with address of string literal"string"
which is read-only. Modifying a string literal is an undefined behavior. What you saw(seg fault) is one manifestation of the undefined behavior.As far as I remember
creates a copy of
"string"
on the stack, so this one is mutable.The form
is just backwards compatibility for
and you are not allowed (in terms of undefined behavior) to modify it's content. The compiler may place such strings in a read only section of memory.