Storing strings - c++

I'm trying to write a code which stores strings in an array. I'm trying to do it with char* but I couldn't achieve. I search the net but couldn't find an answer. I've tried the code below, but it didn't compile.I use string stream because at some point I need to concatenate a string with an integer.
stringstream asd;
asd<<"my name is"<<5;
string s = asd.str();
char *s1 = s;

> I'm trying to write a code which stores strings in an array.
Well, first you'll need an arary of strings. I don't like using naked arrays, so I use std::vector:
std::vector<std::string> myStrings;
But, I understand you have to use an array, so we'll use an array instead:
// I hope 20 is enough, but not too many.
std::string myStrings[20];
int j = 0;
> I use string stream because ...
Okay, we'll use stringstream:
std::stringstream s;
s << "Hello, Agent " << 99;
//myStrings.push_back(s.str()); // How *I* would have done it.
myStrings[j++] = s.str(); // How *you* have to do it.
That gets us one string, but you want an array of them:
for(int i = 3; i < 11; i+=2) {
s.str(""); // clear out old value
s << i << " is a" << (i==9?" very ":"n ") << "odd prime.";
//myStrings.push_back(s.str());
myStrings[j++] = s.str();
}
Now you have an array of strings.
Complete, tested program:
#include <sstream>
#include <iostream>
int main () {
// I hope 20 is enough, but not too many.
std::string myStrings[20];
int j = 0;
std::stringstream s;
s << "Hello, Agent " << 99;
//myStrings.push_back(s.str()); // How *I* would have done it.
myStrings[j++] = s.str(); // How *you* have to do it.
for(int i = 3; i < 11; i+=2) {
s.str(""); // clear out old value
s << i << " is a" << (i==9?" very ":"n ") << "odd prime.";
//myStrings.push_back(s.str());
myStrings[j++] = s.str();
}
// Now we have an array of strings, what to do with them?
// Let's print them.
for(j = 0; j < 5; j++) {
std::cout << myStrings[j] << "\n";
}
}

How about something like this?
vector<string> string_array;
stringstream asd;
asd<<"my name is"<<5;
string_array.push_back(asd.str());

char *s1 = s;
Is illegal. You either need:
const char *s1 = s.c_str();
if you're not set on char*, or you'll need to allocate a new char* and use strcpy to copy the contents from the string.

Just change your code to
char const* s1 = s.c_str();
because a pointer to char can't store a string object, only a pointer to char, which is what c_str() returns.

I wouldn't use the char * directly. I would wrap it in something like the template below. You can override the operators you need to do any more operations (example, I would make data a private member, and override the operators to make the data print out cleanly). I did the assignment operator just to demonstrate how clean that could make code.
#include "MainWindow.h"
#include <stdio.h>
using namespace std;
template<size_t size>
class SaferChar
{
public:
SaferChar & operator=(string const & other)
{
strncpy(data, other.c_str(), size);
return *this;
}
char data[size];
};
int main(int argc, char *argv[])
{
SaferChar<10> safeChar;
std::string String("Testing");
safeChar = String.c_str();
printf("%s\n", safeChar.data);
return 0;
}

Related

How to use pointer to string in cpp?

