Question

After reading the faq's and everything else I can find, I'm still confused. If I have a char pointer that is initialised in this fashion:

char *s = "Hello world!"

The string is in read-only memory and I cannot change it like this:

*s = 'W';

to make "Wello world!". This I understand, but I can't, for the life of me, understand how to make it NOT read-only. Do I have to use an array instead of a pointer? Like here?

This is my code:

char *s = str;
char *e = s;
while (*e != '\0')
e++;
e--;
char *temp;
//Swop the string around
while (s <= e) {
    *temp = *s;
    *s = *e;
    *e = *temp;
    e--;
    s++;
}

The error message is just a segmentation fault. Apologies in advance if this is a really stupid question.

Thanks so much for all the help. After taking all your advice, I get this:

void something(char * str) {
    char *store = str;
    char *s = new char[strlen(str) + 1]; //Allocate memory. Nice one.
    strcpy(s, str);
    char *e = new char[strlen(str) + 1];
    strcpy(e, str);
    while (*e != '\0')
        e++;
    e--;
    char temp; //no longer a pointer
    while (s <= e) {
        cout << *e;
        temp = *s;
        *s = *e;
        *e = temp;
        e--;
        s++;

    }
    delete [] e;
    delete [] s;        
}

however, the deletes at the end of the function seem to be causing their own segmentation faults. Why?

For interest's sake: The faults were due to accessing the e and s pointers after they were incremented. A much simpler solution followed from that:

void something(char * str) {
    char *s = new char[strlen(str) + 1];
    strcpy(s, str);
    char temp;
    int j = strlen(str) - 1;
    for (int i = 0; i <= strlen(str)/2; i++) {
        cout << s << endl;
        temp = s[i];
        s[i] = s[j];
        s[j] = temp;
        j--;
    }
    delete [] s;
}
Was it helpful?

Solution

The easiest way to modify it is to create an array for your storage, and then copy the string into it.

For example:

char buf[128];
const char *src = "Hello World";
strncpy(buf, src, 127); // one less - we always 0-terminate
buf[127] = '\0';

// you can now modify buf
buf[0] = 'W';

The reason your code doesn't work is that you haven't allocated any memory for the copy of the string - you've just made a second pointer to the same read-only memory. (And then tried to copy it? I'm not quite sure what the rest of the code is doing.) You need to get some non-read-only memory somewhere, and it's much easier to use the standard library to copy it into that new memory, rather than writing the loop yourself.

In the case when you don't know the length of the string beforehand, you can also use malloc (or, even better, do what drschnz's answer says and use new char[]):

const char *src = "Hello world";
char *buf = malloc(strlen(src) + 1);   // or = new char[strlen(src) + 1];
strcpy(buf, src);
// you can now modify buf
// later, you need to free it
free(buf);                             // or delete [] buf;

Also, if you're using C++, you can just use a std::string:

std::string myString("Hello world");
myString[0] = "W";

Hope that helps.

OTHER TIPS

Try:

char src[] = "Hello world";
src[6]     = 'W';

-- // or

char   buffer[] = "Hello world";
char*  src      = buffer;
src[6]          = 'W';

If you want to copy a string into a buffer then use strcpy() or strncpy()

char   buffer[20];
char const* s = "Hello World"

strcpy(s,buffer);

If you must write your own string copy then it should look like this:

char   buffer[20];
char const* s = "Hello World";

// OK this is not the perfect solution but it is easy to read.
for(int loop = 0;s[loop] != '\0';++loop)
{
    buffer[loop] = s[loop];
}
buffer[loop] = '\0';

The pointer is not read-only. (the string data itself is, but a pointer pointing to it can be modified freely) However, assigning a character to a pointer doesn't do what you expect.

In general, the only thing you can assign to a point is an address. You can't assign values, only the address of values.

String literals (like "hello world") are the one exception, because strings are special. If you assign one of those to a pointer, you get a pointer to that string. But in general, you assign addresses to pointers.

The other point is that characters in C++ are integral datatypes. They can be treated as integers with no casting required. I can do int i = 'W' and the compiler won't complain.

So what happens if you assign 'W' to a pointer? It takes 'W' as an integer value, and assumes that this is an address. 'W' has the ASCII value 127, so you are effectively setting your pointer to point to address 127, which doesn't make sense.

I don't see how that has much to do with your code though. The problem there seems to be that temp doesn't point to valid data. You declare a pointer, which points to some undefined address. And then you say "wherever it points to, I want to write the value that s points to. The following should work somewhat better:

char temp; // not a pointer. We want a character to store our temporary value in
while (s <= e) {
    temp = *s; // note, no * on temp.
    *s = *e;
    *e = temp; // note, no * on temp.
    e--;
    s++;
}

However, if str points to a string literal, like "hello world", then this won't be legal, because the string data itself is read-only. The compiler may not enforce it, but then you've ventured into undefined-behavior land. If you want to modify the string, copy it into a local buffer, as one of the other answers showed.

You seem a bit confused about the semantics of pointers. Assigning an address (or something that can be converted to an address, like an integer) to a pointer makes the pointer point to that address. It doesn't modify the pointed-to data. Declaring a pointer doesn't mean that it will point to anything meaningful. If you want to store a char, declare a char variable. A pointer doesn't store data, it just points to data allocated elsewhere.

edit Comments and fixes to your updated code:

void something(const char * str) { // let the function take a pointer to a non-modifiable string, so add the const. Now it's clear that we're not allowed to modify the string itself, so we have to make a copy.
    char *s = new char[strlen(str) + 1]; // Since the original string is const, we have to allocate a copy if we want to modify it - in C, you'd use malloc(strlen(str)) instead
    strcpy(s, str);
    char *e = s; // make e point to the start of the copied string (don't allocate two copies, since e and s are supposed to work on the same string
    while (*e != '\0') { // add braces so it's clear where the loop starts and ends.
        e++;
    }
    e--;

    while (s <= e) { // the loop condition wouldn't work if s and e pointed to separate copies of the string
        cout << *e; // why? I thought you just wanted to reverse the string in memory. Alternatively, if you just want to print out the string reversed, you don't need to do most of the rest of the loop body. In C, you'd use printf instead of *e
        char temp = *s; // might as well declare the temp variable when you need it, and not before
        *s = *e;
        *e = temp;
        e--;
        s++;

    }
}

Just for reference, and in response to the comments about C vs C++, here's how I'd write a function to reverse a string in C++:

std::string revert_string(const std::string& str) {
  return std::string(str.rbegin(), str.rend());
}

Or to revert the string in-place:

std::string revert_string(const std::string& str) {
  std::reverse(str.begin(), str.end());
}

Technically, what you have is more correctly written like that:

const char *s = "Hello world!"

What you actually want to have is something like that:

char s[] = "Hello world!"

Following few lines may help you understanding more:

const char *p = "Hello World";
char q[] = "Hello World";
printf("%d %d", sizeof(p), sizeof(q));
// p[0] = 'W' // INVALID
q[0] = 'W'; // valid

Your deletes generate faults, because you changed the pointer. You should save the original location of the new, and delete[] it. You try to delete a location that isn't in the allocation table. If you want to change the pointer value, make another char *temp = t; and use it to iterate over the string.

There#s a function "strdup()" to make a copy of a string...it makes sure you don't forget the "+1" in your malloc.

char* source = "Hello World";
char* dest = strdup(source);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top