Why can I change the value of a const char* variable? - c

Why does the following code in C work?
const char* str = NULL;
str = "test";
str = "test2";
Since str is a pointer to a constant character, why are we allowed to assign it different string literals? Further, how can we protect str from being modified? It seems like this could be a problem if, for example, we later assigned str to a longer string which ended up writing over another portion of memory.
I should add that in my test, I printed out the memory address of str before and after each of my assignments and it never changed. So, although str is a pointer to a const char, the memory is actually being modified. I wondered if perhaps this is a legacy issue with C?

You are changing the pointer, which is not const (the thing it's pointing to is const).
If you want the pointer itself to be const, the declaration would look like:
char * const str = "something";
or
char const * const str = "something"; // a const pointer to const char
const char * const str = "something"; // same thing
Const pointers to non-const data are usually a less useful construct than pointer-to-const.

Further, how can we protect str from being modified?
char * const str1; // str1 cannot be modified, but the character pointed to can
const char * str2; // str2 can be modified, but the character pointed to cannot
const char * const str3 // neither str3 nor the character pointed to can be modified.
The easiest way to read this is to start from the variable name and read to the left:
str1 is a constant pointer to a character
str2 is a pointer to a character constant
str3 is a constant pointer to a character constant
NOTE: the right-to-left reading does not work in the general case, but for simple declarations it's a simple way to do it. I found a java applet based on code from "The C Programming Language" that can decipher declarations with a full explanation of how to do it.

On a related note, definitely take a look at "const pointer versus pointer to const". It helps with what some people call const correctness. I keep it in my bookmarks so that I can refer to it every now and then.

What you're looking for may be the syntax...
const char* const str = NULL;
str = "test";
str = "test2";
Notice the "const" after the char* which yields a compiler error when trying to compile/build.

Memory for the string literals are allocated on the stack, and all your assignments do are change the str pointer to point to those memory addresses. The constant character it pointed to initially hasn't changed at all.

Besides, declaring a variable as const means that variable is read-only; it does not mean the value is constant!

Related

Trying to copy a string into a const char * array in C

I am trying to convert a string in C (using the string.h library) into a const char array.
int len = sizeof(the_string);
const char *char_array = malloc(len);
strcpy(char_array, the_string);
I have pored through the string.h method file and googled it but things keep coming up in C++. Any advice would be greatly appreciated, thank you!!!
This declaration of a pointer
const char *char_array;
means that you may not change the memory pointed to by the pointer using the pointer.
You could make the pointer itself a constant object like
char * const char_array = malloc( some_size );
In this case you may not reassign the pointer itself but you may change the memory pointed to by the pointer.
Take into account that the expression sizeof(the_string) does not make a great sense if you are going to know the length of a string stored in a character array because in general a character array can be much larger than the stored string in it. Instead you should write
size_t len = strlen( the_string );
Using the expression sizeof(the_string) makes a sense in declarations such this
char the_string[] = "Hello";
that is when the size of a character array is determined by the size of a string literal used as an initializer.

Dereferencing a character pointer in C

Here is my code:
char *str = malloc(100*sizeof(char));
*str ="Hello"; // or pass it any string
Now I want to pass str in the function:
sys_open(const char * filename, int flags, int mode)
When I use a char array as the second parameter, it works, but using the pointer whose value was copied over does not work.
I can achieve what I want with a char array, but why can't I do the same with a pointer?
You can't assign strings that way in C. You'll need to use strcpy(3) or one of its relatives.
There are a few things wrong:
*str = "Hello"; // or pass it any string
str is char*, *str is a char, and "Hello" is a const char* (well, actually const char[6] that decays into const char*). It's illegal to assign a const char* to a char.
Assuming you meant str = "Hello";, that's still wrong because it's reassigning the pointer str to point to the string literal "Hello". The memory you previously allocated with malloc now has nothing pointing to it, and you've leaked memory.
Passing str to sys_read as you're doing won't work. str is pointing to a string literal not to the writable memory that you've allocated. Not only will the count be wrong, but sys_read won't be able to write to it at all. (String literals are immutable, and attempting to modify one will result in undefined behavior.)
In the program, I feel that there is a type-cast missing as malloc returns a void * and assigning the same to char * gives an error.

How to change a character in a string using pointers?

im having troubles with this code
int main() {
char *My_St = "abcdef";
*(My_St+1)='+';
printf("%s\n",My_St);
return 0;
}
i built this code and has no errors, but when i try to run it, it throws a segmentation fault, could someone tell what's wrong
You can't because you are trying to modify const data.
change it to:
char My_St[] = "abcdef";
Then you will be able to change it.
Think about what you were doing, you were declaring a pointer that pointed to "abcdef". It IS a pointer, not an array of chars. "abcdef" lives in the farm, I mean, in the .text area of your program and that is immutable.
When you do it the way I've shown, you are telling the compiler: i'm declaring this array, that will have as many chars as are needed to accommodate "abcdef" and also, as you are there, copy "abcdef" to it.
You provided a hint to the compiler by declaring My_St with type char *. Assigning a string literal to this pointer essentially makes it a const char * because a string literal cannot be modified, meaning the memory location is read-only. Writing to that read-only memory location is what is producing your segfault. Change it from char *My_St to char My_St[] to get it working.
char *My_St refers to constant memory, most likely. You will need to dynamically allocate your string and then fill it (using strcpy).
char *str = malloc(7);
strcpy(str, "abcdef");
Or
char *str = strdup("abcdef");
And then it is safe to modify str.
The basics are correct, however your character string is (behind the scenes) constant and can't be modified. You'd have to define a array of chars (e.g. char[20]), copy the string into it and then modify the character.
To be 100% correct you'd have to write const char *My_St = "abcdef"; which makes it clearer that you can't do what you're trying to do.

How to get a pointer to a string in C using the reference operator?

Is there anyway given a string like, "my example\n", to get a pointer to it? For instance, &"my example\n" or &{"my example\n"}?
EDIT: I guess asking rudimentary questions is what I get for not sleeping last night. Ah well, thanks for all your help anyway.
It's already a pointer:
char *string = "my string\n";
string will be a pointer to the literal string.
It already is an address.
Example: char * addr= "my example\n";
Here, the variable addr holds the address of the string.
To your code, a string constant appears as a pointer; specifically a character pointer char* to the first character in the string.
In order to be more strict: the string literals are of type const char[]. However const char[] can be implicitly casted into const char*. So you can easily obtain the pointer by assigning
const char* p = "string";
Please note that if your next line would be
const char* p1 = "string";
--the value of p1 is not guaranteed to be equal to the value of p: different string constants may have different addresses (but don't need to).
Note that p will be pointer to the first character rather than to the whole string.
Another caveats is that you shouldn't try to get the char* pointer (by casting const away), as this will result in undefined behaviour. For example, the compiler may put the string literal into the read-only memory, and the program will simply crash.

Different string initialization yields different behavior?

How come when I use the following method, to be used to convert all the characters in a string to uppercase,
while (*postcode) {
*postcode = toupper(*postcode);
postcode++;
}
Using the following argument works,
char wrong[20];
strcpy(wrong, "la1 4yt");
But the following, doesn't, despite them being the same?
char* wrong = "la1 4yt";
My program crashes in an attempt to write to an illegal address (a segfault, I presume). Is it an issue with not mallocing? Not being null-terimanted? It shouldn't be...
Through debugging I notice it crashes on the attempt to assign the first character as its uppercase.
Any help appreciated!
char* wrong = "la1 4yt";
This declares a pointer to a string constant. The constant cannot be modified, which is why your code crashes. If you wrote the more pedantic
const char* wrong = "la1 4yt"; // Better
then the compiler would catch the mistake. You should probably do this any time you declare a pointer to a string literal rather than creating an array.
This, on the other hand, allocates read/write storage for twenty characters so writing to the space is fine.
char wrong[20];
If you wanted to initialize it to the string above you could do so and then would be allowed to change it.
char wrong[20] = "la1 4yt"; // Can be modified
char wrong[] = "la1 4yt"; // Can be modified; only as large as required
char * whatever = "some cont string";
Is read-only.
In the second variant, "la1 4yt" is a constant and therefore is in a read-only segment. Only the pointer (wrong) to the constant is writeable. That's why you get the segfault. In the first example however, everything is writable.
This one might be interesting: http://eli.thegreenplace.net/2009/10/21/are-pointers-and-arrays-equivalent-in-c/
See Question 8.5 in the C FAQ list.
When you do
char wrong[20] = "la1 4yt";
the compiler copies the elements of the string literal {'l', 'a', '1', ' ', '4', 'y', 't', '\0'} to the corresponding elements of the wrong array; when you do
char *wrong = "la1 4yt";
the compiler assigns to wrong the address of the string literal.
String literals are char[] (arrays of char), not const char[] ... but you cannot change them!!
Quote from the Standard:
6.4.5 String literals
6 It is unspecified whether these arrays are distinct provided
their elements have the appropriate values. If the program
attempts to modify such an array, the behavior is undefined.
When I use a string literal to initialize a char *, I usually also tell the compiler I will not be changing the contents of that string literal by adding a const to the definition.
const char *wrong = "la1 4yt";
Edit
Suppose you had
char *test1 = "example test";
char *test2 = "test";
And the compiler created 1 single string literal and used that single string literal to initialize both test1 and test2. If you were allowed to change the string literal ...
test1[10] = 'x'; /* attempt to change the 's' */
printf("%s\n", test2); /* print "text", not "test"! */

Resources