为什么我不能为指针赋值?

时间:2009-03-15 15:33:25

标签: c++ pointers segmentation-fault readonly

在阅读了faq和我能找到的其他所有内容之后,我仍然感到困惑。如果我有一个以这种方式初始化的char指针:

char *s = "Hello world!"

字符串在只读内存中,我无法像这样更改它:

*s = 'W';

制作“Wello world!”。我理解这一点,但对于我的生活,我不能理解如何使它不是只读的。我必须使用数组而不是指针吗?喜欢here

这是我的代码:

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++;
}

错误消息只是一个分段错误。如果这是一个非常愚蠢的问题,请提前道歉。

非常感谢所有的帮助。在接受了所有建议后,我明白了:

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;        
}

但是,函数末尾的删除似乎导致了它们自己的分段错误。为什么?

为了感兴趣:故障是由于在增加后访问e和s指针。一个更简单的解决方案:

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;
}

6 个答案:

答案 0 :(得分:7)

尝试:

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

-- // or

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

如果要将字符串复制到缓冲区中,请使用strcpy()或strncpy()

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

strcpy(s,buffer);

如果你必须编写自己的字符串副本,那么它应该如下所示:

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';

答案 1 :(得分:6)

修改它的最简单方法是为存储创建一个数组,然后将字符串复制到其中。

例如:

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';

您的代码不起作用的原因是您没有为字符串的副本分配任何内存 - 您刚刚创建了指向同一只读内存的第二个指针。 (然后尝试复制它?我不太确定代码的其余部分是做什么的。)你需要在某处获得一些非只读内存,并且使用标准库将其复制到那个新的记忆,而不是自己写的循环。

如果你事先不知道字符串的长度,你也可以使用malloc(或者更好的是,做drschnz的答案并使用 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;

另外,如果您使用的是C ++,则可以使用std :: string:

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

希望有所帮助。

答案 2 :(得分:2)

指针不是只读的。 (字符串数据本身是,但指向它的指针可以自由修改)但是,将一个字符分配给指针并不能达到预期效果。

通常,您可以分配给一个点的唯一事情是地址。您不能指定值,只能指定值的地址。

字符串文字(如“hello world”)是一个例外,因为字符串是特殊的。如果将其中一个指定给指针,则会得到指向该字符串的指针。但一般来说,你为指针分配地址。

另一点是C ++中的字符是整数数据类型。它们可以被视为整数,不需要铸造。 我可以做int i = 'W',编译器不会抱怨。

那么如果将'W'分配给指针会发生什么?它将'W'作为整数值,并假设这是一个地址。 'W'的ASCII值为127,因此您有效地将指针设置为指向地址127,这没有意义。

我不知道这与你的代码有什么关系。 问题似乎是temp没有指向有效数据。您声明一个指向某个未定义地址的指针。然后你说“无论它指向哪里,我都想写出s指向的值。以下应该会更好一些:

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++;
}

但是,如果str指向字符串文字,例如“hello world”,那么这将不合法,因为字符串数据本身是只读的。编译器可能不强制执行它,但是你已经冒险进入未定义行为的土地。如果要修改字符串,请将其复制到本地缓冲区中,如其他答案之一所示。

你似乎对指针的语义有点困惑。将指针(或可以转换为地址的东西,如整数)分配给指针使指针指向该地址。它不会修改指向的数据。 声明指针并不意味着它会指向任何有意义的东西。如果要存储char,请声明char变量。指针不存储数据,只指向其他地方分配的数据。

修改的 对更新后代码的评论和修正:

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++;

    }
}

仅供参考,并回应有关C vs C ++的评论,这里是我如何编写一个函数来反转C ++中的字符串:

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

或者就地恢复字符串:

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

答案 3 :(得分:1)

从技术上讲,你所拥有的内容更加正确:

const char *s = "Hello world!"

你真正想要的是这样的:

char s[] = "Hello world!"

以下几行可以帮助您了解更多信息:

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

答案 4 :(得分:0)

您的删除会生成错误,因为您更改了指针。您应该保存新的原始位置,并删除它[]。您尝试删除不在分配表中的位置。 如果要更改指针值,请创建另一个char * temp = t;并用它来迭代字符串。

答案 5 :(得分:0)

有一个函数“strdup()”来复制一个字符串...它确保你不会忘记你的malloc中的“+1”。

char* source = "Hello World";
char* dest = strdup(source);