2

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

char *s = "Hello world!"

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

*s = 'W';

制作“Wello world!”。我明白这一点,但我不能,就我的一生,了解如何使它不是只读的。我必须使用数组而不是指针吗?喜欢这里吗?

这是我的代码:

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

6 回答 6

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';
于 2009-03-15T15:47:32.317 回答
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";

希望有帮助。

于 2009-03-15T15:38:47.470 回答
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 与 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());
}
于 2009-03-15T15:48:56.447 回答
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
于 2009-03-15T15:50:23.713 回答
0

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

于 2009-03-15T16:22:58.627 回答
0

有#sa 函数“strdup()”来制作字符串的副本……它确保您不会忘记 malloc 中的“+1”。

char* source = "Hello World";
char* dest = strdup(source);
于 2009-03-15T16:38:39.073 回答