I am bit confused when to allocate memory to a char * and when to point it to a const string.
Yes, I understand that if I wish to modify the string, I need to allocate it memory.
But in cases when I don't wish to modify the string to which I point and just need to pass the value should I just do the below? What are the disadvantages in the below steps as compared to allocating memory with malloc
?
char *str = NULL; str = "This is a test"; str = "Now I am pointing here";
As was indicated by others, you don't need to use malloc just to do: const char *foo = "bar"; The reason for that is exactly that *foo is a pointer — when you initialize foo you're not creating a copy of the string, just a pointer to where "bar" lives in the data section of your executable.
The char type takes 1 byte of memory (8 bits) and allows expressing in the binary notation 2^8=256 values. The char type can contain both positive and negative values.
You delete (or delete[]) it when you longer need it and when it points to a char object that you created with new or new[]. You shouls delete/free only if it created with new/malloc, not if it is created on the stack.
In C, the RAM should use the following code to allocate the two-dimensional array: *contents = (char**) malloc(sizeof(char*) * numRows); **contents = (char*) malloc(sizeof(char) * numColumns * numRows); for(i = 0; i < numRows; i++) (*contents)[i] = ( (**contents) + (i * numColumns) );
Let's try again your example with the -Wwrite-strings
compiler warning flag, you will see a warning:
warning: initialization discards 'const' qualifier from pointer target type
This is because the type of "This is a test" is const char *
, not char *
. So you are losing the constness information when you assign the literal address to the pointer.
For historical reasons, compilers will allow you to store string literals which are constants in non-const variables.
This is, however, a bad behavior and I suggest you to use -Wwrite-strings
all the time.
If you want to prove it for yourself, try to modify the string:
char *str = "foo"; str[0] = 'a';
This program behavior is undefined but you may see a segmentation fault on many systems. Running this example with Valgrind, you will see the following:
Process terminating with default action of signal 11 (SIGSEGV) Bad permissions for mapped region at address 0x4005E4
The problem is that the binary generated by your compiler will store the string literals in a memory location which is read-only. By trying to write in it you cause a segmentation fault.
What is important to understand is that you are dealing here with two different systems:
The C typing system which is something to help you to write correct code and can be easily "muted" (by casting, etc.)
The Kernel memory page permissions which are here to protect your system and which shall always be honored.
Again, for historical reasons, this is a point where 1. and 2. do not agree. Or to be more clear, 1. is much more permissive than 2. (resulting in your program being killed by the kernel).
So don't be fooled by the compiler, the string literals you are declaring are really constant and you cannot do anything about it!
Considering your pointer str
read and write is OK. However, to write correct code, it should be a const char *
and not a char *
. With the following change, your example is a valid piece of C:
const char *str = "some string"; str = "some other string";
(const char *
pointer to a const string)
In this case, the compiler does not emit any warning. What you write and what will be in memory once the code is executed will match.
Note: A const pointer to a const string being const char *const
:
const char *const str = "foo";
The rule of thumb is: always be as constant as possible.
If you need to modify the string, use dynamic allocation (malloc() or better, some higher level string manipulation function such as strdup, etc. from the libc), if you don't need to, use a string literal.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With