I am studying pointers in C++. I have studied call by value and call by reference concept. I am trying to create a function to reverse a string which accepts a pointer to string and the size of string. The code is as follow
void reverse(string* str, int size)
{
int start = 0;
int end = size - 1;
while(start < end)
{
swap(*str[start++], *str[end--]);
}
}
int main()
{
string str = "Something";
reverse(&str, str.length());
cout << "Reversed string: " << str << endl;
return 0;
}
I am getting this error:
error: no match for ‘operator*’ (operand type is ‘std::string’ {aka
‘std::__cxx11::basic_string’})
12 | swap(*str[start++], *str[end--]);
I don't want to use the character array, is there way to do it?
Someone please explain, what's wrong in my code. Thank you.
Here is the simple fix. You don't need to change anything except a few lines.
#include <iostream>
#include <algorithm>
#include <cstring>
void reverse( std::string* str ) // no need to pass size to this function
{
int start = 0;
int end = str->length() - 1; // get the length of str like this
char* ptrToCharArray = const_cast<char*>( str->c_str() ); // gets the pointer to str's internal buffer
while ( start < end )
{
std::swap( ptrToCharArray[start++], ptrToCharArray[end--] ); // no need to use * operator anymore
}
}
int main()
{
std::string str = "Something";
reverse( &str );
std::cout << "Reversed string: " << str << std::endl;
return 0;
}
Output is:
Reversed string: gnihtemoS
Hopefully, this helps you.
Just need a little bit of change in your code
Change this *str[start++] to (*str).at(start++)
void reverse(string* str, int size)
{
int start = 0;
int end = size - 1;
while(start < end)
{
swap((*str).at(start++),(*str).at(end--));
}
}
int main()
{
string str = "Something";
reverse(&str, str.length());
cout << "Reversed string: " << str << endl;
return 0;
}
Note that there is no need to pass the size of the string as an argument to the function. You can use the member function std::string::size for that purpose as shown below:
Version 1: Passing pointer to string as argument
#include <iostream>
#include <algorithm>
void reverse(std::string *str)
{
int n=(*str).size()-1;//dereference the pointer and use size member function on the resulting string object
for(int i=0;i<((*str).size()/2);i++){
//Using the swap method to switch values at each index
std::swap((*str).at(i),(*str).at(n)); //note this can also be written as std::swap((*str)[i],(*str)[n]);
n = n-1;
}
}
int main()
{
std::string myString = "myString";
reverse(&myString);
std::cout<<"Reversed string is: "<<myString<<std::endl;
return 0;
}
In version 1, *(str) gives us a std::string type object. Next we call size member function on this std::string object. Similarly we can call the std::string::at member function on this std::string object.
Version 2: Passing reference to string as argument
#include <iostream>
#include <algorithm>
void reverse( std::string &str)
{
int n=str.size()-1;
for(int i=0;i<(str.size()/2);i++){
//Using the swap method to switch values at each index
std::swap(str.at(i),str.at(n));
n = n-1;
}
}
int main()
{
std::string myString = "myString";
reverse(myString);
std::cout<<"Reversed string is: "<<myString<<std::endl;
return 0;
}

C++ How to write function that return char pointer

I want to write a function that receive an int argument then converter to a char pointer (c-string), but my code output is not right.
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
char *stoc(int n){
stringstream stream;
stream <<"Log"<<n<<".txt";
string name;
stream >>name;
int len = name.length();
char ch[len+1];
for(int i=0; i<len; i++){
ch[i]=name[i];
}
ch[len+1] = '\0';
return ch;
}
int main() {
char *name = stoc(3);
cout << name << endl;
return 0;
}
Summarising the comments:
You normally do not use C-style-strings in C++, just stick to std::strings. Therefor you should rather return name instead of your converted ch, especially since you have already created a std::string. Having access to at least C++11 you can then easily convert your rather long function into a one-liner
C++11
std::string stoc(int n) {
return "Log" + std::to_string(n) + ".txt";
}
prior C++11
std::string stoc(int n) {
std::ostringstream oss;
oss << "Log" + n + ".txt";
return oss.str(); // by accessing a stringstreams content directly there is no need to use an extra variable
}
If you do need to use a C-style-string later on somewhere, e.g. as a parameter for a C-library function, you can use c_str to convert any std::string into it's C-style equivalent:
int main() {
std::string name = stoc(3);
std::cout << name << std::endl;
}
You should do this instead of returning a pointer to a local variable (which yields in undefined behaviour):
...
char *ch = new char[len+1];
for(int i=0; i<len; i++){
ch[i]=name[i];
}
ch[len] = '\0';
...
int main() {
char *name = stoc(3);
cout << name << endl;
delete [] name; // delete what has been allocated in stoc
return 0;
}
Also note the ch[len] = '\0' instead of ch[len + 1] = '\0'.
But in C++ you should rather use std::string and not deal with char arrays, new and delete at all.

