1

I have a situation where I want to efficiently remove a character from a NULL-terminated char *. I can assume the incoming string is large (i.e. it wouldn't be efficient to copy); but I can also assume that I don't need to de-allocate the unused memory.

I thought I could use std::remove_if for this task (replacing the character at the returned iterator with a NULL-terminator), and set up the following test program to make sure I got the syntax correct:

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

This program compiles, however, I'm getting a Segmentation Fault somewhere in remove_if - here's the output from 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;

This is with gcc 4.1.2 on RedHat 4.1.2-52.

My understanding was that raw pointers can be used as ForwardIterators, but perhaps not? Any suggestions?

Tom
  • 2,369
  • 13
  • 21

2 Answers2

5

The program has undefined behaviour as it is attempting to modify a string literal:

char * test1 = "123a45";

Change to:

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

See http://ideone.com/yzeo4k.

hmjd
  • 120,187
  • 20
  • 207
  • 252
4

Your program has undefined behavior, since you are trying to modify an array of const characters (string literals are arrays of const characters). Per paragraph 7.1.6.1/4 of the C++11 Standard:

Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior.

Notice, that since C++11 the conversion from a string literal to a char* is illegal, and in C++03 is deprecated (GCC 4.7.2 gives me a warning for that).

To fix your program with a minimal change, declare test1 as an array of characters and initialize it from the string literal:

char test1[] = "123a45";

Here is a live example.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451