Function not returning desired string - c++

#include <iostream>
#include <string>
using namespace std;
string wordB(string input);
int main() {
//ask for word
cout << "Enter a word\n";
//get word
string input = "";
cin >> input;
//return with b in between all letters
cout << wordB(input);
cout << endl << input;
}
string wordB(string str) {
string rString = "";
for (unsigned i = 0; i < str.length(); ++i) {
rString += "B" + str.at(i);
}
cout << endl << rString;
return rString;
}
Trying to display the word a users enter where between every character there is the letter "B". When I run this with the word "join" I get back "trtr".

"B" + str.at(i); doesn't do what you seem to think it does; it's not string conctatenation. It says: take a char* pointer pointing to the beginning of the string literal "B", advance it by the number of characters equal to the ASCII code of character str.at(i), and treat the resulting pointer as pointing to a nul-terminated string. Unless str.at(i) happens to be '\x0' or '\x1' (unlikely), your program exhibits undefined behavior.
There are many different ways to do what you want. Here's one:
rString.push_back('B');
rString.push_back(str[i]);

A particularly nice fix, available from C++14 onwards, is to write
rString += "B"s + str.at(i);
noting the s, which is a user-defined literal. That then forces the overloaded + operator on std::string to be used, rather than the built-in +, which is actually performing dubious (and potentially undefined) pointer arithmetic on the const char[2] literal "B" decayed to a const char*.

Admittedly it is a pitfall... in this line
rString += "B" + str.at(i);
the "B" + str.at(i) part is not doing what one might expect: It adds str.at(i) to a char pointer (pointing to the first letter of "B"). The fix is easy:
rString += std::string("B") + str.at(i);
// ^-------------- now calls the correct operator
Just as a curiosity consider this:
(rString += "B") += str.at(i);
I do not recommend to write it (its too obfuscated), but it does the right thing, because there is a std::string::operator+(char*) and a std::string::operator+(char).

What you are seeing is as a result of order of evaluation.
The += operator will force the right-hand-side of the expression to be evaluated and the result will be appended to the string.
This is what causes the problem you are facing because the right-hand-side is not std::string, and therefore the meaning of the + operator in that rhs simply translates to pointer arithemetic not string concatenation as you would expect.
A simple fix is to be more explicit and do this:
rString = rString + "B" + str.at(i);
This will now cause the compiler to first evaluate the right-hand-side of the = operator as a string and then you get concatenation. It also gives the added benefit of allowing the compiler to inform you if the right-hand side is not a string.
Another alternative is to use string streams. I think it looks cleaner so here it is:
#include <sstream>
...
string wordB(string str) {
std::ostringstream oss;
for (unsigned i = 0; i < str.length(); ++i) {
oss << 'B' << str.at(i);
}
cout << endl << oss.str();
return oss.str();
}

Related

Concatenate a char into a string [duplicate]

im getting totally confused by this seemingly simple problem.
I have a pain old char, and I want to concatenate it in the middle of a string.
Like so.
string missingOptionArg(char missingArg) {
return "Option -" + missingArg + " requires an operand";
}
I was guessing the + operand was smart enough to deal with this sort of trivial thing, if not, what would be the simplest way of doing this?
To concatenate string literal and char:
std::string miString = std::string("something") + c;
A similar thing happens when you need to concat two strings literals.
Note that "something" is not a std::string, it is a pointer to an array of chars. Then you can't concatenate two string literals using +, that would be adding two pointers and is not what you want.
The correction of your code is in Igor's comment.
Accepted answer is the simplest but other ways to achieve the concatenation.
#include <iostream>
#include <string>
using namespace std;
string missingOptionArgRet(char missingArg) {
string s("Option -");
s += missingArg;
s += " requires an operand";
return s;
}
void missingOptionArgOut(char missingArg, std::string* out) {
*out = "Option -";
*out += missingArg;
*out += " requires an operand";
}
main(int, char**)
{
string s1 = missingOptionArgRet('x');
string s2;
missingOptionArgOut('x', &s2);
cout << "s1 = " << s1 << '\n';
cout << "s2 = " << s2 << '\n';
}
Using += rather than + will prevent temporary string objects. Also there are 2 options. Return by value missingOptionArgRet. This has disadvantage that as a result of return by value the string must be copied to the caller.
The second option missingOptionArgOut can prevent this at the cost of slightly more verbose code. I pass in an already constructed string (by pointer to make it clear its a variable to be modified, but could be passed by reference).

