Tutorial :Modifying C string constants? [duplicate]


Possible Duplicate:
Why do I get a segmentation fault when writing to a string?

I want to write a function that reverses the given string passed into it. But, I can not. If I supply the doReverse function (see code below) with a character array, my code works well.

I can't figure out why this does not work. I am able to access str[0] in doReverse, but I can't change any value of the array by using a char pointer. Any ideas?

void doReverse(char *str) {      str[0] = 'b';  }    void main(void) {      char *str = "abc";      doReverse(str);      puts(str);  }  


I know how to do write a reverse function by passing a character array to it:

void reverse1(char p[]) {      int i, temp, y;        for (i = 0, y = strlen(p); i < y; ++i, --y) {          temp = p[y-1];          p[y-1] = p[i];          p[i] = temp;      }  }  

But, I want to write another version that gets a char pointer as a parameter.


The simplest solution is to change the declaration of str to

char str[] = "abc";  

This makes str an array of char that is initialized to the string "abc". Currently you have str as a pointer-to-char initialized to point to a string described by a string literal. There is a key difference: string literals are read-only to give the compiler maximum flexibility on where to store them; it is UB to modify them. But arrays of char are mutable, and so it's okay to modify those.

PS. main() returns an int.


Since you're studying for an exam, I'll flesh out my comments a bit to explain what's actually happening:

char *str = "abc";  

str is a pointer stored on the stack. It gets initialized to point to the literal string "abc". That literal string is going to be stored in the data section of your compiled executable and gets loaded into memory when your program is loaded. That section of memory is read-only, so when you try and modify the data pointed to by str, you get an access violation.

char* str = malloc(sizeof(char) * 4);  strcpy(str, "abc");  

Here, str is the same stack pointer as the first example. This time, it is initialized to point to a 4-character block of memory on the heap that you can both read and write. At first that block of memory is uninitialized and can contain anything. strcpy reads the block of read-only memory where "abc" is stored, and copies it into the block of read-write memory that str points to. Note that setting str[3] = '\0' is redundant, since strcpy does that already.

As an aside, if you are working in visual studio, use strcpy_s instead to make sure you don't overwrite your buffer if the string being copied is longer than you expected.

char str[] = "abc";   

Here str is now an array allocated on the stack. The compiler will sized it exactly fit the string literal used to initialize it (including the NULL terminator). The stack memory is read-write so you can modify the values in the array however you want.

char str[4] = "abc";  

This is effectively the same as the previous version, only you are telling the compiler that you know better than it does how long the array should be. You may get into trouble if you change the string and not the array size.


Because this is homework I'll give advice but I won't post a complete solution.

I'm guessing you're getting an access violation on str[0] = 'b'? This is because "abc" is a string literal.

Copy the string str points to before calling reverse, or get reverse to allocate a buffer and put the reversed string into that.

Keep in mind you'll have to deallocate all the memory you allocate.


Lordy, Lordy. To all those suggesting ways to actually perform the exchange, please read the question carefully; there's nothing worse than having to reiterate an already perfectly articulate question. Irrespective of the method used to implement the exchange (temp-swap, xor3-swap, etc), this person appears to be all too familiar with the function's fundamental and rather elementary intrinsics.

However, as already explained, the compiler/linker generically places all string literals within the 'const data-segment' of the target executable, which is subsequently associated with a non-writeable MMU descriptor during the appropriate 'load/exec' invocation. All CPU write-cycles subsequently issued via this descriptor are automatically trapped by the MMU's exception mechanism, resulting in the obligatory 'segfault' or platform-specific equivalent. It goes without saying of course, older non-MMU platforms would exhibit no such behaviour.

Although this effectively procures run-time support for the source language's 'constant/literal' idiom, several platforms have historically facilitated explicit compile-time segment overrides. However, this level of support has slowly diminished in favour of a more rigid/robust abstraction layer, thus rendering many obvious and often useful optimisations untenable. As time and attrition yields its steadily ageing "MC/ASM" philosophy before an all too eager "Microsoft" generation, programmers are no longer deemed knowledgeable or responsible enough to make this kind of decision. In lieu of the many contrived, not to say creative, implementations I have witnessed as a project leader, this is by no means a bad thing.

Although this post is rapidly evolving into an off-topic violation, I feel somewhat vindicated by the constant stream of top-down related questions which are slowly becoming endemic within our industry. As a fledgling C programmer - a language originally designed to complement low-level development - my advice is to adopt a bottom-up approach and augment your studies with a little extra-curricular assembly language development. As algorithmic implementation is likely to constitute your primary focus as an applications engineer, it is important to remember that contemporary CPU design has experienced a homogeneous evolution over the past 30 years; today's ultra-fast Intel CPUs are no more than super-scalar CMOS refinements of the 4/8-bit bipolar processors I was programming when the Earth was still young.

Contrary to popular belief, assembly language programming is relatively easy to learn, and absolutely essential when attempting to reconcile high-level constructs with problematic or esoteric behaviour. Once you factor in the endless hours of experimentation, debugging, web-searching and forum-spamming, there can be no doubt that a bottom-up approach is certainly the path of least resistance.

Good luck with your studies.


As far as I know, constant strings are implemented as arrays of constant characters (or, in C terms, const char [length]). Therefore, you can't modify its characters.

Try dynamically allocating the string.

char* str = (char*)malloc(sizeof(char) * 4);  strcpy(str, "abc");  str[3] = '\0';  

Of course, don't forget to free the memory at the end of your program.

Edit: I won't post anything related to reversing the string, because that's your work.

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Next Post »