简体   繁体   中英

In C, why can't the value of a pointer-to-char variable be changed after it has been assigned?

I don't understand the difference between this case:

#include <stdio.h>

int main()
{
  int i = 0;
  i = 1;

  return 0;
}

And this case:

#include <stdio.h>

int main()
{
  char *mychar = "H";
  *mychar = "E";

  return 0;
}

Which produces the compiler warning "assignment makes integer from pointer without a cast".

Shouldn't *mychar = "E" dereference mychar to assign it the value of "E"?

Many thanks.

You have confused few things.

  • Note "E" is actually const char[] which stores 'E' and '\\0' . It is not a single character. For single characters you use '', like 'E' .
  • mychar points to string literal and you can't change string literals.

If what you had in mind is this:

 char *mychar = "H";
 mychar = "E"; 

This is ok, you are not changing the string literal, just first time the pointer mychar points to string literal "H", then to "E".

This you can't do:

  char *mychar = "Hello";
  *mychar = 'E'; // Can't modify the string literal

But this you can do:

  char c = 0;
  char *mychar = &c;
  *mychar = 'E'; // This is ok

"E" is a string literal (char*) and 'E' is a char literal (char).

Note that the two pieces of code which you are comparing are not analogous! The difference between the two pieces of code (int vs char*) will be clearer is you write

char* mychar = "H";
*mychar = "E";

The type corresponding to the int example is (char*). That is, the code being analog to the "int" example is

char* mychar = "H";
mychar = "E";

String literals might be stored in read-only section of memory. Modifying a string literal invokes undefined behavior. You can't modify it.

Add const qualifier to let your compiler know that string is non-modifiable

char const *mychar = "H";  

You should also note that the statement

*mychar = "E";  

is wrong by itself. You are assigning a char * type to char .

I think you mean the following

#include <stdio.h>

int main()
{
  char *mychar = "H";
  mychar = "E";

  return 0;
}

After the assignment the pointer points to string literal "E" .

So as you see the pointer can be reassigned. Only you should use a correct syntax. Expression *mychar means dereferencing a pointer. Its value is not the value stored in the pointer but the value of an object pointed to by the pointer.

As for your original code then in this statement

  *mychar = "E";

the left operand of the assignment *mychar has type char while the right operand "E" has type of pointer char * (the array type that corresponds to the string literal is implicitly converted to the pointer to its first element) and the compiler warns you that you are trying to do something wrong.

Take into account that string literals may not be changed. So for example this statement

  *mychar = 'E';

has undefined behaviour (here is used integer character constant 'E' )

char *mychar = "H" tells the compiler that mychar points to a character array. *mychar dereferences the first character in the array, literally 'H' (note the single quotes).

When you write:

*mychar = "E" you are trying to put a string (literally a pointer-to-character-array) where a literal-character should go, so the technically correct code would be:

*mychar = 'E'; // assign a character-literal, not a string

Note though that strings are generally created in read-only memory, so if you do actually write 'E' to the read-only memory location where 'H' is currently at, your program will probably crash.

If you wanted to avoid the compiler warning ( but still write totally incorrect code and crash ) you would write:

(char *)(*mychar) = "E"; // make the compiler think *mychar is pointer-to-char, very bad, will crash, but won't warn any more

There are two issues at play here -- understanding the type of your pointer, and understanding what parts of memory you can modify.

Recent versions of the gcc compiler issue a warning for the line:

char *mychar = "H";

although the warning can be hard to understand:

 warning: deprecated conversion from string constant to ‘char*’

That line of code still compiles and runs despite the warning. Basically, they are discouraging you from doing that -- mychar is now a pointer to some place in memory where the compiler has placed the two characters, 'H' and '\\0'. If you do something like mychar[3] = 'X', you are writing an area of memory that you know nothing about and don't control; depending on the implementation, that might cause a run-time error. If you add const:

const char *mychar = "H";

or

char const *mychar = "H";

the warning goes away, but now you have made it clear to yourself that you can't use this pointer to change memory. If you later do

*mychar = 'E';

that will cause a compile-time error (not a warning) because you can't use a const char* to change memory.

Now, regarding the error message you actually got, it is because you wrote

*mychar = "E";

instead of

*mychar = 'E';

When the compiler sees "E", it sets aside some memory in the executable with the characters 'E' and '\\0', and the value of "E" is a pointer (char*) to that point in memory. *mychar is the character at the address pointed to by mychar. So

*mychar = "E";

is taking the char* pointer to the "E" string, and put it at the location in memory pointed to by mychar. The really confusing thing about your error message is that it refers to an integer; I guess that is because char can be considered a type of integer (unsigned char can take on any value between 0 and 255).

you are trying to set the value of a character to the value of a pointer. It is legal (though seldom a good idea) to turn a pointer into an integer, so you could try

*mychar = (char)"E";

but with my version of gcc (4.9.3) that produces a compile time error because the cast reduces precision -- you're taking a 32-bit or 64-bit value and turning it into an 8-bit value. Again, with my version of gcc,

*mychar = (int)"E";

compiles (if I didn't make mychar a const char*), but produces a run-time error because it is trying to change read-only memory.

Perhaps what you really meant was

mychar = "E";

This changes mychar from pointing to the place in memory containing "H" to the place in memory containing "E". This compiles and runs correctly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM