1

我有一种情况,我想有效地从 NULL 终止的 char * 中删除一个字符。我可以假设传入的字符串很大(即复制效率不高);但我也可以假设我不需要取消分配未使用的内存。

我想我可以使用std::remove_if这个任务(用 NULL 终止符替换返回的迭代器中的字符),并设置以下测试程序以确保我的语法正确:

#include <algorithm>
#include <iostream>

bool is_bad (const char &c) {
  return c == 'a';
}

int main (int argc, char *argv[]) {
  char * test1 = "123a45";
  int len = 6;
  std::cout << test1 << std::endl;
  char * new_end = std::remove_if(&test1[0], &test1[len], is_bad);
  *new_end = '\0';
  std::cout << test1 << std::endl;

  return 0;
}

这个程序编译,但是,我得到了一个Segmentation Fault地方remove_if- 这是来自的输出gdb

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400914 in std::remove_copy_if<char*, char*, bool (*)(char const&)> (__first=0x400c2c "45", __last=0x400c2e "", __result=0x400c2b "a45", 
    __pred=0x4007d8 <is_bad(char const&)>) at /usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:1218
1218                *__result = *__first;

这是gcc 4.1.2在 RedHat 4.1.2-52 上的。

我的理解是原始指针可以用作ForwardIterators,但也许不是?有什么建议么?

4

2 回答 2

5

该程序在尝试修改字符串文字时具有未定义的行为:

char * test1 = "123a45";

改成:

char test1[] = "123a45"; // 'test1' is a copy of the string literal.
char * new_end = std::remove_if(test1, test1 + sizeof(test1), is_bad);

请参阅http://ideone.com/yzeo4k

于 2013-05-28T22:45:07.803 回答
4

您的程序具有未定义的行为,因为您正在尝试修改const字符数组(字符串文字是const字符数组)。根据 C++11 标准的第 7.1.6.1/4 段:

mutable除了可以修改声明的任何类成员(7.1.1)外,任何const 在其生命周期(3.8)期间修改对象的尝试都会导致未定义的行为。

请注意,从 C++11 开始,从字符串文字到 a 的转换char*是非法的,并且在 C++03 中已弃用(GCC 4.7.2 对此给出了警告)。

要以最小的更改来修复您的程序,请声明test1为一个字符数组并从字符串文字初始化它:

char test1[] = "123a45";

这是一个活生生的例子

于 2013-05-28T22:45:57.467 回答