Why cant we assign char to strings? - c++

in C++, I noticed if I make a string str="kls";, then I can't write string s1=str[0];
I have to instead write:
string s1;
s1=str[0];
Why so?

The reason is that the class std::string does not have a constructor that accepts a single argument of the type char. While there is a copy assignment operator that accepts as an argument a single character.
basic_string& operator=(charT c);
You could write
std::string s1( 1, str[0] );
or (there is used the initializating-list constructor)
std::string s1 = { str[0] };
or
std::string s1 = { str, 0, 1 };

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.

Substitute char array with std::string in an input parameter to a function

Following are two legacy routines. I cannot change the routine declarations.
static bool GetString(char * str); //str is output parameter
static bool IsStringValid(const char * str); //str is input parameter
With call as follows
char inputString[1000];
GetString(inputString);
IsStringValid(inputString);
Instead of using fixed char array, I want to use std::string as the input. I am not able get the semantics right (string::c_str).
With IsEmpty it should not be a problem:
std::string str = "Some text here";
IsEmpty(str.c_str());
Though it's pretty useless if you have a std::string as then you would normally just call str.empty().
The other function though, that's harder. The reason is that it's argument is not const, and std::string doesn't allow you to modify the string using a pointer.
It can be solved, by writing a wrapper-function which takes a string reference, and have an internal array used for the actual GetString call, and uses that array to initialize the passed string reference.
Wrapper examples:
// Function which "creates" a string from scratch
void GetString(std::string& str)
{
char tempstr[4096];
GetString(tempstr);
str = tempstr;
}
// Function which modifies an existing string
void ModifyString(std::string& str)
{
const size_t length = str.size() + 1;
char* tempstr = new char[length];
std::copy_n(str.c_str(), tempstr, length);
ModifyString(tempstr);
str = tempstr;
delete[] tempstr;
}
You can't use c_str for the first function, because it returns a const char*. You can pass a std::string by reference and assign to it. As for is empty, you can call c_str on your string, but you'd be better of calling the member empty().
I think you can use the string container of STL ( Standard template Library ) .
#include <string>
bool isempty ( int x ) {
return ( x == 0 ) ? true : false ;
}
// inside main()
string s ;
cin >> s ; // or getline ( cin , s) ;
bool empty = isEmpty (s.length()) ;
std::string has c_str() which you can use for IsEmpty. There ist no function which gives you a non const pointer. Since std::string's allocation is not guaranteed to be contiguous you cannot do something like &s[0] either. The only thing you can do is to use a temporary char buffer as you do in your example.
std::string s;
char inputString[1000];
std::vector<char> v(1000);
GetString(inputString);
GetString(&v[0]);
s = &v[0];
IsEmpty(s.c_str());

How to copy a string of std::string type in C++?

I used the strcpy() function and it only works if I use C-string arrays like:
char a[6] = "text";
char b[6] = "image";
strcpy(a,b);
but whenever I use
string a = "text";
string b = "image";
strcpy(a,b);
I get this error:
functions.cpp: no matching function for call to strcpy(std::string&, std::string&)
How to copy 2 strings of string data type in C++?
You shouldn't use strcpy() to copy a std::string, only use it for C-Style strings.
If you want to copy a to b then just use the = operator.
string a = "text";
string b = "image";
b = a;
strcpy is only for C strings. For std::string you copy it like any C++ object.
std::string a = "text";
std::string b = a; // copy a into b
If you want to concatenate strings you can use the + operator:
std::string a = "text";
std::string b = "image";
a = a + b; // or a += b;
You can even do many at once:
std::string c = a + " " + b + "hello";
Although "hello" + " world" doesn't work as you might expect. You need an explicit std::string to be in there: std::string("Hello") + "world"
strcpy example:
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[]="Sample string" ;
char str2[40] ;
strcpy (str2,str1) ;
printf ("str1: %s\n",str1) ;
return 0 ;
}
Output: str1: Sample string
Your case:
A simple = operator should do the job.
string str1="Sample string" ;
string str2 = str1 ;
Caesar's solution is the best in my opinion, but if you still insist to use the strcpy function, then after you have your strings ready:
string a = "text";
string b = "image";
You can try either:
strcpy(a.data(), b.data());
or
strcpy(a.c_str(), b.c_str());
Just call either the data() or c_str() member functions of the std::string class, to get the char* pointer of the string object.
The strcpy() function doesn't have overload to accept two std::string objects as parameters.
It has only one overload to accept two char* pointers as parameters.
Both data and c_str return what does strcpy() want exactly.

Why is part of my code not executed?

I'm using Visual C++ to compile my plug-in for Cinema 4D.
GeDebugOut("-->");
subroot = NULL;
head = NULL;
tail = NULL;
success = PolygonizeHierarchy(source, hh, head, tail, &subroot, malloc);
if (!success) {
/* .. */
}
String str("not set.");
if (subroot) {
GeDebugOut("yes");
str = "yes!";
GeDebugOut("Subroot name: " + subroot->GetName());
}
else {
GeDebugOut("no");
str = "no!";
}
GeDebugOut("Is there a subroot? " + str);
GeDebugOut("<--");
The expected output is the following:
-->
yes
Subroot name: Cube
Is there a subroot? yes
<--
(or the same with "no" instead.) But I get
-->
yes
<--
Why are two prints missing here?
This is the declaration of GeDebugOut.
void GeDebugOut(const CHAR* s, ...);
void GeDebugOut(const String& s);
The String class is concatenateable. It overloads the + operator.
String(void);
String(const String& cs);
String(const UWORD* s);
String(const CHAR* cstr, STRINGENCODING type = STRINGENCODING_XBIT);
String(LONG count, UWORD fillch);
friend const String operator +(const String& Str1, const String& Str2);
const String& operator +=(const String& Str);
You need to use GeDebugOut like you use printf:
GeDebugOut("Some message = %s ", whatever);
where whatever is a c-string, i.e its type is char*.
Since an overload of GeDebugOut accepts String type also, then I think you need to use unicode as:
GeDebugOut(L"Is there a subroot? " + str);
// ^ note this!
because my suspicion is that if unicode is enabled, then CHAR is basically wchar_t, not char. And because of this, the string concatenation doesn't work, as the string-literal doesn't implicitly get converted into String type, to be passed to + overload.
You cannot append a string to a string literal.
"Is there a subroot" is a string literal and the compiler will see the use of it as a pointer to that literal.
A better way would be to do:
GeDebugOut("Is there a subroot? %s ", str);
As you mentioned, there are two versions of GeDebugOut the compiler can choose from:
void GeDebugOut(const CHAR* s, ...);
void GeDebugOut(const String& s);
when it encounters:
GeDebugOut("Is there a subroot? " + str);
"Is there a subroot" is a string literal, which translates to type const char*. I suspect String has a conversion operator to some numeric type. So the compiler is choosing the first overload.
This is resulting in behavior you're not expecting, because the + operation for const char* is pointer arithmetic, not string concatenation, so you're calling GeDebugOut on the pointer sum of your string literal, and whatever the output of that const char* conversion of str is.
There's several ways you can correct this. As another mentioned, you can change it to printf-like syntax. Or you can force it to use the String overlaod like so:
GeDebugOut(String("Is there a subroot?") + str);