How do I concatenate strings with chars in C++? - c++

I've got a function which takes a string, let's call it
void print(std::string myString)
{
std::cout << myString;
}
I want to do something like
char myChar;
myChar = '{';
print("Error, unexpected char: " + myChar + "\n");
It doesn't work.
I tried something like
print(std::string("Error, unexpected char") + std::string(myChar) + std::string("\n) )
but then std::string(myChar) becomes whatever int the char represents, it's printed as an int and isn't printed as it's alphanumeric representation!

The function should be declared like:
void print( const std::string &myString)
{
std::cout << myString;
}
and called like:
print( std::string( "Error, unexpected char: " ) + myChar + "\n");
As for your comment:
as a follow up, would it have been possible to pass an anonymous
function returning a string as an argument to print()? Something like
print( {return "hello world";}
then you can do this as it is shown in the demonstration program:
#include <iostream>
#include <string>
void f( std::string h() )
{
std::cout << h() << '\n';
}
int main()
{
f( []()->std::string { return "Hello World!"; } );
return 0;
}

If you are using C++14, you can do this:
using namespace std::literals;
char myChar;
myChar = '{';
print("Error, unexpected char: "s + myChar + "\n"s);

You can convert any one and concat.
You can use str.c_str() to convert C++ string to C character array.
Or
Use std::string inbuilt constructor to convert C character array to C++ string.

Related

Cannot directly convert number to hex null-terminated string, has to convert to std::string then use .c_str()

I've tried to convert an integer to a hex null-terminated (or "C-style") string but I cannot use it with printf or my custom log function. It only works if I convert it to an std::string then use .c_str() when passing it as a parameter, which produces ugly, hard-to-understand code.
It's important to know that using std::string and appending to it with "str +=" does work.
const char* IntToHexString(int nDecimalNumber) {
int nTemp = 0;
char szHex[128] = { 0 };
char hex[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
while (nDecimalNumber > 0) {
nTemp = nDecimalNumber % 16;
sprintf(szHex, "%s%s", hex[nTemp], szHex);
nDecimalNumber = nDecimalNumber / 16;
}
sprintf(szHex, "0x%s", szHex);
return szHex;
}
I've tried to use Visual Studio Debugger but it doesn't show any error messages, because crashes somewhere in a DLL that has no symbols loaded
Your main problem is that you define a variable on the stack, locally in the function, and then return it.
After the function returns, the char* will point to "somewhere", to an undefined position. That is a major bug. You have also other bugs that have been commented on already. Like sprintf(szHex, "0x%s", szHex);, which is undefined behaviour (UB) or sprintf(szHex, "%s%s", hex[nTemp], szHex); which has the same problem + additionally a wrong format string.
The more C++ solution would be, as already shown in many posts:
#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
std::string toHexString(unsigned int hexValue)
{
std::ostringstream oss;
oss << "0x" << std::hex << hexValue;
return std::string(oss.str());
}
int main()
{
std::cout << toHexString(15) << '\n';
// or directly
std::cout << "0x" << std::hex << 15 << '\n';
return 0;
}
Of course a C-Style solution is also possible.
But all the following I would not recommend:
If you want to stick to C like solution with char *, you could make the char szHex[128] = { 0 }; static. Or, even better, pass in the pointer to a buffer and return its address, like in
#include <stdio.h>
#include <iostream>
char* toHexCharP(unsigned int hexValue, char *outBuffer, const size_t maxSizeOutBuffer)
{
snprintf(outBuffer,maxSizeOutBuffer-1,"0x%X",hexValue);
return outBuffer;
}
constexpr size_t MaxBufSize = 100U;
int main()
{
char buf[MaxBufSize];
std::cout << toHexCharP(15, buf, MaxBufSize) << '\n';
return 0;
}
But as said, I would not recomend. Too dangerous.
Your solution should look as follows:
std::string IntToHexString(int nDecimalNumber) {
std::ostringstream str;
str << std::hex << nDecimalNumber;
return str.str();
}
// ...
std::string transformed = IntToHexString(123);
You can then use transformed.c_str() to get your string as const char*.
Unless you have reasons to do so, you should never work with const char* in modern C++. Use std::string::c_str() if you need to.

difference between char and const char

# include <iostream>
# include <string.h>
using namespace std;
int main()
{
int a=10;
int b=20;
char op[10];
const char p='+';
cout<<"enter the operation"<<endl;
cin>>op;
if(!strcmp(op,p)==0)
{
cout<<a+b;
}
return 0;
}
compilation result
12 17 C:\Users\DELL\Documents\cac.cpp [Error] invalid conversion from 'char' to 'const char*' [-fpermissive]
I am a beginner. Please tell me what mistake have I done.
This isn't about the difference between char and const char, but between char [] and char.
strcmp expects two character arrays.
op is an array of (10) characters. Good: that's what strcmp expects.
p is a single character. Not good: strcmp needs a char array, and p isn't any kind of array, but a single character.
You can change p from a single char '+' to a char array "+", or compare only the 0th character of op, as suggested in a comment above.
there is no version of strcmp that takes a single character as a parameter but instead it takes two string and compares them.
if you want to compare a single char variable with a string you can compare it with the first element of string or with any other element:
#include <iostream>
#include <string>
int main()
{
char op[10] = "Hi";
const char p = '+';
// if( strcmp( op, p) ) // error cannot covert parameter 2 from char to const char*
// cout << "op and p are identic" << std::endl;
// else
// std::cout << "op and b are not identic" << std::endl;
if(op[0] == p)
std::cout << "op[0] and p are identic" << std::endl;
else
std::cout << "op[0] and p are not identic" << std::endl;
const char* const pStr = "Bye"; //constant pointer to constant character string: pStr cannot change neither the address nor the value in address
const char* const pStr2 = "bye"; // the same as above
// pStr++; //error
// pStr[0]++; // error
if( !strcmp( pStr, pStr2) )
std::cout << "pStr and pStr2 are identic" << std::endl;
else
std::cout << "pStr and pStr2 are Not identic" << std::endl;
return 0;
}

C++ Pointer Char

I'm new to C++ and I'm now learning about pointers. I'm trying to understand this program:
#include <iostream>
int main() {
char *text = "hello world";
int i = 0;
while (*text) {
i++;
text++;
}
printf("Char num of <%s> = %d", text, i);
}
It outputs:
Char num of <> = 11
But why not this:
Char num of <hello world> = 11
As your increase text until it points to '\0',
the string printed is empty.
You changed the value of text before printing it out:
#include <iostream>
int main() {
// text starts pointing at the beginnin of "hello world"
char *text = "hello world"; // this should be const char*
int i = 0;
while (*text) {
i++;
// text moves forward one character each time in the loop
text++;
}
// now text is pointing to the end of the "hello world" text so nothing to print
printf("Char num of <%s> = %d", text, i);
}
The value of a char pointer (like text) is the location of the character that it is pointing to. If you increase text by one (using text++) then it points to the location of the next character.
Not sure why you #include <iostream> but use printf(). Typically in C++ code you would do this:
std::cout << "Char num of <" << text << "> = " << i << '\n';
A working example of what you are trying to do:
int main()
{
const char* text = "hello world"; // should be const char*
int length = 0;
for(const char* p = text; *p; ++p)
{
++length;
}
std::cout << "Char num of <" << text << "> = " << length << '\n';
}
First of all - don't use char-string in c++! Use std::string.
Your while loop continues until it reach zero which is the string termination, so %s is just an empty string. The '<' and '>' is still printed even if the string is empty.
Your text pointer start as the following chars:
'h','e','l','l','o',' ','w','o','r','l','d','\0'
After the first loop, text points to:
'e','l','l','o',' ','w','o','r','l','d','\0'
After second loop, text points to:
'l','l','o',' ','w','o','r','l','d','\0'
And so on.
The while-loop continues until text points to '\0' which is just an empty string, i.e. "".
Consequently %s doesn't print anything.
In c++ do:
int main() {
std::string text = "hello world";
cout << "Char num of <" << text << "> = " << text.size() << std::endl;
}
text is a pointer to a char. So when you increment the pointer you make it to point to the next element. The end of a string in C is delimited by the null character. So you are incrementing the pointer until it points to the null character. After that, when you call printf it doesn't print anything because it prints characters until reaches the null character but it is already at the null character.
This could be a quick fix:
#include <stdio.h>
int main() {
char *text = "hello world";
int i = 0;
while (*text) {
i++;
text++;
}
printf("Char num of <%s> = %d", text-i, i);
}
After the loop pointer text points to the terminating zero of the string literal because it is increased in the loop.
Also function printf is declared in header <cstdio> And string literals in C++ have types of constant arrays (Though in C they have types of non-constant arrays. Nevertheless in the both languages you may not change string literals)
You can rewrite the program either like
#include <cstdio>
int main() {
const char *text = "hello world";
int i = 0;
while ( text[i] ) ++i;
std::printf("Char num of <%s> = %d\n", text, i);
}
Or like
#include <cstdio>
int main() {
const char *text = "hello world";
int i = 0;
for ( const char *p = text; *p; ++p ) ++i;
std::printf("Char num of <%s> = %d\n", text, i);
}
Also it is better instead of C function printf to use standard C++ stream operators.
For example
#include <iostream>
int main() {
const char *text = "hello world";
size_t i = 0;
for ( const char *p = text; *p; ++p ) ++i;
std::cout << "Char num of <" << text << "> = " << i << std::endl;
}

Unexpected output when I try to reverse a char*

#include<iostream>
#include<string>
using namespace std;
void reverse(char* str)
{
char *new_str = str;
while(*new_str != '\n'){
new_str++;
}
while(new_str != str){
cout << *new_str;
new_str--;
}
cout << *new_str;
}
int main()
{
char *str = new char[1024];
str = "hello world";
reverse(str);
}
When I try to run this I get some crazy output and my computer starts to beep. What am I doing blatantly wrong here?
The end of a C string is marked by the character '\0'. You used '\n' which is the newline character.
You mean apart from using the naked leaky new, the deprecated char* instead of const char* or even better std::string, not using a Standard Library algorithm std::reverse, mixing IO with your algorithm and including the entire namespace std (which might indirectly bring std::reverse() into scope) without putting your own reverse() inside its own namespace?
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
// using namespace std; // for the brave, and drop the std:: in the next 3 lines
int main()
{
std::string str = "hello world"; // std::string instead of char*
std::reverse(begin(str), end(str)); // standard library algorithm
std::cout << str; // IO separate from algorithm
}
If you are only interested in how to code a reverse algorithm, here is one way to do it without relying on the fact that you have a null terminator:
template<class BidirIt>
void reverse(BidirIt first, BidirIt last)
{
while ((first != last) && (first != --last)) {
std::swap(*first++, *last);
}
}
The problem is that at first you assigned str the address of allocated memory and then reassigned it to point to string literal that has type const char[] in C++.
char *str = new char[1024];
str = "hello world";
This string literal has terminating zero char '\0'. It has no the new line char '\n'. So the function is invalid because it will try to access memory beyond the array searching the new line char.
The valid code could look the following way
#include <iostream>
using namespace std;
void reverse( const char* s )
{
const char *p = s;
while ( *p ) p++;
while ( p != s ) cout << *--p;
}
int main()
{
const char *s = "hello world";
reverse( s );
}
Or if you want to enter a string yourself interactively then main could look as
int main()
{
const size_t N = 1024;
char s[N];
cout << "Enter a statement: ";
cin.getline( s, N );
reverse( s );
}
correct your function :
void reverse(char* str)
{
char *new_str = str;
while(*new_str){ // use this instead of *new_ptr != '\n'
new_str++;
}
while(new_str != str){
cout << *new_str;
new_str--;
}
cout << *new_str;
}

Quoting strings in C++

In Pascal Lazarus/Delphi, we have a function QuotedStr() that wraps any string within single quotes.
Here's an example of my current C++ code:
//I need to quote tblCustomers
pqxx::result r = txn.exec( "Select * from \"tblCustomers\" ");
Another one:
//I need to quote cCustomerName
std::cout << "Name: " << r[a]["\"cCustomerName\""];
Similar to the above, I have to frequently double-quote strings. Typing this in is kind of slowing me down. Is there a standard function I can use for this?
BTW, I develop using Ubuntu/Windows with Code::Blocks. The technique used must be compatible across both platforms. If there's no function, this means that I must write one.
C++14 added std::quoted which does exactly that, and more actually: it takes care of escaping quotes and backslashes in output streams, and of unescaping them in input streams. It is efficient, in that it does not create a new string, it's really a IO manipulator. (So you don't get a string, as you'd like.)
#include <iostream>
#include <iomanip>
#include <sstream>
int main()
{
std::string in = "\\Hello \"Wörld\"\\\n";
std::stringstream ss;
ss << std::quoted(in);
std::string out;
ss >> std::quoted(out);
std::cout << '{' << in << "}\n"
<< '{' << ss.str() << "}\n"
<< '{' << out << "}\n";
}
gives
{\Hello "Wörld"\
}
{"\\Hello \"Wörld\"\\
"}
{\Hello "Wörld"\
}
As described in its proposal, it was really designed for round-tripping of strings.
Using C++11 you can create user defined literals like this:
#include <iostream>
#include <string>
#include <cstddef>
// Define user defined literal "_quoted" operator.
std::string operator"" _quoted(const char* text, std::size_t len) {
return "\"" + std::string(text, len) + "\"";
}
int main() {
std::cout << "tblCustomers"_quoted << std::endl;
std::cout << "cCustomerName"_quoted << std::endl;
}
Output:
"tblCustomers"
"cCustomerName"
You can even define the operator with a shorter name if you want, e.g.:
std::string operator"" _q(const char* text, std::size_t len) { /* ... */ }
// ...
std::cout << "tblCustomers"_q << std::endl;
More info on user-defined literals
String str = "tblCustomers";
str = "'" + str + "'";
See more options here
No standard function, unless you count std::basic_string::operator+(), but writing it is trivial.
I'm somewhat confused by what's slowing you down - quoted( "cCustomerName" ) is more characters, no? :>
You could use your own placeholder character to stand for the quote, some ASCII symbol that will never be used, and replace it with " just before you output the strings.
#include <iostream>
#include <string>
struct quoted
{
const char * _text;
quoted( const char * text ) : _text(text) {}
operator std::string () const
{
std::string quotedStr = "\"";
quotedStr += _text;
quotedStr += "\"";
return quotedStr;
}
};
std::ostream & operator<< ( std::ostream & ostr, const quoted & q )
{
ostr << "\"" << q._text << "\"";
return ostr;
}
int main ( int argc, char * argv[] )
{
std::string strq = quoted( "tblCustomers" );
std::cout << strq << std::endl;
std::cout << quoted( "cCustomerName" ) << std::endl;
return 0;
}
With this you get what you want.
What about using some C function and backslash to escape the quotes?
Like sprintf_s:
#define BUF_SIZE 100
void execute_prog() {
//Strings that will be predicted by quotes
string param1 = "C:\\users\\foo\\input file.txt", string param2 = "output.txt";
//Char array with any buffer size
char command[BUF_SIZE];
//Concating my prog call in the C string.
//sprintf_s requires a buffer size for security reasons
sprintf_s(command, BUF_SIZE, "program.exe \"%s\" \"%s\"", param1.c_str(),
param2.c_str());
system(command);
}
Resulting string is:
program.exe "C:\users\foo\input file.txt" "output.txt"
Here is the documentation.