Different string initialization yields different behavior? - c

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"! */

Related

Cannot modify char array

Consider the following code.
char message[]="foo";
void main(void){
message[] = "bar";
}
Why is there a syntax error in MPLAB IDE v8.63? I am just trying to change the value of character array.
You cannot use character array like that after declaration. If you want to assign new value to your character array, you can do it like this: -
strcpy(message, "bar");
Assignments like
message[] = "bar";
or
message = "bar";
are not supported by C.
The reason the initial assignment works is that it's actually array initialization masquerading as assignment. The compiler interprets
char message[]="foo";
as
char message[4] = {'f', 'o', 'o', '\0'};
There is actually no string literal "foo" involved here.
But when you try to
message = "bar";
The "bar" is interpreted as an actual string literal, and not only that, but message is not a modifiable lvalue, ie. you can't assign stuff to it. If you want to modify your array you must do it character by character:
message[0] = 'b';
message[1] = 'a';
etc, or (better) use a library function that does it for you, like strcpy().
you can do that only in the initialisation when you declare the char array
message[] = "bar";
You can not do it in your code
To modify it you can use strcpy from <string.h>
strcpy(message, "bar");
You cant change the character array like this . If you want to change the value of character array then you have to change it by modifying single character or you can use
strcpy(message,"bar");
char message[]="foo";
This statement cause compiler to create memory space of 4 char variable.Starting address of this memory cluster is pointer value of message. address of message is unchangeable, you cannot change the address where it points . In this case, your only chance is changing the data pointed by message.
char* message="foo"
In this time, memory is created to store the address of pointer, so the address where message point can change during execution. Then you can safely do message="bar"

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.

strtok - char array versus char pointer [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
strtok wont accept: char *str
When using the strtok function, using a char * instead of a char [] results in a segmentation fault.
This runs properly:
char string[] = "hello world";
char *result = strtok(string, " ");
This causes a segmentation fault:
char *string = "hello world";
char *result = strtok(string, " ");
Can anyone explain what causes this difference in behaviour?
char string[] = "hello world";
This line initializes string to be a big-enough array of characters (in this case char[12]). It copies those characters into your local array as though you had written out
char string[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0' };
The other line:
char* string = "hello world";
does not initialize a local array, it just initializes a local pointer. The compiler is allowed to set it to a pointer to an array which you're not allowed to change, as though the code were
const char literal_string[] = "hello world";
char* string = (char*) literal_string;
The reason C allows this without a cast is mainly to let ancient code continue compiling. You should pretend that the type of a string literal in your source code is const char[], which can convert to const char*, but never convert it to a char*.
In the second example:
char *string = "hello world";
char *result = strtok(string, " ");
the pointer string is pointing to a string literal, which cannot be modified (as strtok() would like to do).
You could do something along the lines of:
char *string = strdup("hello world");
char *result = strtok(string, " ");
so that string is pointing to a modifiable copy of the literal.
strtok modifies the string you pass to it (or tries to anyway). In your first code, you're passing the address of an array that's been initialized to a particular value -- but since it's a normal array of char, modifying it is allowed.
In the second code, you're passing the address of a string literal. Attempting to modify a string literal gives undefined behavior.
In the second case (char *), the string is in read-only memory. The correct type of string constants is const char *, and if you used that type to declare the variable you would get warned by the compiler when you tried to modify it. For historical reasons, you're allowed to use string constants to initialize variables of type char * even though they can't be modified. (Some compilers let you turn this historic license off, e.g. with gcc's -Wwrite-strings.)
The first case creates a (non const) char array that is big enough to hold the string and initializes it with the contents of the string. The second case creates a char pointer and initializes it to point at the string literal, which is probably stored in read only memory.
Since strtok wants to modify the memory pointed at by the argument you pass it, the latter case causes undefined behavior (you're passing in a pointer that points at a (const) string literal), so its unsuprising that it crashes
Because the second one declares a pointer (that can change) to a constant string...
So depending on your compiler / platform / OS / memory map... the "hello world" string will be stored as a constant (in an embedded system, it may be stored in ROM) and trying to modify it will cause that error.

Simple modification of C strings using pointers

I have two pointers to the same C string. If I increment the second pointer by one, and assign the value of the second pointer to that of the first, I expect the first character of the first string to be changed. For example:
#include "stdio.h"
int main() {
char* original_str = "ABC"; // Get pointer to "ABC"
char* off_by_one = original_str; // Duplicate pointer to "ABC"
off_by_one++; // Increment duplicate by one: now "BC"
*original_str = *off_by_one; // Set 1st char of one to 1st char of other
printf("%s\n", original_str); // Prints "ABC" (why not "BBC"?)
*original_str = *(off_by_one + 1); // Set 1st char of one to 2nd char of other
printf("%s\n", original_str); // Prints "ABC" (why not "CBC"?)
return 0;
}
This doesn't work. I'm sure I'm missing something obvious - I have very, very little experience with C.
Thanks for your help!
You are attempting to modify a string literal. String literals are not modifiable (i.e., they are read-only).
A program that attempts to modify a string literal exhibits undefined behavior: the program may be able to "successfully" modify the string literal, the program may crash (immediately or at a later time), a program may exhibit unusual and unexpected behavior, or anything else might happen. All bets are off when the behavior is undefined.
Your code declares original_string as a pointer to the string literal "ABC":
char* original_string = "ABC";
If you change this to:
char original_string[] = "ABC";
you should be good to go. This declares an array of char that is initialized with the contents of the string literal "ABC". The array is automatically given a size of four elements (at compile-time), because that is the size required to hold the string literal (including the null terminator).
The problem is that you can't modify the literal "ABC", which is read only.
Try char[] original_string = "ABC", which uses an array to hold the string that you can modify.

Resources