Problem with comparison between pointer and integer C++

I've been getting error messages saying
[Error] ISO C++ forbids comparison between pointer and integer [-fpermissive]
and don't know how to fix it.
I've searched stackoverflow for people with same issues, but only came up with this: c++ compile error: ISO C++ forbids comparison between pointer and integer which didn't answer my question. What also confused me is that the error is on line indicated by the HERE comment, which is the if statement, but I don't see any integers in the condition part.
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
int main() {
char in[100];
gets(in);
int len = strlen(in);
std::string s(in);
int count = 0;
for (int i = 0; i < len; i++) {
if (s.at(i) == " ") { // <-- HERE
count += 1;
}
}
cout << count;
}
Say the input is Hello World, I am expecting output to be 1, but I didn't get any output.
The expression " " is a string literal with type const char [2].
The expression s.at(i) returns a char&.
So, s.at(i) == " " is trying to find an equality operator taking
char& on the left and a reference to the literal array const char(&)[4] on the right.
It finds one or more candidates for operator==, but the argument types don't match any exactly, so next it tries the implicit conversion sequences - this is where the char& undergoes integral promotion to int, and the array decays to const char*.
It still doesn't find a match with these, and gives up, but that explains why it has int and const char * arguments when the error is emitted.
All that is a long way of saying that you write character literals like ' ' in C++. They're not just a string of length 1 as in some other languages (and you can't write strings with single quotes at all).
Change the if statement
if (s.at(i) == ' ') {
count += 1;
}
since s.at(i) returns char&, " " is a string, and ' ' is a char.
The problem is that " " is a string literal not a character! A character literal would be ' '.
The error is a bit misleading, because " " is acutally a const char*.
C++ differentiates between character strings and single characters in the literals by different quoting symbols (" vs '). The " " in your code is the string literal that contains one space, a single space character would be written as ' '. The function std::string::at returns a single character.
A small example will show you how the compiler looks on that
#include <iostream>
#include <string>
#include <typeinfo> // for typeid
using namespace std;
int main() {
string s = "Hello, world!";
cout << typeid(" ").name() << endl;
cout << typeid(' ').name() << endl;
cout << typeid(s.at(0)).name() << endl;
return 0;
}
see online demo of above code.
But, to be precise, identical types aren't required for comparisons in C++, but the types need to be compatible. Pointers (string literals are considered constant pointers to characters, in fact pointing to the first character in the literal) and integers (to which char is promoted in your case) are not compatible. To "fix" your problem quickly, change s.at(i) == " " to s.at(i) == ' ', but your program will remain problematic: it still contains a lot of C code that's problematic in it self, too. A possible C++ version could be this:
#include <iostream>
#include <string>
using namespace std;
int main() {
int count = 0;
string line;
std::getline(cin, line);
for (const auto c: line) {
if (c == ' ') {
count++;
}
}
cout << "Your input \""<< line << "\" contains " << count << " space(s)." << endl;
return 0;
}

Passing values ​to an array within a loop

I'm trying to make a program in C++ in which the number of mathematical signs are counted. I am using isdigit to figure this out, but when I pass the value of my string, it gives me a warning.
This is the code that I have. The line digito[i] = entrada[i] is where I think the problem lies, but I do not understand why.
cout << "Input the operation" << endl;
cin >> input;
string digit[] = { "" };
string sign[]={""};
int cn = 0, cs = 0;
for (int i = 0; i < input.size(); i++) {
if (isdigit(input[i])) {
cout << "There is a digit in position " << i << endl;
cn += 1;
digit[i] = input[i];
}
else {
cout << "There is a sign in position " << i << endl;
// sign[i] = input[i];
cs += 1;
sign[i] = input[i];
}
}
It takes me to this code as the problem:
static _CONSTEXPR17 void assign(char& _Left, const char& _Right) noexcept
{ // assign an element
_Left = _Right;
}
Those two strings are problematic. You've unnecessarily declared them as arrays with one element each, and initialized each string to empty.
string digito[] = { "" };
string signo[]={""};
Yet afterwards, you're indexing them with non-zero indices:
digito[i] = entrada[i];
This line is problematic because of two reasons; going beyond the array bounds, and incompatible types.
digito[i] is the type of std::string (because digito is std::string[]), while entrada[i] is char (assuming entrada is std::string). std::string has an overload of its operator= that allows assigning to a single character, but that's not what you want here, I assume.
As for the second problem, std::string requires you to enlarge it before you random-access it at a given index. The best way to do this in this case would be during construction, dropping the erroneous array use:
std::cin >> entrada;
std::string digito(entrada.size(), ' ');
std::string signo(entrada.size(), ' ');
That being said, I'm not sure if this code does what you want it to. Given an input string of:
2+2/3
You'll get two such strings:
digito = "2 2 3"
signo = " + / "
If your actual goal was to tokenize the input (divide into numbers and operators), a much better way would be to use either two std::vector<char>s, or, even better:
using Number = int;
enum class Operator { Plus, Minus, Div, Mul };
using Token = std::variant<Number, Operator>
using Sequence = std::vector<Token>;
A consistent, strongly-typed data model will make it much easier to write correct code that produces it and operates on the results afterwards.

Concatenate plain char and string?

im getting totally confused by this seemingly simple problem.
I have a pain old char, and I want to concatenate it in the middle of a string.
Like so.
string missingOptionArg(char missingArg) {
return "Option -" + missingArg + " requires an operand";
}
I was guessing the + operand was smart enough to deal with this sort of trivial thing, if not, what would be the simplest way of doing this?
To concatenate string literal and char:
std::string miString = std::string("something") + c;
A similar thing happens when you need to concat two strings literals.
Note that "something" is not a std::string, it is a pointer to an array of chars. Then you can't concatenate two string literals using +, that would be adding two pointers and is not what you want.
The correction of your code is in Igor's comment.
Accepted answer is the simplest but other ways to achieve the concatenation.
#include <iostream>
#include <string>
using namespace std;
string missingOptionArgRet(char missingArg) {
string s("Option -");
s += missingArg;
s += " requires an operand";
return s;
}
void missingOptionArgOut(char missingArg, std::string* out) {
*out = "Option -";
*out += missingArg;
*out += " requires an operand";
}
main(int, char**)
{
string s1 = missingOptionArgRet('x');
string s2;
missingOptionArgOut('x', &s2);
cout << "s1 = " << s1 << '\n';
cout << "s2 = " << s2 << '\n';
}
Using += rather than + will prevent temporary string objects. Also there are 2 options. Return by value missingOptionArgRet. This has disadvantage that as a result of return by value the string must be copied to the caller.
The second option missingOptionArgOut can prevent this at the cost of slightly more verbose code. I pass in an already constructed string (by pointer to make it clear its a variable to be modified, but could be passed by reference).

Invalid conversion char to char* - Copying char in string array to another string array

I'm a beginner in C++ Programming language. I wanted to write a program that take the alphabets in a string array called str, and copy it in a new array called str_alpha.
And the same goes to numbers, the program copies it from str array to str_digit array.
There's my humble code, it might be full of errors and stuff. But this is what I could do now with my very little experience.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
using namespace std;
char str[100], str_alpha[100], str_digit[100];
int main()
{
gets(str);
for (int i=0 ; str[i] ; i++)
{
if (isalpha(str[i]))
{
strcpy (str_alpha[i] , str[i]);
}
else if (isdigit(str[i]))
{
strcpy (str_digit[i] , str[i]);
}
}
cout << "Alpha is " << str_alpha << endl ;
cout << "Number is : " << str_digit << endl ;
return 0;
}
And it gives my those errors :
F:\C++Progs\string\main.cpp||In function `int main()':|
F:\C++Progs\string\main.cpp|18|error: invalid conversion from `char' to `char*'|
F:\C++Progs\string\main.cpp|18|error: initializing argument 1 of `char* strcpy(char*, const char*)'|
F:\C++Progs\string\main.cpp|18|error: invalid conversion from `char' to `const char*'|
F:\C++Progs\string\main.cpp|18|error: initializing argument 2 of `char* strcpy(char*, const char*)'|
F:\C++Progs\string\main.cpp|22|error: invalid conversion from `char' to `char*'|
F:\C++Progs\string\main.cpp|22|error: initializing argument 1 of `char* strcpy(char*, const char*)'|
F:\C++Progs\string\main.cpp|22|error: invalid conversion from `char' to `const char*'|
F:\C++Progs\string\main.cpp|22|error: initializing argument 2 of `char* strcpy(char*, const char*)'|
||=== Build finished: 8 errors, 0 warnings ===|
Help me please.
Thanks in advance.
First of all, strcpy copies C strings (character arrays) not chars. Additionally, the lines strcpy(str_digit[i],str[i]) and strcpy(str_alpha[i], str[i]) would still probably be wrong even if this wasn't the case. Since you haven't initialised the arrays str_digit and str_alpha, you'll get a lot of garbage values while printing them and if any of those garbage values happen to be 0x00, the cout statements will fail to print the whole string. As already mentioned, you really should be using std::string rather than char[] or char*. Having said that, here are corrected versions of your code for both char[] and std::string.
Using gets is bad practice and you might consider using std::cin instead. And you might want to use an iterator rather than a simple for loop.
//using char[]
#include <iostream>
using namespace std;
int main()
{
char str[100] , str_alpha[100] , str_digit[100] ;
int alpha_counter=0, digit_counter=0;
cin.get(str, 99);
for (int i=0 ; str[i] ; i++)
{
if(isalpha(str[i]))
{
str_alpha[alpha_counter] = str[i];
alpha_counter++;
}
else if (isdigit(str[i]))
{
str_digit[digit_counter] = str[i];
digit_counter++;
}
}
str_alpha[alpha_counter] = 0;
str_digit[digit_counter] = 0;
cout << "Alpha is " << str_alpha << endl ;
cout << "Number is : " << str_digit << endl ;
return 0;
}
And the version using std::string:
//using std::string
#include <iostream>
using namespace std;
int main()
{
string str, str_alpha , str_digit;
cin >> str ;
for (string::iterator it = str.begin();it<str.end();it++)
{
if(isalpha(*it))
{
str_alpha += *it;
}
else if (isdigit(*it))
{
str_digit += *it;
}
}
cout << "Alpha is " << str_alpha << endl ;
cout << "Number is : " << str_digit << endl ;
return 0;
}
Both versions compile without warnings on g++ 4.2.1 with -Wall and -pedantic.
I'm a beginner in C++ Programming language.
The do not use char* and the likes; use C++ predefined types for this, in your case string:
string str;
cin >> str;
string alpha;
string digit;
for (unsigned int i = 0; i < str.length(); ++i) {
char chr = str[i];
if (isalpha(chr))
alpha.push_back(chr);
else if (isdigit(chr))
digit.push_back(chr);
}
Furthermore, strcpy is, as the name says, used to copy strings, not individual chars. You can copy those directly by assigning them. No function call needed.
The problem is that strcpy is intended to copy a whole string. In this case, you're copying individual characters, not entire strings. For individual characters, you can use a simple assignment.
There are a few other things to deal with though. First of all, you have:
char str[100];
outside any function. That defines an array of 100 char's, and initializes all of them to 0. You then loop through that, trying to find characters that are classified as alphabetical or digits -- which will never happen, because a zero byte ('\0', not '0') is never either one.
In fact, as far as a I can tell, you don't need str at all. What you (apparently) want is roughly like:
for (i in 0 to 127)
if (alpha(i))
add i to str_alpha
else if (digit(i))
add i to str_digit
As Konrad Rudolph already pointed out, you'd probably be much better off making str_digit and str_alpha into std::string's than arrays of char. Arrays can do the job, but they'll be more work to get really correct.
strcpy copies a whole string. Use plain assignment (= operator) for copying characters.
You're copying characters over, even though strcpy is designed to copy over strings (arrays of characters). The compiler is therefore complaining because you're supplying 'char' rather than 'char *'. If you're copying characters over then just do:
str_alpha[i] = str[i];