Why I can't assign string::back to string? - c++

I write a simple program:
Get last character of string1 and assign it to string2.
It's like:
#include<iostream>
#include<string>
int main(int argc, char const *argv[])
{
std::string s1 = "abc!";
std::string s2 = s1.back();
std::cout << s1;
return 0;
}
However, I get a compile error:
conversion from ‘__gnu_cxx::__alloc_traits<std::allocator<char> >::value_type {aka char}’ to non-scalar type ‘std::__cxx11::string {aka std::__cxx11::basic_string<char>}’ requested
I don't know this error exactly means.
It's seems like some type conversion error occur.
But the return value of string::back should be char, right?
Why I can't assign it to another string?
And how I can give last character of s1 to s2?

It's because std::string does not have an implicit constructor which takes just a single character parameter, that's why conversion from char to std::string fails. Instead you can use:
// 1. Constructor with length + char
std::string s2(1, s1.back());
// 2. Constructor which takes an std::initializer_list<char>
std::string s2{s1.back()};

A string is a collection of characters, the back of a string is a character (i.e., just an element of the collection), not a string.
You can achieve what you want by using the following constructor overload of std::string:
std::string s2(1, s1.back());
That is, construct s2 as a one-character-length string with the value s1.back().

Hope you are trying to create a new string s2 out of the last character of string s1.
You can achieve that using the solution below:
#include<iostream>
#include<string>
int main()
{
std::string s1 = "abc!";
std::string s2;
s2 = s1.back();
std::cout << s1;
std::cout << s2;
return 0;
}

Related

Getting error while initializing string with string character array? [duplicate]

This question already has answers here:
no viable conversion from 'value_type' (aka 'char') to 'string' (aka 'basic_string<char, char_traits<char>, allocator<char> >')
(1 answer)
Initializing a string with a single character
(1 answer)
Closed 1 year ago.
I'm trying to initialize this string s1 but Idk why I'm getting this error, This may be due to s[0] is character but why everything turns fine when I initialize and declare same string s1 but in diffrent lines, one after another.
#include <bits/stdc++.h>
int main()
{
std::string s = "text";
std::string s1 = s[0];
std::cout << s1;
}
Error:
error: conversion from '__gnu_cxx::__alloc_traits<std::allocator<char>, char>::value_type'
{aka 'char'} to non-scalar type 'std::__cxx11::string' {aka
'std::__cxx11::basic_string<char>'} requested
std::string s1 = s[0];
^
This is working fine:
#include <bits/stdc++.h>
int main()
{
std::string s = "text";
std::string s1;
s1 = s[0];
std::cout << s1;
}
There's no constructor for char. There's a copy assignignment, which works for the second snippet.
However, you can write either like
std::string s1 ( 1, s[0] );
std::string s1 = s[0]; is initialization, it doesn't work because std::string doesn't have any constructor taking a single char.
s1 = s[0]; is assignment, it works because std::string has a operator= taking a single char.
If we take a look at the documentation, we can see that
std::string has no constructor that takes a char type - cppreference.com
It does have an overload for the operator= that can take a
char - cppreference.com
[The copy assignment that takes a char] replaces the contents with
character ch as if by assign(std::addressof(ch), 1)
As to why, consider the fact that the std::string already has so called fill-constructor, string s(n, val), that takes an initial value val and fills the string with n copies of it. So there's no need to have special case for n == 1:
std::string s1 = "text";
std::string s2(1, s[0]); // One char of value s[0]
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s = "text";
string s1;
s1 = s;
cout << s1;
}
the code should work now.

Initializing a string with a single character

