5

So here is the code:

#include <stdio.h>

int main() {
    char str1[] ="Hello", str2[20] ="Hi";
    char *p ="Hello", *s ="Hi";
    str1 = "Adieu";
    return 0;
}

Now my Book gives this reason

error, constant pointer cannot change

And when I run it, I get error as :

error: assignment to expression with array type

My question is why does my book says so ?, From where did pointers come here ?

The book is Let us C 18th edition (latest edition at the time the question was posted) by Yashavant P. Kanetkar incase you need refence.

Virat
  • 77
  • 7
  • Perhaps the particular compiler the author used gave that error message. The compiler may have decayed `str1` into a `char * const` in `str1 = "Adieu";`. – Ted Lyngmo Nov 27 '22 at 18:45
  • @TedLyngmo Maybe but I think the author is probably wrong here, he was trying to teach pointers and strings and how the pointer can point to a string, He probably messed up here. – Virat Nov 27 '22 at 18:50
  • @Virat The book is in at least its 18th edition from what I can find, so errors like that are more than a bit concerning. – Andrew Henle Nov 27 '22 at 18:51
  • 1
    @AndrewHenle Well what can I do, Its the prescribed book, I can't not read it. – Virat Nov 27 '22 at 18:54
  • 2
    @Virat Well, you're probably already well ahead of any classmates if you're discerning enough to note the error message is wrong. Congratulations on picking up on some of the nuances of C quickly because they can really matter. – Andrew Henle Nov 27 '22 at 18:59
  • @AndrewHenle Well Thank you, It really helps boost my confidence. Especially since we switched to C from python. – Virat Nov 27 '22 at 19:02
  • If you're quoting, e.g. from a book, please also include author and revision. Also check errata for updates. In any case, compiler error messages are implementation-specific, so they may well change when using a different compiler. Expecting a specific text is wrong. – Ulrich Eckhardt Nov 27 '22 at 19:31

2 Answers2

5

In the line

str1 = "Adieu";

the array str will decay to a pointer to the first element of the array, which is an rvalue (not an lvalue) and therefore cannot be modified.

This behavior is specified in §6.3.2.1 ¶3 of the ISO C11 standard:

Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object and is not an lvalue. [...]

Note that in the quote above, "initialize an array" means initialize it inside a declaration, not assign it a value outside a declaration (which would be an "assignment", not an "initialization").

For this reason, the error message in your book

error, constant pointer cannot change

is correct. An rvalue cannot be modified and it is therefore not wrong to describe it as "constant".

However, the error message from your compiler

error: assignment to expression with array type

is also correct and probably more useful.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
  • so you are saying if the author used something like str1[10] = "Hello ", then he world be wrong, right? – Virat Nov 27 '22 at 19:40
  • 1
    @Virat: The expression `str1[10]` is an lvalue of type `char`. The expression `"Hello"` is a string literal, so it is an array, which will decay to a pointer to the first element of the array, i.e. to the character `H`. In C, you cannot assign a `char *` to a `char` without a cast, so it is wrong. – Andreas Wenzel Nov 27 '22 at 19:45
  • 1
    @Virat: However, if you mean `char str1[10] = "Hello";`, then the situation is very different, as that is a declaration with an initialization from a string literal. That will work. In an assignment, you cannot assign anything to the array itself, only to its individual elements. However, during initialization, you can initialize the entire array at once, from a string literal. – Andreas Wenzel Nov 27 '22 at 19:51
1
str1[] = "Hello";

str1 is a character array which has been initialized from a string literal. It has automatic storage duration and is modifiable. The string literal "hello" on the other hand, is placed in the text segment(read-only-memory), although the compiler may choose not to, and as such it's illegal to modify it, and doing so results in undefined behaviour. str1[ ] on the other hand, stores a copy of the literal. So you're only modifying the copy, not the literal itself. But C doesn't allow you to modify it like this:

str2 = str1;

You can modify it by assigning a single element at a time or by using string functions such as strcpy, strnpcy, et cetera declared in the string.h header file to copy one string to another string. Or you may use a pointer to a character, which is modifiable and can be changed to point to some other location in memory.

As of that book, it's infamous here, being the cause of too many errors on stackoverflow. The author has an incomplete understanding of the language. Consider picking up another book, preferably from The Definitive C Book Guide and List.

Harith
  • 4,663
  • 1
  • 5
  • 20
  • The book is my prescribed syllabus, I can't change it. But I know it has a lot of errors that's why asked to confirm my doubt. – Virat Nov 27 '22 at 18:52
  • 2
    Given `char str1[] = "Hello";`, `str1` is not a string literal and in no way refers to nor contains a string literal. `str1` may have been initialized *from* a string literal (or directly created in some other manner), but that does not make `str1` a string literal. `str1` is a fully-modifiable array of `char` values with a proper `NUL` terminator to make it a C-style string. – Andrew Henle Nov 27 '22 at 18:53
  • @AndrewHenle Yes, str is initialized with a literal. str itself is not a literal, since it's not unnamed. I'd change the answer to reflect that. – Harith Nov 27 '22 at 18:58
  • @Virat You may read a modern text along with it. A good one would be Robert Seacord's "Effective C." – Harith Nov 27 '22 at 19:04
  • @Haris OK I think I can do that. – Virat Nov 27 '22 at 19:05
  • *It is stored in static storage duration and any attempt to modify its content results in undefined behaviour.* That does not apply to `str1`. In the question's `char str1[] ="Hello"` code, `str1` is an *automatic* variable (almost certainly on the stack) of 6 `char` elements including the `NUL` terminator that is fully modifiable. See [What is the difference between char s\[\] and char *s?](https://stackoverflow.com/questions/1704407/what-is-the-difference-between-char-s-and-char-s). – Andrew Henle Nov 27 '22 at 19:07
  • @AndrewHenle the top answer states that the "Hello" is placed in read only memory, and in this case, copied to the stack which makes it legal to modify it. – Harith Nov 27 '22 at 19:14
  • @AndrewHenle I removed that part to be more explicit. – Harith Nov 27 '22 at 19:17
  • @Haris Your compiler doesn't have to do it that way - the only requirement is that `str1` winds up as a modifiable 6-byte array with automatic storage duration and containing '`H'`, `'e'`, `'l'`, `'l'`, `'o'`, and `'\0'`. The `"Hello"` string literal may or may not appear at all in the final executable. – Andrew Henle Nov 27 '22 at 19:17
  • 1
    (cont) I didn't downvote, but your "str1 is a character array which has been initialized from a string literal. It is stored in static storage and an attempt to modify it as such is illegal" is still wrong - `str1` is not a static variable as it has automatic storage (as currently coded in the question). Someone else likely downvoted your answer for that. – Andrew Henle Nov 27 '22 at 19:19
  • @AndrewHenle I would rewrite the answer but, would I be correct to assume that "Hello" itself is placed on the text segment? – Harith Nov 27 '22 at 19:29