0

I am wondering if one could change the string stored in a variable, without changing the address. And I am unable to write the code to do this, since when I write codes like

char* A = "abc";
char* B = "def";
A = B; <-- if I write down this code, then A will point to B and address changes. 

So does anyone know how to do this, changing the string stored in A to "def" ,without changing the initial address of A?

Moreover, I have tried to change only one word in variable A, again, without changing the address.

To do this, I have write the following failure code. BUT I don't know why it fails.

#include <stdio.h>
#include <string.h>

int main(void)
{
    char* s = "ABC";

    // print value and address of s.
    printf("Value of s is %s \n", s);
    printf("Address of s is %p \n", s);

    s[0] = 'v';

    printf("Value of s is %s \n", s);
    printf("Address of s is %p \n", s);
}

Using gdb, I figure out that s[0] = 'v' is invalid and lead to segmentation fault. Why is it the case? Can anyone tell me the reason behind this as well? Thanks.

CHANist
  • 1,302
  • 11
  • 36
  • Check this question and its accepted answer: http://stackoverflow.com/questions/2245664/string-literals-in-c – Fernando Jan 08 '15 at 03:55

2 Answers2

2

This answer is based on a similar one of mine from some time ago.

By declaring a string in the manner you have, you have effectively created a const string that is stored in read only memory.

Short answer:


char A[] = "abc";  // 'A' points to a read-write string, which is 4 characters long { 'a', 'b', 'c', '\0' }
char* B;           // 'B' is a pointer that currently points to an unknown area since it isn't initialized
B = A;             // 'A' and 'B' now point to the same chunk of memory
char C[] = "abc";
snprintf(C, strlen(C)+1, "def"); // Modify the contents of the area 'C' points to, but don't change what 'C' actually points to.

Long answer:


Consider the example below:

char strGlobal[10] = "Global";

int main(void) {
  char* str = "Stack";
  char* st2 = "NewStack";
  str = str2;  // OK
  strcpy(str, str2); // Will crash
}

To be safe, you should actually allocate as a pointer to const data to make sure you don't attempt to modify the data.

const char* str = "Stack"; // Same effect as char* str, but the compiler
                           // now provides additional warnings against doing something dangerous

The first way of allocating memory is static allocation in read-only memory (ie: as with str and str2).

The second allocation is known as dynamic allocation, which allocates memory on the heap, not the stack. The string can be modified without hassle. At some point, you need to free this dynamically allocated memory via the free() command.

There is a third means of allocating a string, which is static allocation on the stack. This allows you to modify the contents of the array which is holding the string, and it is statically allocated.

char str[] = "Stack";

In summary:

Example:                       Allocation Type:     Read/Write:    Storage Location:
================================================================================
const char* str = "Stack";     Static               Read-only      Code segment
char* str = "Stack";           Static               Read-only      Code segment
char* str = malloc(...);       Dynamic              Read-write     Heap
char str[] = "Stack";          Static               Read-write     Stack
char strGlobal[10] = "Global"; Static               Read-write     Data Segment (R/W)
Community
  • 1
  • 1
Cloud
  • 18,753
  • 15
  • 79
  • 153
  • It looks like you copied a significant portion [of your other answer](http://stackoverflow.com/a/16021546/335858) - which is a pretty good answer, by the way. You may want to link that answer, so that in case you or someone else makes improvements to it, both places would benefit. – Sergey Kalinichenko Jan 08 '15 at 04:03
  • Thanks. I learn a lot from you and the summary is really cool. – CHANist Jan 08 '15 at 04:13
  • @dasblinkenlight Will do. Normally I just flag as a duplicate, but it gets ignored. – Cloud Jan 08 '15 at 05:08
  • @CHANist No prob. I just updated the answer and linked to the full source of it. These changes may likely help you. Good luck! – Cloud Jan 08 '15 at 05:12
  • 1
    "Code segment" isn't really correct. On ELF targets, it will end up in a `.rodata` section, which is separate from the `.text` section. And, those should be in different loaded segments as `.rodata` should be `r--` while `.txt` should be `r-x`, and `.data` should be `rw-`. – Jonathon Reinhart Jan 08 '15 at 05:19
  • @JonathonReinhart Thank you John. Do you have some tech docs or a book on that particular topic you could point me towards? It would be good to expand on my knowledge of that detail. :) – Cloud Apr 16 '15 at 13:41
  • 1
    On a Linux machine: `$ readelf -a random_elf_file` might be the most enlightening. That and `/proc/[some pid]/maps`. – Jonathon Reinhart Apr 16 '15 at 22:23
1

You can change a string only when its content resides in "writable" memory. When you do this

char* A = "abc";

the content of the string A, a string literal, resides in memory that cannot be written. However, if you change the declaration to this

char A[] = "abc";

your string would become writable, and you would be able to copy new content into it:

char A[] = "abc";
char* B = "def";
strcpy(A, B);

The address of the string would remain the same.

One caveat here is that you cannot copy a string into A if its content is longer than that of your original string. To work around this issue, declare A with a specific size, like this:

char A[100] = "abc";
char* B = "quick brown fox jumps over the lazy dog";
strcpy(A, B); // This would work fine
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523