I want to initialize a std::string with a single character. The following code doesn't work:
int main()
{
string s = 'c';
cout<<s;
return 0;
}
Error:
error: conversion from ‘char’ to non-scalar type ‘std::__cxx11::string {aka std::__cxx11::basic_string<char>}’ requested
string s = 'c';
But the following does work. Why is it so?
int main()
{
string s;
s = 'c';
cout<<s;
return 0;
}
Output:
c[Finished in 0.8s]
When you do
string s = 'c';
you are basically invoking constructor initialisation rather than an assignment operation. But there isn’t any constructor for std::string that takes only a single char as input. There is however one std::string(n, c), where n is the number of characters c in the string.
When you do
s = 'c'
you do an assignment operation, invoking the overloaded string::operator= (string& operator= (char c);) for std::string. Now this method is overloaded to accept a single char as input as well, as you can see from the code snippet at this reference as well as at this one.
std::string str1;
// ...
// (4) operator=( CharT );
str1 = '!';
Additionally, std::string::assign doesn’t accept a single char, similar to the constructor.

Why std::string concatenation in one expression gives different result than char by char?

I'm concatenating 3 chars from the middle of a std::string. If I do it char by char, I get the expected result, but if I do it in only one expression, I get a weird result. Why?
#include <string>
#include <iostream>
using namespace std;
int main()
{
string s1 = "abcdefghijklmnopq";
string s2 = "";
string s3 = "";
s3+=s1[4];
s3+=s1[5];
s3+=s1[6];
cout << s3 << endl; // Expected behaviour
s2=s1[4]+s1[5]+s1[6];
cout << s2 << endl; // ?????
}
s1[4]+s1[5]+s1[6] uses the built-in + on a char type: every argument is promoted to an int and the expression is an int type. When this is assigned to s2, the overloaded = operator to char is called, and the expression is truncated to a char prior to the assignment. If char is signed on your platform, then this is implementation defined. See http://en.cppreference.com/w/cpp/language/implicit_conversion.
s3+=s1[4]; and company uses the overloaded += operator on the std::string for a char argument. That is defined to concatenate the char to the string.
Finally from C++14 onwards, you could use the beautiful
s2 = ""s + s1[4] + s1[5] + s1[6];
if substr cannot come to your rescue (s2 = s1.substr(4, 3); would do the job in this particular case). Note the user defined literal ""s defined in the C++14 Standard Library.

What is the return type of stack.top() and stack.pop() using stack<string> in cpp?

I am trying to print the return value of stack.top() using printf() of a stack but it is giving a format mismatch. The code is given below :
int main(){
stack <string> cards;
char *ch1;
char ch2[20];
cards.push("Ace");
cards.push("King");
cards.push("Queen");
cards.push("Jack");
printf("Number of cards : %ld \n", cards.size());
ch1 = cards.top(); // As sizeof(cards.top()) is 8. error of type conversion
strcpy(ch2,cards.top()); // cannot convert ‘std::basic_string<char>’ to ‘const char*’
printf("Top of the Stack : %s \n", ch);
return 0
}
In all examples I saw it was printed using "cout".
A std::string is a different type from a char*, the following won't work:
ch1 = cards.top(); // top() returns a string, not a char*
I suggest using std::strings for your code:
int main(){
stack <string> cards;
string ch1; // std::strings
string ch2;
...
ch1 = cards.top(); // Correct
printf("Top of the Stack : %s \n", ch1.c_str()); // c_str() needed
return 0;
}
Also notice that using printf requires a char* type, you can get one with std::string::c_str(), or (even better) you can use cout in the first place:
std::cout << "Top of the Stack : " << ch1;
Therefore I'd suggest doing something like:
#include <iostream>
#include <stack>
#include <string>
int main() {
std::stack <std::string> cards;
std::string ch1;
cards.push("Ace");
cards.push("King");
cards.push("Queen");
cards.push("Jack in the Jack");
std::cout << "Number of cards : " << cards.size() << std::endl;
ch1 = cards.top(); // Get the top card
std::cout << "Top of the Stack : " << ch1;
}
Example
The return value of is pop is void, top returns a reference to the data type that the stack holds. std::string is not the same as an array of char and it does not directly work with any of the C string functions. You can use std::string::c_str() to get the raw data, but it is better to stay in STL land. You can directly print std::string using std::cout.
You can't use strcpy, which is a C function for C-style char * strings, for C++ std::strings - if you must use C strings for some reason then change:
strcpy(ch2,cards.top());
to
strcpy(ch2,cards.top().c_str());
^^^^^^^^
This takes the std::string returned by cards.top() and returns a const char * which can be used by strcpy.
A better solution though would be to stick to C++ idioms throughout, i.e. use std::string exclusively and use std::cout instead of printf for display purposes.
In the following line
ch1 = cards.top();
stack<string>::top() returns string, while ch1 is char *. There is no type conversion from string to char *. To convert it, use the member function c_str :
ch1 = cards.top().c_str();
And ch1 must be const char*, not char *, because thats what c_str returns.
Why it returns const char* ? Because otherwise you could disrupt the string value by extracting char * and changing it.

