8

所以我试图将 a 附加char到 a char*

例如我有char *word = " "; 我也有char ch = 'x';

我确实append(word, ch);使用这种方法..

void append(char* s, char c)
{

    int len = strlen(s);
    s[len] = c;
    s[len+1] = '\0';
}

它给了我一个分段错误,我明白我为什么这么想。因为s[len]越界了。我如何使它起作用?如果我要使用 char word[500]; 之类的东西,我也需要清除char*很多。一旦它附加了一些字符,我将如何清除它?会strlen一直这样500吗?提前致谢。

4

5 回答 5

11

典型的 C 实践如下:

//returns 1 if failed, 0 if succeeded 
int  append(char*s, size_t size, char c) {
     if(strlen(s) + 1 >= size) {
          return 1;
     }
     int len = strlen(s);
     s[len] = c;
     s[len+1] = '\0';
     return 0;
}

传递函数时,要修改函数的数组在编译时不知道它有多少空间。C 中的通常做法是也传递数组的长度,如果函数无法在其拥有的空间中完成工作,函数将信任此边界并失败。另一种选择是重新分配并返回新数组,您需要返回char*char**作为输入,但您必须仔细考虑在这种情况下如何管理堆内存。但是如果没有重新分配,是的,如果在没有剩余空间时要求附加,您的函数必须以某种方式失败,如何失败取决于您。

于 2012-10-17T16:56:47.663 回答
5

很难在 C 中就地附加到字符串。试试这样的事情:

char *append(const char *s, char c) {
    int len = strlen(s);
    char buf[len+2];
    strcpy(buf, s);
    buf[len] = c;
    buf[len + 1] = 0;
    return strdup(buf);
}

确保在完成后释放返回的字符串。

仅供参考:可能是因为您传递的字符串存储在只读内存中,所以可能会出现段错误。但你是对的,你也在写完结尾([len+1]写,而不是那个[len])。

于 2012-10-17T16:57:36.043 回答
3

如果你通过

append("foo", 'X');

它会崩溃,因为 foo 通常放在只读存储中。即使不是,它也可能会覆盖一些不好的东西!在这种情况下,编译器应该警告您从 const char * 到 char * 的转换,这将是一个线索。

于 2012-10-17T16:55:29.050 回答
0

是的,您所做的假设是 - 几乎 - 正确 - 崩溃可能是因为您试图写入字符串的边界(实际上只是s[strlen(s) + 1]超出范围,因为s[strlen(s)]它仍然是一个有效位置 - 终止 NUL 字节被存储那里)。但是您也不能修改字符串文字,因为它通常位于进程内存的某个只读部分中。这两个动作都会导致调用未定义的行为,这可能会导致崩溃。您可以通过将字符串复制到动态分配的存储空间然后修改副本来解决此问题。此外,您应该const char *在函数的参数中使用,因为这char *表明只读字符串不能传入。

char *append(const char *orig, char c)
{
    size_t sz = strlen(orig);
    char *str = malloc(sz + 2);
    strcpy(str, orig);
    str[sz] = c;
    str[sz + 1] = '\0';
    return str;
}

free()此外,当不再需要返回的字符串时,不要忘记它。

于 2012-10-17T17:01:00.740 回答
0

您不能真正安全地附加到任意字符串,因为首先,字符串常量往往位于只读内存中,因此尝试写入它们可能会导致分段错误,其次,您无法保证如果他们给了你一个缓冲区,你还没有在它结束时拍摄。

特别是,如果您执行 char x[500];

不能保证 strlen(x) 会返回 500。它会返回从 x 的开头开始向前计数的字符数,然后才达到空值。它可能会返回 0、1 ... 500、501 ...,具体取决于 x 中的内容。

实际上,您唯一的选择是使用要附加到的缓冲区的大小来调用 append (因此,如果缓冲区已满,您可以做一些适当的事情),或者每次调用 append 时都分配一个新缓冲区,在这种情况下,您当然需要再次释放缓冲区。

于 2012-10-17T17:02:29.380 回答