C++ SDL 2.0 - Importing multiple textures using a loop

I don't know whether or not this is possible but I have used this technique in different languages but am struggling to use it in C++. I have 10 images that I am trying to load into an array using a loop as so:
for (int i = 0; i < 10; i++)
{
Sprite[i] = IMG_LoadTexture(renderer, "Graphics/Player" + i + ".png");
}
This however does not seem to work in C++ so I was wondering what I am doing wrong, or what can I do to get the same result without having to load each image individually like so:
Sprite[0] = IMG_LoadTexture(renderer, "Graphics/Player0.png");
My error is: "Expression must have integral or unscoped enum type"
Thanks for any help =)
You cannot do this:
"This is my number: " + (int)4 + "!";
This is illegal. It will give you an error for trying to operator+ a const char* and a const char[SOME_INT_GOES_HERE] or another error for trying to use operator+ to add an int onto a string. Things just don't work that way.
You'd either have to use C (i.e. snprintf()) or a string stream. Here's my test code for isolating your problem:
#include <iostream>
#include <string>
int main()
{
int a = 1;
std::string str = "blah";
std::string end = "!";
//std::string hello = str + a + end;// GIVES AN ERROR for operator+
std::string hello = "blah" + a + "!";
//const char* c_str = "blah" + a + "end";
//std::cout << c_str << std::endl;
std::cout << hello << std::endl;
return 0;
}
Here's an alternative solution using string streams.
#include <iostream>
#include <string>
#include <sstream>
int main()
{
int i = 0;
std::string str;
std::stringstream ss;
while (i < 10)
{
//Send text to string stream.
ss << "text" << i;
//Set string to the text inside string stream
str = ss.str();
//Print out the string
std::cout << str << std::endl;
//ss.clear() doesn't work. Calling a constructor
//for std::string() and setting ss.str(std::string())
//will set the string stream to an empty string.
ss.str(std::string());
//Remember to increment the variable inside of while{}
++i;
}
}
Alternatively, you can also use std::to_string() if you're using C++11 (which just requires -std=c++11) but std::to_string() is broken on some sets of compilers (i.e. regular MinGW). Either switch to another flavor where it works (i.e. MinGW-w64) or just write your own to_string() function using string streams behind the scenes.
snprintf() may be the fastest way of doing such a thing, but for safer C++ and better style, it is recommended you use a non-C way of doing things.
I had a similar problem and I solwed it this way:
#include <iostream>
using namespace std;
int main() {
string line;
for (int i = 0; i < 10; i++) {
line = "Graphics/Player" + inttostr(i) + ".png"; //I wrote inttostr function because built in inttostr functions messed up my program (see below)
char charger[line.length()]; //creating char array
for (int i = 0; i < sizeof(line); i++) {
charger[i] = line[i]; // copying string to char arry
}
Sprite[i] = IMG_LoadTexture(renderer, charger);
}
}
string inttostr(int integer) { //I know it isn't the best way to convert integer to string, but it works
string charakter;
int swap;
bool negativ = false;
if (integer < 0) {
integer = -integer;
negativ = true;
}
if (integer == 0) {
charakter = "0";
}
while (integer >= 1) {
swap = integer % 10;
integer = integer / 10;
charakter = char(swap + 48) + charakter;
}
if (negativ) {
charakter = "-" + charakter;
}
return charakter;
}

c++ vector of boost::shared_ptr

