4

Sorry in advance for any possible duplicate question. I have been Googling a solution for my compiler error, for a week now, tried different workarounds from various answers around here, yet I keep getting some errors.

I am currently learning C++, trying to build a program that does basic stuff like vowel/consonant count, letter removal etc. Everything works fine until I get to the custom letter removal part. Basically, it's near impossible to do that using character functions (according to my knowledge), while converting to a string seems to spawn other kinds of errors.

Here is the code fragment where I keep getting errors:

if (strcmp (service, key4) ==0)
{
string str(s);

cout<<endl<<"Please insert the letter you would like removed from your "<<phrasal<<":"<<endl;

cin>>letterToRemove;

s.erase(remove(s.begin(), s.end(),letterToRemove), s.end());

cout<<endl<<s<< "\n"<<endl;
}

and here are initialized variable I used:

int main()

{
char s[1000], phrasal[10], service[50], key1[] = "1", key2[] = "2", key3[] = "3", key4[] = "4", key5[] = "5", key6[] = "6", key0[] = "0", *p, letterToRemove;

int vowel=0, vowel2=0, consonant=0, consonant2=0, b, i, j, k, phrase=0, minusOne, letter, idxToDel;

void pop_back();

char *s_bin;

As you can see, the original 's' is a char array. In the first code sample I have tried converting it into a string array (string str(s)), but that results in the following compiling errors:

  • error: request for member 'erase' in 's', which is of non-class type 'char[1000]'
  • error: request for member 'begin' in 's', which is of non-class type 'char[1000]'
  • error: request for member 'end' in 's', which is of non-class type 'char[1000]'
  • error: request for member 'end' in 's', which is of non-class type 'char[1000]'

The other workaround I've tried was this:

if(strcmp(service, key4)==0)

{std::string s(s);

cout<<endl<<"Please insert the letter you would like removed from your "<<phrasal<<":"<<endl;

cin>>letterToRemove;

s.erase(remove(s.begin(), s.end(),letterToRemove), s.end());

cout<<endl<<s<< "\n"<<endl;
}

Now here's the funny part, I get no errors whatsoever for this one, but the debug crashes as soon as I select the custom letter removal feature. Here's what it says:

"terminate called after throwing an instance of 'std::length_error' what(): basic_string::_S_create          This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information."

Any help would be much appreciated, stuck at this one for a week now!

P.S. Is it okay if I or a moderator deletes this question after it's been answered? I'm quite sure I'm not the first one who asks this, but, as before-hand mentioned, I keep getting these errors, even after following answers from similar questions.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
Eludium
  • 61
  • 1
  • 1
  • 6
  • 1
    Are you coding in C or C++? Is `s` a string? If you are coding in C++ and `s` is a string, then why don't use `std::string` to begin with? – Some programmer dude Aug 24 '16 at 11:45
  • 4
    no it's not ok to ask a question, get the answer and then delete the question. We are a community here and your question and answers could help others. – bolov Aug 24 '16 at 11:46
  • 1
    As for your errors, try using e.g. `str.erase(...)` instead. – Some programmer dude Aug 24 '16 at 11:46
  • 1
    `std::string s(s);` What do you think this does? It's UB because you use the value of an uninitialized object (ironically in an attempt to initialize that object). – bolov Aug 24 '16 at 11:47
  • The first failure about begin and end... Raw arrays cannot be treated as containers, so you can't std::begin() or std::end() them. Also, you seem to be constructing a std::string "s" with "s": what's that supposed to do?. You should be constructing it with the original string ("prhasal", I assume?"). – The Marlboro Man Aug 24 '16 at 11:47
  • @JoachimPileborg C++. 's' was initially a char, as shown in the second code fragment (char s[1000]). I have previously read that a solution for this would be converting the char array into a string array, yet that still gives errors, as above. – Eludium Aug 24 '16 at 11:49
  • 1
    @Teo If you program in `C++` then do so. Use `std::string` from the begging. – bolov Aug 24 '16 at 11:50
  • @bolov Thank you for the heads-up, my intention is just not to flood the archive. I've tried doing that aswell, but my code previously uses character functions such as strcpy and strcmp, I would have to rewrite 113 lines of code, so I was curious if there is any way of making it work by editing this portion – Eludium Aug 24 '16 at 11:51
  • @Teo Good questions are valued. So when you ask good questions you are actually contributing here. – bolov Aug 24 '16 at 11:53

3 Answers3

9

For a char array you have to use std::remove instead of erase, and insert the null-terminator manually:

auto newEnd = std::remove(std::begin(s), std::end(s), letterToRemove);
*newEnd = '\0';
Emil Laine
  • 41,598
  • 9
  • 101
  • 157
  • Thank you. Both yours and @baddger964 's answers seems to have solved this problem. However, what exactly happens to the _char s[ ]_ array after I have converted it using _string str(s)_ ? My code consists of some loops that will make it go back to certain points, where the operator is required to insert a word/phrase based on the _cin.getline_ format (to be as detailed as possible, you have to insert a sentence which equals '_cin.getline(service, 50)_' ; depending on your input, the standard will have to apply some **char** functions to the **s** array). Thank you for your time. – Eludium Aug 24 '16 at 14:08
  • _"what exactly happens to the char s[ ] array after I have converted it using string str(s) ?"_ — Nothing. The characters are copied into the `std::string` object, and the array is left untouched. – Emil Laine Aug 24 '16 at 15:02
  • Thanks @tuple_cat, that's great! – Eludium Aug 24 '16 at 15:31
1

If you have a generic array, that may or may not have decayed to a pointer, and you have the number of elements in the array but no other terminator (i.e. it's not a C-style zero-terminated string), then here's a solution:

First I want to you think abut how the array looks in memory. For example if we have an array of characters

char array[X] = { 'A', 'B', 'C', 'D', ... };

This array will look like this in memory

+---+---+---+---+-----+
| A | B | C | D | ... |
+---+---+---+---+-----+

If you wanted to remove the letter 'B' from that array you find the position of the letter, then you copy the next letter ('C') into its place, and the next next letter ('D') into the next letter place, etc.

You can of course do this using a single loop:

size_t index_to_remove = 1;  // The index of 'B'
for (size_t i = index_to_remove = 1; i < element_count - 1; ++i)
    array[i] = array[i + 1];

The above loop is simple, easy to figure out, and easy to step through in a debugger. It is also not very effective, especially if the array is large.

All the above copying can actually be done using a single call to the memmove function:

memmove(&array[index_to_remove],
        &array[index_to_remove + 1],
        element_count - index_to_remove - 1);

The above call will basically do the same as our loop above but in a more efficient and optimized way.

Using either of the above methods, the loop or the memmove call, will leave the array like this:

+---+---+---+-----+
| A | C | D | ... |
+---+---+---+-----+

Important note: Remember to change element_count after you "removed" the character, so it reflects the new size.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Yep, that's how it works indeed, but for my code you do not have an already known position for the element you want removed; the operator inputs a number/letter and the program would have to search for that element in the string array... which brings it to another questioning: what algorithm should I apply after the **strchr** function, that will basically do what you pinpointed in your example above? Thanks for the highly detailed answer, though, I appreciate it. – Eludium Aug 24 '16 at 14:19
  • @Teo If you are using `strchr`, or any other C string function on this array, then it *is* a string and you should really be using `std::string`. – Some programmer dude Aug 24 '16 at 14:22
  • @Teo As for your question in the comment, you can actually subtract two (related) pointers to get the difference. If you subtract `s` from the (non-null) pointer you get from `strchr` you get an offset that can be used as an index. Or you use the result from `strchr` directly in the call to `memmove`. – Some programmer dude Aug 24 '16 at 14:23
0

For your first workaround :

string str(s);

This statement declare a string named str and is content is initialized with the content of s

This statement as no effect on you object s

So you need to call str.erase() not s.erase()

baddger964
  • 1,199
  • 9
  • 18