views:

373

answers:

4

I'm trying to do some classic C development in Visual C++ 2008 that will modify the characters of a string like so:

void ModifyString(char *input)
{
  // Change first character to 'a'
  *input = 'a';
}

I'm getting a unhandled exception when I try to change a character. It seems like I could do this in Visual Studio 6 or using gcc, but maybe I'm just forgetting something. Does Visual Studio somehow pass char* by value (managing memory). If so, how do I turn this off?

+1  A: 

Is the input a string literal? That's probably the problem. Otherwise you'll need to post more code, as the pointer has somehow ended up pointing at a readonly location in memory.

Daniel Earwicker
+2  A: 

It's impossible to answer this question without seeing how ModifyString is called. The function itself is correct assuming it's contract is to be passed a non-NULL value.

However it's possible for the call site to fail by doing any number of things

  • Passing NULL
  • Passing const char by means of an evil cast
JaredPar
you don't have to have an "evil cast" to accidentally pass a const char * to the function. in C string literals are typed "char *" even though they are constant
newacct
@newacct - that is evil!
Daniel Earwicker
@newacct: No, C string literals are type `const char[]`. It just happens that there's an implicit conversion from string literals to `char*`. The reason for that was that when they were standardizing the C language, there was a lot of legacy code that assumed string constants were modifiable, and the ANSI committee didn't want to invalidate all of that legacy code. Unfortunately, C++ inherited this implicit cast as well, although it is deprecated.
Adam Rosenfield
+5  A: 

You're probably passing a string literal somewhere:

ModifyString("oops");  // ERROR!

C and C++ allow you to implicitly cast from string literals (which have type const char[]) to char*, but such usage is deprecated. String constants are allowed to be allocated in read-only memory (and they usually are), so if you attempt to modify them, you'll get an access violation (aka segmentation fault or bus error). If the compiler doesn't put string constants in read-only memory, the program will still work, but it is undefined behavior.

The correct way to do this is to copy the string into a writeable buffer:

// one way:
char mystring[] = "test";
ModifyString(mystring);  // ok

// another way:
char mystring[64];  // make sure this is big enough!!
strcpy(mystring, "test");
ModifyString(mystring);  // ok
Adam Rosenfield
Yep, that was it. My driver was declaring test strings as so:char *test = "Hello World!"I changed it to use char arrays as you described and it worked. Thanks for the quick replies.
@Brian: Make sure you don't writer after the end of your buffer in ModifyString or you'll have much bigger problem.
Paul
A: 

I can't say exactly why this doesn't work, but the problem is in your code, not Visual Studio. For some reason, you are passing an invalid pointer to the function. It is either a null pointer, or it points to some address you don't have read access to.

If you post some more of the code (where is the function called from, and how is it called?), we may be able to point out the exact problem.

The reason it worked in GCC or VC6 is quite simply that it is undefined behavior. The C++ standard doesn't say that "this should work", or "this should cause a crash". Anything can happen if you write to memory you don't have access to. And depending on the compiler, and the system you're running the application on, the address you end up accessing will vary. By sheer luck, you hit an address that caused an access violation when compiled with VC2008. Under GCC and VC6, you weren't as lucky, and got code which appeared to work, and simply wrote to some garbage address.

jalf