3

Please explain why I get the segfault using the ++ operator. What is the difference between explicitly adding 1 and using the ++ operator ?

using namespace std;
#include <iostream>

int main() {

  char* p = (char*) "hello";

  cout << ++(*p) << endl; //segfault
  cout << 1 + (*p) << endl; // prints 105 because 1 + 'h' = 105  

} 
Kacy Raye
  • 1,312
  • 1
  • 11
  • 14
  • 7
    `++(*p)` attempts to modify the string itself. You can't do that because it's a literal string. Casting to `char*` (from its' original `const char*`) is wrong in the first place. – jogojapan Jun 28 '13 at 03:06
  • I don't think that's entirely correct. After reading that guy's answer below, I think I was actually trying to modify a character literal, not a string literal because (*p) returns the character 'h' before I actually call on the ++ operator. – Kacy Raye Jun 28 '13 at 03:23
  • 1
    There is only one literal in your code: `"hello"` (apart from `1`, but that's unrelated), which is a string literal. `*p` points to an address of one of the characters within that literal. You attempt to modify the value the address points to. If you were to succeed doing this, you would have modified that character, and therefore -- given that it is part of the string literal defined in your code --, you would have suceeded in modifying the string literal. – jogojapan Jun 28 '13 at 03:26
  • 1
    Oh, I thought ++(*p) was the same as ++'h' but you're right. It does actually try to change the value inside the string literal. I tried my exact same example again except this time with a string of numbers instead of "hello" and I still got a segfault. `char* p = (char*) "123"; cout << ++(*p);` Thanks a lot! – Kacy Raye Jun 28 '13 at 03:34
  • Ok. (Just for the record, and for other people who might read this in the future: Checking whether you get a segfault is not generally a valid way to check whether the code is correct (or valid, or has undefined behaviour or whatever). In fact, depending on platform and compiler, even your original code could well have run without crashing. But even then, it would have been incorrect and unpredictable.) – jogojapan Jun 28 '13 at 03:36
  • Oh wait, I just realized I still might be right. In my previous comment, I'm still trying to modify a character literal which happens to be '1'. The *p returns the character, which then has nothing to do with the string literal anymore. After this character is returned, I'm basically saying ++'1' which is trying to change the character literal in memory which causes the seg fault. The string literal has nothing to do with it. – Kacy Raye Jun 28 '13 at 03:42
  • 1
    `*p` does not "return" the character. `*p` is an lvalue expression that you can use to access (including _modify_) the data behind the address stored in `p`. So what you modify is not a copy of the character. It's the character inside the string literal itself. Modifying it is tantamount to modifying the string literal. – jogojapan Jun 28 '13 at 03:46
  • 1
    After one little test with an int pointer, I finally believe you lol...you're totally right. Sorry for not taking your word for it right away! – Kacy Raye Jun 28 '13 at 12:23

2 Answers2

8

Because you're trying to increment a constant.

char* p = (char*) "hello";  // p is a pointer to a constant string.
cout << ++(*p) << endl;     // try to increment (*p), the constant 'h'.
cout << 1 + (*p) << endl;   // prints 105 because 1 + 'h' = 105

In other words, the ++ operator attempts to increment the character p is pointing to, and then replace the original value with the new one. That's illegal, because p points to constant characters. On the other hand, simply adding 1 does not update the original character.

Adam Liss
  • 47,594
  • 12
  • 108
  • 150
  • Awesome succinct answer, explains the problem really well. +1 – Fantastic Mr Fox Jun 28 '13 at 03:11
  • Specifically, when the program is started by the os, that string is read out of the executable and loaded into memory pages that are read-only. – antiduh Jun 28 '13 at 03:13
  • 1
    So basically what I was saying was 'h' = 'h' + 1 ? I feel retarded now...lol I can't believe this question didn't get down voted. For the record though, I wasn't trying to modify a string literal though, right? I was trying to modify a character literal since (*p) returns the character 'h' before the ++ operator is called. Am I right or...? – Kacy Raye Jun 28 '13 at 03:18
  • @KacyRaye there's no character *literals* (the ones with single quotes) in your program. – Ilmo Euro Jun 28 '13 at 03:40
  • Really? Because I can count 5 of them. Strings are an array of characters. And *p returns the character 'h'. – Kacy Raye Jun 28 '13 at 03:44
  • @KacyRaye, yes, that's exactly what was happening: the code was trying to increment the letter `h` in the original (read-only) string. The reason `1 + (*p)` works is that `*p` returns a modifiable _copy_ of the `h`, which is then incremented (to `i`) and displayed as an integer value. I just upvoted your question because pointer operations are among the most powerful features of C, and they cause endless strife to beginners. I promise you most of us made a similar mistake at one time or another. Except me. I've done it _lots_ of times. – Adam Liss Jun 28 '13 at 21:48
2

You can't modify a C-style string literal. That's what ++(*p) is doing.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294