98

I have been struggling for a few hours with all sorts of C tutorials and books related to pointers but what I really want to know is if it's possible to change a char pointer once it's been created.

This is what I have tried:

char *a = "This is a string";
char *b = "new string";

a[2] = b[1]; // Causes a segment fault

*b[2] = b[1]; // This almost seems like it would work but the compiler throws an error.

So is there any way to change the values inside the strings rather than the pointer addresses?

Ken Wayne VanderLinde
  • 18,915
  • 3
  • 47
  • 72
Matthew Stopa
  • 3,793
  • 6
  • 42
  • 51

9 Answers9

180

When you write a "string" in your source code, it gets written directly into the executable because that value needs to be known at compile time (there are tools available to pull software apart and find all the plain text strings in them). When you write char *a = "This is a string", the location of "This is a string" is in the executable, and the location a points to, is in the executable. The data in the executable image is read-only.

What you need to do (as the other answers have pointed out) is create that memory in a location that is not read only--on the heap, or in the stack frame. If you declare a local array, then space is made on the stack for each element of that array, and the string literal (which is stored in the executable) is copied to that space in the stack.

char a[] = "This is a string";

you can also copy that data manually by allocating some memory on the heap, and then using strcpy() to copy a string literal into that space.

char *a = malloc(256);
strcpy(a, "This is a string");

Whenever you allocate space using malloc() remember to call free() when you are finished with it (read: memory leak).

Basically, you have to keep track of where your data is. Whenever you write a string in your source, that string is read only (otherwise you would be potentially changing the behavior of the executable--imagine if you wrote char *a = "hello"; and then changed a[0] to 'c'. Then somewhere else wrote printf("hello");. If you were allowed to change the first character of "hello", and your compiler only stored it once (it should), then printf("hello"); would output cello!)

iluxa
  • 6,941
  • 18
  • 36
Carson Myers
  • 37,678
  • 39
  • 126
  • 176
  • 13
    The last section explained me a lot on why that needs to be readonly. Thank you. – CDR Jun 18 '09 at 09:07
  • 1
    -1: doesn't tell to use const char*, and nothing guarantees that literal strings are stored in executable memory. – Bastien Léonard Jun 18 '09 at 09:42
  • I don't you don't need const for the two solutions I've given--also, if the string is known at compile time, and compiled into the executable--where else would it get stored? In gcc, if I write either char *a = "hallo."; or char b[] = "hello.";, then the assembly outputs "LC0: .ascii "Hallo.\0" LC1: .ascii "Hello.\0"" both are in executable memory... When is it not? – Carson Myers Jun 18 '09 at 18:33
  • 1
    Just tried with GCC 4.4, it puts literal strings in .rodata (read-only data). I checked with objdump and the assembly listing. I don't think the standard *requires* literal strings to be read-only, so I think they could even be put in .data. – Bastien Léonard Jun 19 '09 at 13:35
  • Also, I don't see any advantage in not qualifying the pointer as const. It may hide bugs if later you decide to change the string. – Bastien Léonard Jun 19 '09 at 13:36
  • I thought everything that was saved in the executable image was readonly... also, the OP wanted to know how to *change* an array of chars--the two examples I have given make mutable char arrays--if they were const, that would defeat the purpose of allocating on the stack or heap instead of just pointing to a string literal. – Carson Myers Jun 20 '09 at 05:08
  • @CarsonMyers Any references that 'everything that was saved in the executable image was readonly'? – Tony Jul 18 '14 at 08:58
  • @Tony It doesn't necessarily have to be but that's beside the point - I was trying to explain the difference between pointers to string literals and arrays initialized with a string literals. I said read only because the OP was getting a segmentation fault. Keep in mind I wrote this answer over 5 years ago (I was 19 years old at the time). – Carson Myers Jul 18 '14 at 22:52
  • @CarsonMyers I am just wondering where is the string literals located in? – Tony Jul 19 '14 at 08:41
  • String literals are copied into the executable at compile time and are referenced using pointers into the program data. Generally you cannot modify this data at runtime (or if you can, you probably shouldn't). It can be copied into the stack or heap and modified there, though. – Carson Myers Jul 21 '14 at 23:27
  • So, char *a = "Hello"; is stored in the read-only executable while char a[] = "Hello" is stored in read/write memory space. Is that correct? – mrbean Oct 19 '20 at 19:24
  • Both will store `"Hello"` in the executable, but `char a[] = "Hello"` will also copy that data into an array stored on the stack, whereas `char *a = "Hello"` will just point to the original data – Carson Myers Oct 21 '20 at 11:35
34

No, you cannot modify it, as the string can be stored in read-only memory. If you want to modify it, you can use an array instead e.g.

char a[] = "This is a string";

Or alternately, you could allocate memory using malloc e.g.

char *a = malloc(100);
strcpy(a, "This is a string");
free(a); // deallocate memory once you've done
Jonathan Maddison
  • 1,067
  • 2
  • 11
  • 24
20

A lot of folks get confused about the difference between char* and char[] in conjunction with string literals in C. When you write:

char *foo = "hello world";

...you are actually pointing foo to a constant block of memory (in fact, what the compiler does with "hello world" in this instance is implementation-dependent.)

Using char[] instead tells the compiler that you want to create an array and fill it with the contents, "hello world". foo is then a pointer to the first index of the char array. They both are char pointers, but only char[] will point to a locally allocated and mutable block of memory.

Løiten
  • 3,185
  • 4
  • 24
  • 36
Jeff Ober
  • 4,967
  • 20
  • 15
9

The memory for a & b is not allocated by you. The compiler is free to choose a read-only memory location to store the characters. So if you try to change it may result in seg fault. So I suggest you to create a character array yourself. Something like: char a[10]; strcpy(a, "Hello");

Naveen
  • 74,600
  • 47
  • 176
  • 233
  • 1
    The problem with character arrays is that I am passing a pointer of a char array to a function so I could manipulate a string there and then ship it out again. Looks like I have to use malloc unfortunately. – Matthew Stopa Jun 18 '09 at 08:37
  • 1
    No you can still use the object allocated on stack. For example if you have a function void f(char *p); then from main() you can pass f(a). This will pass the address of the first character to the function. Also, if you decide to go by malloc() then don't forget to release the memory using free(). – Naveen Jun 18 '09 at 08:41
7

It seems like your question has been answered but now you might wonder why char *a = "String" is stored in read-only memory. Well, it is actually left undefined by the c99 standard but most compilers choose to it this way for instances like:

printf("Hello, World\n");

c99 standard(pdf) [page 130, section 6.7.8]:

The declaration:

char s[] = "abc", t[3] = "abc";

defines "plain" char array objects s and t whose elements are initialized with character string literals. This declaration is identical to char

s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };

The contents of the arrays are modifiable. On the other hand, the declaration

char *p = "abc";

defines p with type "pointer to char" and initializes it to point to an object with type "array of char" with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p to modify the contents of the array, the behavior is undefined.

Sweeney
  • 672
  • 4
  • 6
6

You could also use strdup:

   The strdup() function returns a pointer to a new string which is a duplicate of the string  s.
   Memory for the new string is obtained with malloc(3), and can be freed with free(3).

For you example:

char *a = strdup("stack overflow");
Maxime Chéramy
  • 17,761
  • 8
  • 54
  • 75
2

All are good answers explaining why you cannot modify string literals because they are placed in read-only memory. However, when push comes to shove, there is a way to do this. Check out this example:

#include <sys/mman.h>
#include <unistd.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

int take_me_back_to_DOS_times(const void *ptr, size_t len);

int main()
{
    const *data = "Bender is always sober.";
    printf("Before: %s\n", data);
    if (take_me_back_to_DOS_times(data, sizeof(data)) != 0)
        perror("Time machine appears to be broken!");
    memcpy((char *)data + 17, "drunk!", 6);
    printf("After: %s\n", data);

    return 0;
}

int take_me_back_to_DOS_times(const void *ptr, size_t len)
{
    int pagesize;
    unsigned long long pg_off;
    void *page;

    pagesize = sysconf(_SC_PAGE_SIZE);
    if (pagesize < 0)
        return -1;
    pg_off = (unsigned long long)ptr % (unsigned long long)pagesize;
    page = ((char *)ptr - pg_off);
    if (mprotect(page, len + pg_off, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
        return -1;
    return 0;
}

I have written this as part of my somewhat deeper thoughts on const-correctness, which you might find interesting (I hope :)).

Hope it helps. Good Luck!

0

You need to copy the string into another, not read-only memory buffer and modify it there. Use strncpy() for copying the string, strlen() for detecting string length, malloc() and free() for dynamically allocating a buffer for the new string.

For example (C++ like pseudocode):

int stringLength = strlen( sourceString );
char* newBuffer = malloc( stringLength + 1 );

// you should check if newBuffer is 0 here to test for memory allocaton failure - omitted

strncpy( newBuffer, sourceString, stringLength );
newBuffer[stringLength] = 0;

// you can now modify the contents of newBuffer freely

free( newBuffer );
newBuffer = 0;
Nathan Fellman
  • 122,701
  • 101
  • 260
  • 319
sharptooth
  • 167,383
  • 100
  • 513
  • 979
-1
char *a = "stack overflow";
char *b = "new string, it's real";
int d = strlen(a);

b = malloc(d * sizeof(char));
b = strcpy(b,a);
printf("%s %s\n", a, b);
Nathan Fellman
  • 122,701
  • 101
  • 260
  • 319
  • 6
    The malloc needs 1 more byte. Don't forget the NULL termination character, which strcpy expects, and will copy too. This is an all-too-frequent mistake. – xcramps Jun 18 '09 at 09:53
  • This doesn't modify the initial string value of b, but instead makes b (a char pointer) to point to a new location. – perrocallcenter Jan 08 '23 at 23:52