Unexpected problems concatenating strings

I'm trying to concatenate strings using +, but there is some weird stuff going on. Here is my "Grade" class I have for a class project:
#pragma once
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Grade {
private:
string className;
string student;
string letter;
public:
Grade(string c, string s, string l) : className(c), student(s), letter(l) {}
string getLetterGrade() const { return letter; }
string getClassName() const { return className; }
string getStudent() const { return student; }
void setLetterGrade(string l) { letter = l; return;}
void setClassName(string c) { className = c; return;}
void setStudnet(string s) { student = s; return;}
string toString() const { string output = "hello"+student; return output; }
};
Obviously, the toString() method isn't currently what I want it to be.
If I run the toString() as above, I get "hello529173860" out, as expected. However, if I change the line to:
string toString() const { string output = student+"hello"; return output; }
then the output is "hello3860". This isn't just putting the hello string on the front, but its replacing characters from the student string in the process... somehow?
Furthermore, if I try to use:
string toString() const { string output = "hello"+" world"; return output; }
I get an error:
Grade.h: In member function ‘std::string Grade::toString() const’:
Grade.h:29:53: error: invalid operands of types ‘const char [6]’ and ‘const char [7]’ to binary ‘operator+’
string toString() const { string output = "hello"+" world"; return output; }
^
I'm really at a loss for what it going on here... especially since I have done string concatenation earlier in the program without issue.
What I would like is to output something like:
"student+[some white space]+letter+[some white space]+className"
A std::string can be added to anything (another std::string, double-quoted string literal, char) and provide intuitive results, but if you try to add a double-quoted string literal to another string literal or a char then it won't "work":
a string literal added to a char or other integral value will undergo Standard Conversion to a const char*, then any number added to the pointer will move along the literal that number of characters: if the offset isn't inside the string literal then you get undefined behaviour if you dereference (use) the resultant pointer,
two string literals just can't be added, even after decaying to two pointers, so you'll get a compile-time error.
Sometimes you will want to explicitly construct a std::string so that concatenation with other values works as you'd like: e.g. my_string = std::string("hello ") + my_const_char_ptr + '\n'.
Examples:
std::string s = "Hello";
s + " World"; // ok
"Hello " + s; // ok
"Hello " + "World"; // NOT ok - two string literals
s += " World"; // ok
s += " Goodbye " + "World"; // NOT ok - "+" evaluated before "+="
s += std::string(" Goodbye ") + "World"; // OK - right-hand-side no longer two literals
// BUT may be slower than two "s +="
The constant strings "hello" and "world" are nothing but compile time constants of type const char*. Just like you cannot add two int pointers:
int *p1, *p2;
p1+p1; // Error
You cannot add two (const) char* objects. This is against the C/C++ language rules. If you must concatenate two const-char-pointers, you can just place them together:
"hello" "world"
This technique is mainly useful if you use them along with macros. For example:
// Over simplified
#define ONE(_x) _x
#define TWO(_x) _X
ONE("This is") TWO(" concatenation")
If you are adding two (or more) runtime C-Strings, you must use strXXX functions (like strcat), or better use std::string.
There is no operator + for character arrays. So it is obvious that this code
string toString() const { string output = "hello"+" world"; return output; }
is invalid.
In this expression "hello"+" world" there are used two string literals that have the types correspondingly const char[6] and const char[7]. The operator + is not defined for arrays.
You could just write
string toString() const { return string( "hello" ) + " world"; }
In this case there is used the operator + overloaded for the class std::string. Declaration of the local variable input is redundant. So you could simplify the function even the following way
string toString() const { return "hello world"; }