3

So, its a pretty simple problem and I know the solution which is a simple function like the one below:

  void removeSpaces(char* s) {
    char* source = s;
    char* dest = s;

    while(*source) {
        if(*source == ' ') {
            source++;
        } else {
            *dest++ = *source++;
        }
    }

    *dest = 0;
}

I am working in Visual C++ 2008 Express edition

When I call it with the following it works fine without any issues i.e it removes all the spaces:

int main() {
    char input[50] = "I       like            2% milk";
    removeSpaces(input);
    cout<<input;

    getchar();
    return 0;
}

But, the problem is when I call it by changing the string declaration to this:

char * input = "I       like            2% milk";

I get a exception (some kind of access violation)

The exception is showing on this line of code of the removeSpace function

*dest++ = *source++;

Can anyone elaborate as to why is this happening?

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
Sushant
  • 1,074
  • 2
  • 13
  • 21

3 Answers3

6

When you do

char* something = "a string literal";

The compiler puts "a string literal" into the executable image itself and just assigns a pointer to this memory to something. You are not allowed to modify this memory, and many times the memory that the string resides in is marked read-only, so any attempts to write to it result in an access violation like the one you experienced.

When you do

char something[] = "a string literal";

you are really creating an array on the stack named something and initialising it with "a string literal". This is equivalent of doing char something[] = {'a', ' ', 's', 't', 'r', ..., 'a', 'l', 0};. Since this memory is on the stack, you can modify it freely.

char* something = "a string literal" looks like

    stack                              executable

-------------                     ---------------------
|~~~~~~~~~~~|                     | ~~~~~~~~~~~~~~~~~ |
| something | ----------------->  | a string literal0 |
-------------                     | ~~~~~~~~~~~~~~~~~ |
                                  ---------------------

Whereas char something[] = "a string literal" looks like

stack

-----
|~~~|
| a |  <- something is an alias for this location
|   |
| s |
| t |
| r |
| i |
| n |
| g |
|   |
| l |
| i |
| t |
| e |
| r |
| a |
| l |
| 0 |
-----

Where ~~~ means "other memory etc".

Note that

char* x = "string literal";

Is actually invalid and should not compile because you cannot convert a char const[x] to a char*. It should be const char* x, not char* x, but some old and non-conformant compilers wrongly allow this behaviour.

Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
  • 3
    Depending on your compiler and settings, this can be all sorts of hideously undefined or non-standard. Some folks and I tested writing to "const" strings a while back, and it often segfaults, but occasionally worked, segfaulted when we wrote past the end, didn't error at all, etc. It was tested across a few versions of MSVC and GCC. The only good thing that happened was almost all the compilers warned about it, so **turn your warnings up and watch them**. – ssube Feb 04 '12 at 16:51
  • @Sushant Note that if you *really* want to use pointers you can always get out with `char s[] = "string literal"; char* pt = s;`... – Matthieu Feb 10 '16 at 09:39
4

because you are trying to change the constant string.

char input[50] allocates memory you can change and initializes it with the string. the char* = just points to a string you are not allowed to change.

On embedded devices, constant strings like that would generally be put into ROM, where you can't even physically write to that memory! More modern OS's with memory management units just protect the area where that constant data is and then you get the exception if you violate that memory with your nasty writes to it :-)

Keith Nicholas
  • 43,549
  • 15
  • 93
  • 156
1

char* input = "some string literal"; creates a non-const pointer to the string literal that is - on most systems - placed in read-only memory. Attempts to write to it typically create a signal or CPU exception, as distinct from a C++ language exception as per try/catch blocks. This horrible situation is allowed to retain compatibility with C, where it is allowed.

So, stick with the original code, which explicitly requests a non-const buffer with that content. Or, use a std::string or something....

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252