Passing control character to char array - c++

This one
char *house2="JAM gain\r\n"
differs from this one:
string house, prefix="JAM ", suffix="\r\n";
cin>>house;
house = prefix + nickname + suffix;
char house2[100];
strncpy(house2, house.c_str(), sizeof(house));
return house2;
Even though I type "gain" on keyboard, I need to pass this char array with control-characters to api because without them it seems it's not working. what can I do to solve problem?
Ok real code:
string nickname, prefix="NICK ", suffix="\r\n";
cout<<"Choose nickname\n";
cin>>nickname;
nickname = prefix + nickname + suffix;
cout<<nickname;
char nick[100];
strncpy(nick, nickname.c_str(), sizeof(nickname));
return nick;

sizeof is not doing what you think. Instead of
strncpy(nick, nickname.c_str(), sizeof(nickname));
you want
strncpy(nick, nickname.c_str(), nickname.size());
But even then you open yourself up to buffer-overflow, so you really want
strncpy(nick, nickname.c_str(), sizeof(nick));
Next problem is that nick is local to your function so returning it is going to "cause bad things". You could make it static (and then run into complex problems with threads later...) or you could pass it in as an argument (which would then mean you couldn't use sizeof, for technical reasons). What you really need is something a lot simpler - just return the string, not the C string.
string getNick() {
string nickname, prefix="NICK ", suffix="\r\n";
cout<<"Choose nickname\n";
cin>>nickname;
nickname = prefix + nickname + suffix;
cout<<nickname;
return nickname;
}
And just to show that it really is doing what its supposed to be, here's a working online version. Here's its full code for posterity:
#include <iostream>
#include <string>
std::string getNick() {
std::string nickname, prefix="NICK ", suffix="\r\n";
std::cout<<"Choose nickname\n";
std::cin>>nickname;
nickname = prefix + nickname + suffix;
std::cout<<nickname;
return nickname;
}
int main() {
std::string nick = getNick();
std::cout<<"in main nick = '"<<nick<<"'"<<std::endl;
}
Input
gain
.
Output
Choose nickname
NICK gain
in main nick = 'NICK gain
'
Since you have an API that takes a C string, you'll need to check the details for that api for ownership of the C-string - there are two options.
The API takes ownership of the C string and will dealloc it later.
The API makes a copy of the C string, and you control its lifetime.
In the first case you need to do this: (I'm assuming a C api, which will eventually free the passed in pointer - if its a badly designed C++ API which will delete[] it, you need to replace the malloc with a new char[nick.size()]
string nick = getNick();
char * buffer = (char*)malloc(nick.size()+1);
memcpy(buffer, nick.c_str(), nick.size());
buffer[nick.size()]=0;
your_api(buffer);
In the second case you can simply do
your_api(getNick().c_str());

Your code should be
string house, prefix="JAM ", suffix="\r\n";
string nickname;
cin>>nickname;
house = prefix + nickname + suffix;
char house2[100];
strncpy(house2, house.c_str(), sizeof(house2));
//or strncpy(house2, house.c_str(), house.length());
return string(house2);
Do not return house2 as char* as the memory will be destroyed once the function exits.

PROBLEM SOLVED (why? :P )
string prawniczek=choosenick();
int TempNumOne=prawniczek.size();
char niczek[40];
for (int a=0;a<=TempNumOne;a++)
{
niczek[a]=prawniczek[a];
}
ok problem was solved by simple rewriting chars at index position one by one
it has to mean that
strncpy with nickname.c_str() works different.
anyway - i think that way is not elegant, even though it works
does anyone know how to do it in correct way?
UPDATE:
moreover:
when the loop is in main at translate to char array from choosenick() method it works perfectly, but when i do it inside method choosenick() and return translated loop result to main it doesn't work

Related

Ogre3d having unique node names error

I am working on city generation for a pcg game of mine. I have a for loop which makes 3 cities in random locations, I assign parentIteration to get that "id" for the city and do the same in the for loop where I make a building
for (int i = 0; i < 3; i++)
{
parentIteration = i;
std::srand(i);
_rootNode = GameManager::getSingletonPtr()->getSceneManager()->getRootSceneNode();
_cityNode = _rootNode->createChildSceneNode("cityNode " + parentIteration);
generateCity(std::rand() % 10000 + 10, std::rand() % 10000 + 10, std::rand() % 11 +1);
}
building
for (int i = 0; i < _numberOfBuildings; i++)
{
childIteration = i;
printf(" parent %d and child %d \n", parentIteration, childIteration);
Ogre::SceneNode* buildingNode = _cityNode->createChildSceneNode("citybuildingNode"+childIteration+parentIteration );
}
However when I try to launch the game it will crash on creating the second city. Saying it already has a name similar to what it is trying to write. Yet my printf clearly show that the numbers at that point are all unique. Anyone know how to resolve this issue? (added picture for proof of output)
The "itybuildingNode" in the error message suggests that
"citybuildingNode"+childIteration+parentIteration
is not working quite the way you wanted.
This is because of a couple things working against you:
"citybuildingNode" is a String Literal, and not a string object. It is litteraly just a bunch of characters in a row terminated by a null character and represented as a const char *, a pointer to that array of characters. It is low-level voodoo, the sort of stuff you might make a string class around. For more information see String Literals
Because it's not a string object, you can't pull any of the usual string object tricks like concatenating with a + and comparing with ==. But because it is a pointer, the compiler interprets + as an attempt to perform pointer arithmetic and reference another location in the array. It compiles, but note how it turned "citybuildingNode" into "itybuildingNode". Oops.
What this looks like is something like:
const char* temp = "citybuildingNode"
_cityNode->createChildSceneNode(temp + childIteration + parentIteration);
which resolves to
const char* temp = "citybuildingNode"
_cityNode->createChildSceneNode(&temp[childIteration + parentIteration]);
Even if it was a string object, the C++ standard string object, std::string does not allow you to add numbers to strings. It only adds strings together to build a bigger string. To add a number to a std::string, you have to turn the number into a std::string. std::to_string can help you here, but there is a cleaner-looking way to do this with std::stringstream
Eg:
std::stringstream nodename("citybuildingNode");
// builds a string stream around the string literal
nodename << childIteration << parentIteration;
// writes the numbers into the stream the same way `cin << number;` would
// turning the number into a string for you
Ogre::SceneNode* buildingNode = _cityNode->createChildSceneNode(nodename.str());
// gets the assembled string from the stringstream
// null-terminated string like ogre expects
This gets you started in the right direction, but still allows for collision between child 1 and parent 10 ("citybuildingNode110") and child 11 and parent 0 (also "citybuildingNode110") and similar. So you really want something more like
nodename << childIteration << '_' << parentIteration;
to force a separator between the two numbers.
Documentation for std::stringstream.
There is also another possible nasty. The string we just supplied to ogre will only exist for as long as std::stringstream nodename exists and it will die at the end of the loop that generates it. I do not see anything in a quick perusal of the documentation that says ogre makes its own copy of this string. So play around a bit to make sure that you don't have to store this name somewhere to prevent it from falling out of scope, being destroyed, and leaving ogre with a dangling reference.

C++, best way to change a string at a particular index

I want to change a C++ string at a particular index like this:
string s = "abc";
s[1] = 'a';
Is the following code valid? Is this an acceptable way to do this?
I didn't find any reference which says it is valid:
http://www.cplusplus.com/reference/string/string/
Which says that through "overloaded [] operator in string" we can perform the write operation.
Assigning a character to an std::string at an index will produce the correct result, for example:
#include <iostream>
int main() {
std::string s = "abc";
s[1] = 'a';
std::cout << s;
}
For those of you below doubting my IDE/library setup, see jdoodle demo: http://jdoodle.com/ia/ljR, and screenshot: https://imgur.com/f21rA5R
Which prints aac. The drawback is you risk accidentally writing to un-assigned memory if string s is blankstring or you write too far. C++ will gladly write off the end of the string, and that causes undefined behavior.
A safer way to do this would be to use string::replace: http://cplusplus.com/reference/string/string/replace
For example
#include <iostream>
int main() {
std::string s = "What kind of king do you think you'll be?";
std::string s2 = "A good king?";
// pos len str_repl
s.replace(40, 1, s2);
std::cout << s;
//prints: What kind of king do you think you'll beA good king?
}
The replace function takes the string s, and at position 40, replaced one character, a questionmark, with the string s2. If the string is blank or you assign something out of bounds, then there's no undefined behavior.
Yes. The website you link has a page about it. You can also use at function, which performs bounds checking.
http://www.cplusplus.com/reference/string/string/operator%5B%5D/
Yes the code you have written is valid. You can also try:
string num;
cin>>num;
num.at(1)='a';
cout<<num;
**Input**:asdf
**Output**:aadf
the std::replace can also be used to replace the charecter. Here is the reference link http://www.cplusplus.com/reference/string/string/replace/
Hope this helps.
You could use substring to achieve this
string s = "abc";
string new_s = s.substr(0,1) + "a" + s.substr(2);
cout << new_s;
//you can now use new_s as the variable to use with "aac"

Adding char to string in C++

I work with Eclipse and Arduino.
I want to add a char to a string. I tried to use append,insert ( but these can not be resolved)
I tried to use += but when i print the string it always have one char.Basically i deletes the string and writes only the new char i want to add in.
I tried also concat and it does the same thing.Also strcat gives me headache with the operands cause it needs a const char pointer and i want to add a char that changes.
while (theSettings.available()) {
character = theSettings.read();
if(character == '/') {
// Comment - ignore this line
while(character != '\n'){
character = theSettings.read();
}
} else if(isalnum(character)){ // Add a character to the description
Serial.println(character);
description +=character;
//description.concat(character);
Serial.println(description);
}
It sounds like what you want (for convenience) is the String object class available with the Arduino library.
http://arduino.cc/en/Reference/StringObject
If description is of the Ardunio-specific String type, you should be able to use the += operator to append.
You can do a very simple thing;
Serial.print(character);
Serial.print("");
Serial.println(description);
alternatively you can use "dtostrf" if you need to concatenate float and strings

a simple c++ program crashes?

Write a program that asks the user to enter his or her first name and then last
name, and that then constructs, stores, and displays a third string, consisting of the
user’s last name followed by a comma, a space, and first name.Use char arrays and
functions from the cstring header file.A sample run could look like this:
Enter your first name: Flip
Enter your last name: Fleming
Here’s the information in a single string: Fleming, Flip
int main()
{
char * fName,*lName,*fullName;
fName = new char;
cin.getline(fName,100);
lName=new char;
cin.getline(lName,100);
fullName=new char[strlen(lName)+strlen(fName)+3];
strncpy(fullName,lName,strlen(lName));
fullName[strlen(lName)]=',';
fullName[strlen(lName)+1]=' ';
char* dummy=(char*)fullName[strlen(lName)+2];//making a pointer to the char after the ' ' char to start copying the first name
strncpy(dummy,fName,strlen(fName));
dummy[strlen(fName)+strlen(lName)+2]='\0';
cout<<endl<<endl<<dummy<<endl;
delete fullName;
delete lName;
delete fName;
return 0;
}
why it crashes when i point to a char in the middle of the array and start copying ???
fName = new char;
allocates a single char.
cin.getline(fName,100);
goes way beyond that.
Use std::string instead. You'll see that writing C++ code in C++ instead of C makes life a lot easier.
The type of fullName[strlen(lName)+2] is char, to get the pointer do:
char* dummy=fullName + strlen(lName)+2;

Parsing a string by a delimeter in C++

Ok, so I need some info parsed and I would like to know what would be the best way to do it.
Ok so here is the string that I need to parse. The delimeter is the "^"
John Doe^Male^20
I need to parse the string into name, gender, and age variables. What would be the best way to do it in C++? I was thinking about looping and set the condition to while(!string.empty()
and then assign all characters up until the '^' to a string, and then erase what I have already assigned. Is there a better way of doing this?
You can use getline in C++ stream.
istream& getline(istream& is,string& str,char delimiter=’\n’)
change delimiter to '^'
You have a few options. One good option you have, if you can use boost, is the split algorithm they provide in their string library. You can check out this so question to see the boost answer in action: How to split a string in c
If you cannot use boost, you can use string::find to get the index of a character:
string str = "John Doe^Male^20";
int last = 0;
int cPos = -1;
while ((cPos = str.find('^', cPos + 1)) != string::npos)
{
string sub = str.substr(last, cPos - last);
// Do something with the string
last = cPos + 1;
}
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "This is a sample string";
char * pch;
printf ("Looking for the 's' character in \"%s\"...\n",str);
pch=strchr(str,'s');
while (pch!=NULL)
{
printf ("found at %d\n",pch-str+1);
pch=strchr(pch+1,'s');
}
return 0;
}
Do something like this in an array.
You have a number of choices but I would use strtok(), myself. It would make short work of this.