I want to change the characters in a string passed by user, converted into a C-style string and passed as an argument to a function with a char * argument:
#include <string>
#include <cstring>
#include <iostream>
#include <stdlib.h>
void functoupper(char *myString)
{
int i=0;
char z;
do {
z= myString[i];
myString[i]=toupper(z);
++i;
} while(myString[i]!=0);
}
int main() {
std::string name;
std::cout << "Please, enter your full name in small caps: ";
std::getline (std::cin,name);
const char *myString = name.c_str();
std::cout << "Hello, " << functoupper(myString) << "!\n";
return 0;
}
I get error error: invalid conversion from 'const char*' to 'char*' [-fpermissive] when calling function functoupper(myString) in main().
The std::string::c_str() method returns a pointer to const char data, but your function expects a pointer to non-const char data. That is why you are getting an error.
You could use const_cast to cast away the const (but that is not really advisable):
char *myString = const_cast<char*>(name.c_str());
functoupper(myString);
std::cout << "Hello, " << name << "!\n";
You could use the non-const std::string::operator[] to access the string's underlying character data (just be careful because prior to C++11, characters were not required to be stored contiguously in memory, but most std::string implementations did):
functoupper(&name[0]);
std::cout << "Hello, " << name << "!\n";
In C++17 and later, you can use the non-const std::string::data() method instead:
functoupper(name.data());
std::cout << "Hello, " << name << "!\n";
That being said, heed this warning when using toupper():
Like all other functions from <cctype>, the behavior of std::toupper is undefined if the argument's value is neither representable as unsigned char nor equal to EOF. To use these functions safely with plain chars (or signed chars), the argument should first be converted to unsigned char ... Similarly, they should not be directly used with standard algorithms when the iterator's value type is char or signed char. Instead, convert the value to unsigned char first
With that said, try something more like this:
#include <string>
#include <iostream>
#include <cctype>
void functoupper(char *myString)
{
for (int i = 0; myString[i] != '\0'; ++i) {
unsigned char z = static_cast<unsigned char>(myString[i]);
myString[i] = static_cast<char>(std::toupper(z));
}
}
int main() {
std::string name;
std::cout << "Please, enter your full name in small caps: ";
std::getline(std::cin, name);
functoupper(&name[0]); // or name.data()
std::cout << "Hello, " << name << "!\n";
return 0;
}
That being said, you should just pass the entire std::string as-is into your function instead, and then you can manipulate it as needed, for instance with the std::transform() algorithm:
#include <string>
#include <iostream>
#include <algorithm>
#include <cctype>
void functoupper(std::string &myString)
{
std::transform(myString.begin(), myString.end(), myString.begin(),
[](unsigned char ch){ return std::toupper(ch); }
);
}
int main() {
std::string name;
std::cout << "Please, enter your full name in small caps: ";
std::getline(std::cin, name);
functoupper(name);
std::cout << "Hello, " << name << "!\n";
return 0;
}
Alternatively:
#include <string>
#include <iostream>
#include <algorithm>
#include <cctype>
std::string functoupper(std::string myString)
{
std::transform(myString.begin(), myString.end(), myString.begin(),
[](unsigned char ch){ return std::toupper(ch); }
);
return myString;
}
int main() {
std::string name;
std::cout << "Please, enter your full name in small caps: ";
std::getline(std::cin, name);
std::cout << "Hello, " << functoupper(name) << "!\n";
return 0;
}
As #Someprogrammerdude and #RemyLebeau comment, why not simply:
std::transform(std::begin(name), std::end(name), std::begin(name),
[](const unsigned char c)
{
return std::toupper(c);
});
But if you must do it via a char*, then you'll need to copy the data over first, something like:
char myString* = new char[name.size() + 1];
strcpy(myString, name.c_str());
EDIT: Thanks to the helpful comments by #RemyLebeau
Better still avoid all the memory management issues with the above by simply coping your std::string into a std::vector:
std::vector<char> myVec(std::begin(name), std::end(name));
myVec.push_back(`\0`);
and then call your char* function with:
functoupper(myVec.data());
Related
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.
I learned a helper function that can convert strings to integers:
int string_to_int(string s)
{
istringstream instr(s);
int n;
instr>>n;
return n;
}
It's mentioned that the argument s cannot be c-str string, why is this the case?
But you can pass a C style string.
The reason for that is because the std::string constructor can implicitly accept a CharT* (Char type, which is char in this case) as a parameter. Thus, something like the following would work:
#include <iostream>
#include <sstream>
using namespace std;
int string_to_int(string s)
{
istringstream instr(s);
int n;
instr>>n;
return n;
}
int main()
{
const char* test = "12345";
std::cout << string_to_int(test) << "\n"; // Outputs 12345
std::cout << string_to_int("122") << "\n"; // Outputs 122
}
I ran into such a problem: i wrote some code and when i try to format some data (especially strings) i got strange result
#include <iostream> // std::cout, std::endl
#include <string.h>
#include <vector>
#include <cstdarg>
#include <sstream>
using namespace std;
void va_cout(string format, ...)
{
vector<char> buf(256);
va_list args;
va_start(args, format);
vsnprintf_s(&buf[0], buf.size(), buf.size() + strlen(format.c_str()), format.c_str(), args);
va_end(args);
cout << endl << "apply va_cout(""%s"", s) = " << &buf[0] << endl;
}
int main() {
string s("myString");
cout << endl << s << endl;
va_cout("%s", s);
va_cout("%s", s.c_str());
return 0;
}
// results
myString
apply va_cout(%s, s) = └¤#
apply va_cout(%s, s) = myString
why it returns line 2 ?
%s can be used only with char * and const char *. You are passing a std::string and treating it like a char * in vsnprintf_s(). There is no implicit conversion from std::string to char *. You need to call std::string::c_str() for that.
So I have been trying for 1.30 hour to get this to work. I am new indeed, but I have searched all over the place and couldn't find an exact answer. I do not wish to do this another way, as it would take away the entire purpose of learning to code. I have to find why this thing isn't working. I tried dozens if not hunderds of syntaxes, but nothing works.
I want to read in a const char* name, than count the number of elements in it, so I thought had to be strlen(), and than output the name and the number of elements. If that works I can write the rest of the code.
#include <iostream>
using namespace std;
int main()
{
//writing your name, and counting the characters including \0
int a;
const char* name;
a = int strlen(name);
cin.getline(name);
cout << name;
cout >> a;
return 0;
}
There are a lot of problems with your code.
You are not allocating any memory for cin.getline() to read into. const char* name; is declaring an uninitialized pointer to nothing. You have to allocate memory for name before you can then read any data into it.
cin.getline() expects two input parameters (a pointer to an allocated buffer, and the max number of characters the buffer can hold), but you are only passing in one value.
You are calling strlen() before you have read anything into name (and there is a syntax error on your strlen() statement anyway).
You are passing a to std::cout using >>, but std::ostream does not implement the >> operator. You have to use << instead.
And lastly, don't use using namespace std;.
Try this instead:
#include <iostream>
#include <cstring>
int main()
{
//writing your name, and counting the characters including \0
int a;
char name[32];
std::cin.getline(name, 32);
a = std::strlen(name);
std::cout << "You entered: " << name << std::endl;
std::cout << "It is << a << " chars in length" << std::endl;
return 0;
}
Or, if you really don't like using std:: everywhere, at least use using <identifier>; instead of using namespace std;:
#include <iostream>
#include <cstring>
using std::cin;
using std::strlen;
using std::cout;
using std::endl;
int main()
{
//writing your name, and counting the characters including \0
int a;
char name[32];
cin.getline(name, 32);
a = strlen(name);
cout << "You entered: " << name << endl;
cout << "It is " << a << " chars in length" << endl;
return 0;
}
Now, that being said, the preferred solution is to use std::getline() instead of cin.getline():
#include <iostream>
#include <string>
int main()
{
int a;
std::string name;
std::getline(std::cin, name);
a = name.length();
std::cout << "You entered: " << name << std::endl;
std::cout << "It is " << a << " chars in length" << std::endl;
return 0;
}
I found a working solution, although I don't see where I had gone wrong. But this does exactly what I want using const char* and strlen() without using std::string.
Thanks for all your help, you have all pointed me to the correct direction.
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int main ()
{
const char *name;
int len;
name = "stephane";
len = strlen(name);
cout << name;
cout << len;
return(0);
}
As another user has pointed out, I think it's a good idea for you to take a few steps back and read the basics until you understand how pointers work.
A const char* is that: const. It could be used usually while doing things like this:
const char* cpName = "Stephane"; //expected not to change through the program's lifetime
char* pName = "Stephane"; //can be changed to point to something else
char *pOther = "Vada";
pName = pOther; //pName now points to the string "Vada"
cpName = pOther; //this won't compile as cpName is const
I would like to know what is the easiest way to convert an int to C++ style string and from C++ style string to int.
edit
Thank you very much. When converting form string to int what happens if I pass a char string ? (ex: "abce").
Thanks & Regards,
Mousey
Probably the easiest is to use operator<< and operator>> with a stringstream (you can initialize a stringstream from a string, and use the stream's .str() member to retrieve a string after writing to it.
Boost has a lexical_cast that makes this particularly easy (though hardly a paragon of efficiency). Normal use would be something like int x = lexical_cast<int>(your_string);
You can change "%x" specifier to "%d" or any other format supported by sprintf. Ensure to appropriately adjust the buffer size 'buf'
int main(){
char buf[sizeof(int)*2 + 1];
int x = 0x12345678;
sprintf(buf, "%x", x);
string str(buf);
int y = atoi(str.c_str());
}
EDIT 2:
int main(){
char buf[sizeof(int)*2 + 1];
int x = 42;
sprintf(buf, "%x", x);
string str(buf);
//int y = atoi(str.c_str());
int y = static_cast<int>(strtol(str.c_str(), NULL, 16));
}
This is to convert string to number.
#include "stdafx.h"
#include <iostream>
#include <string>
#include <sstream>
int convert_string_to_number(const std::string& st)
{
std::istringstream stringinfo(st);
int num = 0;
stringinfo >> num;
return num;
}
int main()
{
int number = 0;
std::string number_as_string("425");
number = convert_string_to_number(number_as_string);
std::cout << "The number is " << number << std::endl;
std::cout << "Number of digits are " << number_as_string.length() << std::endl;
}
Like wise, the following is to convert number to string.
#include "stdafx.h"
#include <iostream>
#include <string>
#include <sstream>
std::string convert_number_to_string(const int& number_to_convert)
{
std::ostringstream os;
os << number_to_convert;
return (os.str());
}
int main()
{
int number = 425;
std::string stringafterconversion;
stringafterconversion = convert_number_to_string(number);
std::cout << "After conversion " << stringafterconversion << std::endl;
std::cout << "Number of digits are " << stringafterconversion.length() << std::endl;
}
Use atoi to convert a string to an int. Use a stringstream to convert the other way.