I just started learning boost shared pointers.
I wrote a short program, results look good but I'm not sure if memory is deallocating well with my code. I would like to ask, if someone could look at my code and tell if I correctly use shared pointers.
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <vector>
#include <string>
#define VECTSIZE 10
typedef boost::shared_ptr<std::string> StringPtr;
typedef std::vector<StringPtr> StringVect;
///////////////////////////////////////////////////////////////
std::string random_string (size_t length);
///////////////////////////////////////////////////////////////
int main()
{
StringVect vect;
for (int i = 0; i < VECTSIZE; i++)
{
std::string * stdstr;
stdstr = new std::string;
*stdstr = random_string(10);
std::cout << *stdstr << "\r\n";
StringPtr str(stdstr);
vect.push_back(str);
}
std::cout << "\r\n\r\n";
for (int i = 0; i < VECTSIZE; i++)
{
std::cout << *vect[i] << "\r\n";
}
vect.clear();
system("pause");
return 0;
}
///////////////////////////////////////////////////////////////
std::string random_string (size_t length)
{
auto randchar = []() -> char
{
const char charset[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
const size_t max_index = (sizeof(charset) - 1);
return charset[ rand() % max_index ];
};
std::string str(length,0);
std::generate_n( str.begin(), length, randchar );
return str;
}
Thanks for any advice; I hope it'll be helpful for me and others.
Your use is correct in the sense that there are no direct memory leaks. However, you're not really exception safe - if random_string throws, you'll leak stdstr. It's better (and more idiomatic) to bypass rwa pointers entirely. Here's an example with using std::shared_ptr:
for (int i = 0; i < VECTSIZE; i++)
{
StringPtr str = std::make_shared<std::string>(); // Encapsulates new
*str = random_string(10);
std::cout << *str << '\n'; //No \r here: text streams insert it on Windows automatically
vect.push_back(str);
}
Also, as #ForEveR noted, there's little reason to allocate std::string dynamically in real world apps. But I assume you use it just as an excercise with smart pointers, which is fine of course.
All is okay, but you needn't vect.clear() string. However, string is value-type, don't use shared_ptr of string.

Dereferencing an unsigned char pointer and storing its values into a string

So I am working on a tool that dereferences the values of some addresses, it is in both C and C++, and although I am not familiar with C++ I figured out I can maybe take advantage of the string type offered by C++.
What I have is this:
unsigned char contents_address = 0;
unsigned char * address = (unsigned char *) add.addr;
int i;
for(i = 0; i < bytesize; i++){ //bytesize can be anything from 1 to whatever
if(add.num == 3){
contents_address = *(address + i);
//printf("%02x ", contents_address);
}
}
As you can see what I am trying to do is dereference the unsigned char pointer. What I want to do is have a string variable and concatenate all of the dereferenced values into it and by the end instead of having to go through a for case for getting each one of the elements (by having an array of characters or by just going through the pointers) to have a string variable with everything inside.
NOTE: I need to do this because the string variable is going to a MySQL database and it would be a pain to insert an array into a table...
Try this that I borrowed from this link:
http://www.corsix.org/content/algorithmic-stdstring-creation
#include <sstream>
#include <iomanip>
std::string hexifyChar(int c)
{
std::stringstream ss;
ss << std::hex << std::setw(2) << std::setfill('0') << c;
return ss.str();
}
std::string hexify(const char* base, size_t len)
{
std::stringstream ss;
for(size_t i = 0; i < len; ++i)
ss << hexifyChar(base[i]);
return ss.str();
}
I didn't quite understand what you want to do here (why do you assign a dereferenced value to a variable called ..._address)?.
But maybe what you're looking for is a stringstream.
Here's a relatively efficient version that performs only one allocation and no additional function calls:
#include <string>
std::string hexify(unsigned char buf, unsigned int len)
{
std::string result;
result.reserve(2 * len);
static char const alphabet[] = "0123456789ABCDEF";
for (unsigned int i = 0; i != len)
{
result.push_back(alphabet[buf[i] / 16]);
result.push_back(alphabet[buf[i] % 16]);
{
return result;
}
This should be rather more efficient than using iostreams. You can also modify this trivially to write into a given output buffer, if you prefer a C version which leaves allocation to the consumer.