I meant to write program which will simply delete single letters from the input given by user, let's say we've got some text like: "monkey eat banana" and we supposed to delete the letter 'a' from the text above.
The final output supposed to look like this:
'monkey et bnn'
I've got the code which works pretty much flawlessly with single strings, but I have to use getline() function to obtain some longer texts, that is why I have to declare array of string, in order to pass it's size in the second argument of getline() function, like so:
string text[256];
getline(text, 256);
I would like to use getline() function without giving a size of an array, but I think it's impossible, therefore I need to stick with string array instead of a string.
The problem I've got is that I don't know how to correctly pass array of string, to use it as function's argument. Here's my code;
#include <iostream>
#include <string>
using namespace std;
void deleteLetter(string &text[], char c)
{
size_t positionL = text.find(c);
if(positionL == string::npos)
cout << "I'm sorry, there is no such letter in text" << endl;
else
text.erase(positionL, positionL);
cout << "After your character removed: " << text << endl;
}
int main()
{
string str1[256];
char a = 'a';
cin.getline(str1, 256);
deleteLetter(str1, a);
}
I know it's elementary stuff, but still I can't figure it out on my own.
Perhpahs I should reach out for your help.
It sounds to me like you don't need an array of strings. Just to read as many characters the user types, into a string. getline should deal fine with this.
int main()
{
std::string str1; // just a string here, not an array.
std::getline (std::cin,str1);
deleteLetter(str1, 'a');
}
Now you should change the signature of DeleteLetter to take a single string as argument.
void deleteLetter(std::string& text, char c);
How your are going to implement deleteLetter is another question. The way you have it, it will delete only the first occurence of 'a'.
To read a string from console input (cin), you can use the getline() function:
std::string line;
std::getline(std::cin, line);
To remove all the occurrences of a given letter from a string, you can use the so called erase-remove idiom, with a combination of the string::erase() method and the std::remove() algorithm.
(Note that this idiom is usually showed applied to std::vector, but don't forget that a std::string can also be viewed as a "container of characters" stored in sequence, similar to vector, so this idiom can be applied to string content as well.)
To pass a std::string to functions/methods, use the usual C++ rules, i.e.:
If the function is observing the string (without modifying it), pass using const reference: const std::string &
If the function does modify the content of the string, you can pass using non-const reference: std::string &
A simple compilable code follows:
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
//
// NOTE:
// Since the content of 'text' string is changed by the
// removeLetter() function, pass using non-const reference (&).
//
void removeLetter(string& text, char letter)
{
// Use the erase-remove idiom
text.erase(remove(text.begin(), text.end(), letter),
text.end());
}
int main()
{
string line;
getline(cin, line);
cout << "Read string: " << line << endl;
removeLetter(line, 'a');
cout << "After removing: " << line << endl;
}
This is what I got with MSVC:
C:\Temp\CppTests>cl /EHsc /W4 /nologo test.cpp
test.cpp
C:\Temp\CppTests>test.exe
monkey eats banana
Read string: monkey eats banana
After removing: monkey ets bnn
It's not very clear to me from your question if you also want to pass vectors of strings around (probably in other parts of your code)...
Anyway, if you want a vector of strings (i.e. you want to store some strings in a vector container) you can simply combine these STL class templates like this:
std::vector<std::string> strings;
To pass that to functions/methods, use the usual C++ rules, i.e.:
If the function is observing the array of strings (without modifying it), pass using const references (const &): vector<string> &
If the function does modify the content of the vector, you can pass using non-const references (&): vector<string> &
Related
If I want to construct a std::string with a line like:
std::string my_string("a\0b");
Where i want to have three characters in the resulting string (a, null, b), I only get one. What is the proper syntax?
Since C++14
we have been able to create literal std::string
#include <iostream>
#include <string>
int main()
{
using namespace std::string_literals;
std::string s = "pl-\0-op"s; // <- Notice the "s" at the end
// This is a std::string literal not
// a C-String literal.
std::cout << s << "\n";
}
Before C++14
The problem is the std::string constructor that takes a const char* assumes the input is a C-string. C-strings are \0 terminated and thus parsing stops when it reaches the \0 character.
To compensate for this, you need to use the constructor that builds the string from a char array (not a C-String). This takes two parameters - a pointer to the array and a length:
std::string x("pq\0rs"); // Two characters because input assumed to be C-String
std::string x("pq\0rs",5); // 5 Characters as the input is now a char array with 5 characters.
Note: C++ std::string is NOT \0-terminated (as suggested in other posts). However, you can extract a pointer to an internal buffer that contains a C-String with the method c_str().
Also check out Doug T's answer below about using a vector<char>.
Also check out RiaD for a C++14 solution.
If you are doing manipulation like you would with a c-style string (array of chars) consider using
std::vector<char>
You have more freedom to treat it like an array in the same manner you would treat a c-string. You can use copy() to copy into a string:
std::vector<char> vec(100)
strncpy(&vec[0], "blah blah blah", 100);
std::string vecAsStr( vec.begin(), vec.end());
and you can use it in many of the same places you can use c-strings
printf("%s" &vec[0])
vec[10] = '\0';
vec[11] = 'b';
Naturally, however, you suffer from the same problems as c-strings. You may forget your null terminal or write past the allocated space.
I have no idea why you'd want to do such a thing, but try this:
std::string my_string("a\0b", 3);
What new capabilities do user-defined literals add to C++? presents an elegant answer: Define
std::string operator "" _s(const char* str, size_t n)
{
return std::string(str, n);
}
then you can create your string this way:
std::string my_string("a\0b"_s);
or even so:
auto my_string = "a\0b"_s;
There's an "old style" way:
#define S(s) s, sizeof s - 1 // trailing NUL does not belong to the string
then you can define
std::string my_string(S("a\0b"));
The following will work...
std::string s;
s.push_back('a');
s.push_back('\0');
s.push_back('b');
You'll have to be careful with this. If you replace 'b' with any numeric character, you will silently create the wrong string using most methods. See: Rules for C++ string literals escape character.
For example, I dropped this innocent looking snippet in the middle of a program
// Create '\0' followed by '0' 40 times ;)
std::string str("\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", 80);
std::cerr << "Entering loop.\n";
for (char & c : str) {
std::cerr << c;
// 'Q' is way cooler than '\0' or '0'
c = 'Q';
}
std::cerr << "\n";
for (char & c : str) {
std::cerr << c;
}
std::cerr << "\n";
Here is what this program output for me:
Entering loop.
Entering loop.
vector::_M_emplace_ba
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
That was my first print statement twice, several non-printing characters, followed by a newline, followed by something in internal memory, which I just overwrote (and then printed, showing that it has been overwritten). Worst of all, even compiling this with thorough and verbose gcc warnings gave me no indication of something being wrong, and running the program through valgrind didn't complain about any improper memory access patterns. In other words, it's completely undetectable by modern tools.
You can get this same problem with the much simpler std::string("0", 100);, but the example above is a little trickier, and thus harder to see what's wrong.
Fortunately, C++11 gives us a good solution to the problem using initializer list syntax. This saves you from having to specify the number of characters (which, as I showed above, you can do incorrectly), and avoids combining escaped numbers. std::string str({'a', '\0', 'b'}) is safe for any string content, unlike versions that take an array of char and a size.
In C++14 you now may use literals
using namespace std::literals::string_literals;
std::string s = "a\0b"s;
std::cout << s.size(); // 3
Better to use std::vector<char> if this question isn't just for educational purposes.
anonym's answer is excellent, but there's a non-macro solution in C++98 as well:
template <size_t N>
std::string RawString(const char (&ch)[N])
{
return std::string(ch, N-1); // Again, exclude trailing `null`
}
With this function, RawString(/* literal */) will produce the same string as S(/* literal */):
std::string my_string_t(RawString("a\0b"));
std::string my_string_m(S("a\0b"));
std::cout << "Using template: " << my_string_t << std::endl;
std::cout << "Using macro: " << my_string_m << std::endl;
Additionally, there's an issue with the macro: the expression is not actually a std::string as written, and therefore can't be used e.g. for simple assignment-initialization:
std::string s = S("a\0b"); // ERROR!
...so it might be preferable to use:
#define std::string(s, sizeof s - 1)
Obviously you should only use one or the other solution in your project and call it whatever you think is appropriate.
I know it is a long time this question has been asked. But for anyone who is having a similar problem might be interested in the following code.
CComBSTR(20,"mystring1\0mystring2\0")
Almost all implementations of std::strings are null-terminated, so you probably shouldn't do this. Note that "a\0b" is actually four characters long because of the automatic null terminator (a, null, b, null). If you really want to do this and break std::string's contract, you can do:
std::string s("aab");
s.at(1) = '\0';
but if you do, all your friends will laugh at you, you will never find true happiness.
This question already has answers here:
How do I print out the contents of a vector?
(31 answers)
Closed 1 year ago.
Why doesn't this vector print out?
void str_read(std::vector<char> str);
int main() {
std::vector<char> str;
str_read(str);
std::cout << str << std::endl;
return -1;
}
void str_read(std::vector<char> str) {
while (1) {
char ch;
scanf("%c", &ch);
if (ch == '\n');
break;
}
}
I get an error:
error: no type named 'type' in 'struct std::enable_if<false, void>'
You get the error because there is no standard operator<< defined for std::vector. If you want that, you have to implement it yourself.
Even so, str_read() takes in a std::vector by value, so it receives a copy of the caller's vector, and thus any modifications it makes will be to that copy and thus lost when str_read() exits. That means the vector in main() is never populated.
Try this instead:
#include <iostream>
#include <vector>
#include <string>
std::ostream operator<<(std::ostream &out, const std::vector<char> &vec) {
for(auto ch : vec) {
out << ch;
}
return out;
/* alternatively:
return out.write(vec.data(), vec.size());
*/
}
void str_read(std::vector<char> &str) {
char ch;
while (cin.get(ch) && ch != '\n') {
str.push_back(ch);
}
}
int main() {
std::vector<char> str;
str_read(str);
std::cout << str << std::endl;
}
That being said, why not just use std::string instead of std::vector<char>? There is a standard operator<< defined for std::string, and a standard std::getline() function for reading characters into std::string until '\n':
#include <iostream>
#include <string>
int main() {
std::string str;
std::getline(cin, str);
std::cout << str << std::endl;
}
There are 3 BIG problems here.
You are passing the vector by value, not by reference. As a result, any changes made to the vector in the function will stay local to the vector initialised as a part of that function call stack. It will be deleted by the time you return. so change the signature to str_read(std::vector<char>& str).
You are going through the stdin capture character by character. AFAIK scanf although will read the new line character, will leave it in the buffer not appending it to your string. From the looks of it, all you are trying to do is read a string from stdin, store it in a char array, and print that char array out. Don't overengineer stuff. just use std::cin and store it in a string, to begin with, like
std::string captured_string;
std::getline(std::cin, captured_string);
You can then std:cout << captured_string << "\n"; directly
If you insist on storing characters in a vector, which I do not understand why would you need to, you can just do std::vector<uint8_t> char_array(captured_string.begin(), captured_string.end()). However, std::cout << char_array << "\n" will still not work. That is for 2 reasons, the first one being that std::vector<T, allocator> does not have an overload for << of std::ostream. The second is that the moment you convert your string to an array of characters, they do not mean the same thing.
I think you misunderstood what you were taught in class about strings being stored as arrays of characters. They are indeed stored as arrays, but an array type and a string type are fundamentally different and are not equivalent.
Capturing the string from stdin will anyway store it in a char* or a std::string as I have shown above. You can use that directly without having to convert a string to an array of characters.
In essence, your program decays to this
#include <iostream>
#include <string>
int main()
{
std::string captured_string;
std::getline(std::cin, captured_string);
std::cout << captured_string << "\n";
return EXIT_SUCCESS;
}
EDIT
I just realised that your objective may have been to print the string character by character. In that case, you don't need to convert it to an array. There are multiple ways of doing this, but the least confusing and probably the easiest way of doing this would be to use the range-based for loop.
int main()
{
std::string captured_string;
std::getline(std::cin, captured_string);
for (auto& ch: captured_string) // containers in the standard library support range based for loops.
std::cout << ch << "\n"; // print each character in the string on a new line
return EXIT_SUCCESS;
}
First, explain
error: no type named 'type' in 'struct std::enable_if<false, void>'
cout is character-oriented stream output and does not accept output formats of the vector<char> type.
Vector is an array of elements of the specified type. If you want to use a vector, you can store values in it first:
vector<char> str;
str.push_back('H');
An element of the array is then printed to standard output cout
cout << str[0] <<endl;
The second problem is that your function str_read is defined as void, which has no value, so it cannot be located in cout's standard output either.
It looks like you want to put the characters as input into a vector and print them out. If you position the function as void, you will need to change the value of str by reference
Next question, I see that your while loop break is mistimed and does not combine with if. You should not add a semicolon after an if statement.
if (ch == '\n')break;
Finally, if you choose to change the value of str by reference, you need to implement this in the function, as mentioned above, when you type a value of ch, you need to use str.push_back(ch) to store it.
Your 'str' variable doesn't have anything in it when you try to display it. You also don't initialize your vector to any variables for the function to read anyways.
How to print out the first element of a const string?
I tried to do std::cout << path[0] << std::endl; on CLion
but path[0] does not work and the IDE would warn.
CLion warns that
Cannot assign to return value because function 'operator[]' returns a const value.
type print(const std::string &path){}
You can use
std::string::at
It can be used to extract characters by characters from a given string.
Consider an example
#include <stdio.h>
#include<iostream>
using namespace std;
int main()
{
string str = "goodday";
cout << str.at(0);
return 0;
}
Hope this will help you.
First of all you can ignore the warning sometimes the compiler complains about unnecessary things, secondly do not do the following:
type print(const std::string &path){}
Dangerous, first of all Passing a string as a reference?? Think about it from the compilers point of view, the string is const, each time you use the += you are actually create a new string. But if you use the & with the string you are telling the compiler that you are planning to modify the string object which has type const..... Use string path as a parameter but never, ever use string& path......
If I want to construct a std::string with a line like:
std::string my_string("a\0b");
Where i want to have three characters in the resulting string (a, null, b), I only get one. What is the proper syntax?
Since C++14
we have been able to create literal std::string
#include <iostream>
#include <string>
int main()
{
using namespace std::string_literals;
std::string s = "pl-\0-op"s; // <- Notice the "s" at the end
// This is a std::string literal not
// a C-String literal.
std::cout << s << "\n";
}
Before C++14
The problem is the std::string constructor that takes a const char* assumes the input is a C-string. C-strings are \0 terminated and thus parsing stops when it reaches the \0 character.
To compensate for this, you need to use the constructor that builds the string from a char array (not a C-String). This takes two parameters - a pointer to the array and a length:
std::string x("pq\0rs"); // Two characters because input assumed to be C-String
std::string x("pq\0rs",5); // 5 Characters as the input is now a char array with 5 characters.
Note: C++ std::string is NOT \0-terminated (as suggested in other posts). However, you can extract a pointer to an internal buffer that contains a C-String with the method c_str().
Also check out Doug T's answer below about using a vector<char>.
Also check out RiaD for a C++14 solution.
If you are doing manipulation like you would with a c-style string (array of chars) consider using
std::vector<char>
You have more freedom to treat it like an array in the same manner you would treat a c-string. You can use copy() to copy into a string:
std::vector<char> vec(100)
strncpy(&vec[0], "blah blah blah", 100);
std::string vecAsStr( vec.begin(), vec.end());
and you can use it in many of the same places you can use c-strings
printf("%s" &vec[0])
vec[10] = '\0';
vec[11] = 'b';
Naturally, however, you suffer from the same problems as c-strings. You may forget your null terminal or write past the allocated space.
I have no idea why you'd want to do such a thing, but try this:
std::string my_string("a\0b", 3);
What new capabilities do user-defined literals add to C++? presents an elegant answer: Define
std::string operator "" _s(const char* str, size_t n)
{
return std::string(str, n);
}
then you can create your string this way:
std::string my_string("a\0b"_s);
or even so:
auto my_string = "a\0b"_s;
There's an "old style" way:
#define S(s) s, sizeof s - 1 // trailing NUL does not belong to the string
then you can define
std::string my_string(S("a\0b"));
The following will work...
std::string s;
s.push_back('a');
s.push_back('\0');
s.push_back('b');
You'll have to be careful with this. If you replace 'b' with any numeric character, you will silently create the wrong string using most methods. See: Rules for C++ string literals escape character.
For example, I dropped this innocent looking snippet in the middle of a program
// Create '\0' followed by '0' 40 times ;)
std::string str("\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", 80);
std::cerr << "Entering loop.\n";
for (char & c : str) {
std::cerr << c;
// 'Q' is way cooler than '\0' or '0'
c = 'Q';
}
std::cerr << "\n";
for (char & c : str) {
std::cerr << c;
}
std::cerr << "\n";
Here is what this program output for me:
Entering loop.
Entering loop.
vector::_M_emplace_ba
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
That was my first print statement twice, several non-printing characters, followed by a newline, followed by something in internal memory, which I just overwrote (and then printed, showing that it has been overwritten). Worst of all, even compiling this with thorough and verbose gcc warnings gave me no indication of something being wrong, and running the program through valgrind didn't complain about any improper memory access patterns. In other words, it's completely undetectable by modern tools.
You can get this same problem with the much simpler std::string("0", 100);, but the example above is a little trickier, and thus harder to see what's wrong.
Fortunately, C++11 gives us a good solution to the problem using initializer list syntax. This saves you from having to specify the number of characters (which, as I showed above, you can do incorrectly), and avoids combining escaped numbers. std::string str({'a', '\0', 'b'}) is safe for any string content, unlike versions that take an array of char and a size.
In C++14 you now may use literals
using namespace std::literals::string_literals;
std::string s = "a\0b"s;
std::cout << s.size(); // 3
Better to use std::vector<char> if this question isn't just for educational purposes.
anonym's answer is excellent, but there's a non-macro solution in C++98 as well:
template <size_t N>
std::string RawString(const char (&ch)[N])
{
return std::string(ch, N-1); // Again, exclude trailing `null`
}
With this function, RawString(/* literal */) will produce the same string as S(/* literal */):
std::string my_string_t(RawString("a\0b"));
std::string my_string_m(S("a\0b"));
std::cout << "Using template: " << my_string_t << std::endl;
std::cout << "Using macro: " << my_string_m << std::endl;
Additionally, there's an issue with the macro: the expression is not actually a std::string as written, and therefore can't be used e.g. for simple assignment-initialization:
std::string s = S("a\0b"); // ERROR!
...so it might be preferable to use:
#define std::string(s, sizeof s - 1)
Obviously you should only use one or the other solution in your project and call it whatever you think is appropriate.
I know it is a long time this question has been asked. But for anyone who is having a similar problem might be interested in the following code.
CComBSTR(20,"mystring1\0mystring2\0")
Almost all implementations of std::strings are null-terminated, so you probably shouldn't do this. Note that "a\0b" is actually four characters long because of the automatic null terminator (a, null, b, null). If you really want to do this and break std::string's contract, you can do:
std::string s("aab");
s.at(1) = '\0';
but if you do, all your friends will laugh at you, you will never find true happiness.
#include <iostream>
#include <string>
using namespace std;
std::string dispCard(int card)
{
string textCard = "help";
//cout << textCard;
system("pause");
return textCard;
}
int main()
{
// Using this area to test functions for now
cout << dispCard(14);
return 0;
}
Uncommenting the cout line actually does display the value. But I cannot return the value in the string.
Honestly, I have no idea why this isn't working. I initially just wanted to use "char" but that doesn't work for some reason.
Visual Studio didn't like:
char test;
test = "help";
It underlined the "=".
For now, I just want to return a string value from a function. There's more that I need it to do, but this is the main issue right now.
Uncommenting the cout line actually does display the string. But not returning the string.
Your program both prints and returns the string, printing it again in main. The only problems I can see with your program are:
You are using system("pause") for no reason.
You are not consistent with the use of either the std:: prefix or importing the namespace. On this regard I highly suggest the std:: prefix.
You are not using the function argument.
I initially just wanted to use "char" but that doesn't work for some reason.
Well, char, as the name suggests, can only store 1 characters. In:
char test = "help";
you are trying to assign 5 characters (4 + \0) to an objects who's size can only store 1. That's the reason why your compiler complained.
I think you need to pass an int to your function and get it back in string form. To do this conversion you need something like this:
std::ostringstream stm;
stm << yourIntValue;
std::string s(stm.str());
or this:
char bf[100];
sprintf(bf, "%d", yourIntValue);
std::string s(bf);
If you put this snippet in a function then you can also accept an int parameter, convert it to a std::string and return the std::string as others have shown.
What you need to do is to declare return type of function as std::string and then return either a string object, something that can implicitly be converted to string object or something that explicitly constructs string object.
Example:
std::string foo(){
return "idkfa"; //return C-style string -> implicitly convertible to string
return {"idkfa"}; // direct initialization of returning std::string
return std::string("idkfa"); //return explicitly constructed std::string object
}
Also note that C-style strings are of type char* (C-style strings are basically an array of chars, with last element being \0, that is 0).
Your code works perfectly fine, though the the system("pause") is totally redundant and pointless and should be removed. It may in fact be confusing you.