c++ String returning with an extra char - c++

I have tested my program and am certain right before being returned the string in my function equals "card001". But the returned value equals "card0011". I have no idea how this even happens. Help me before I lose my mind. ;)
std::string function_cardTexture(int card) {
//removes the last 1
card = card - 10000;
int ctr = 0;
card = floor(card / 10);
std::cout << card << std::endl;
//turn int card into a string
std::string a = static_cast<std::ostringstream*>(&(std::ostringstream() << card))->str();
//combines card and string a into one string
std::string nametext = "card00" + a;
std::cout << nametext << std::endl;
return (nametext);
}
void function_Battle(tempPlayer &Player, tempCard &card001) {
if (Player.Start == true) {
//Draw hand
for (int i = 0; i < Player.numDrawn; i++) {
int x = rand() % Player.deckSize + 0; ;
Player.Hand[i] = Player.Deck[x];
Player.Discarded[x] = 1;
}
Player.Start = false;
}
std::map<std::string, tempCard> Vars;
//draw hand
for (int i = 0; i < Player.handMax;i++) {
if (Player.Hand[i] != 0) {
sf::RectangleShape Card(sf::Vector2f(80.0f, 128.0f));
std::string nametext = function_cardTexture(Player.Hand[i]);
std::cout << nametext;
sf::Texture texture = Vars[nametext].Art;
Card.setTexture(&texture);
window.draw(Card);
}
}
}

Your problem is how you're printing things out without a newline in the function_Battle() function, so you're likely "smashing together" your new value with an old one. If you replace your main function with just a loop with clearer printing of values, you can see you don't have a problem:
http://coliru.stacked-crooked.com/a/8d1e4f51643b84b9
That link will go to an online compiler where I just replaced the calling function with a loop that makes numbers. It even supplies a negative one.

Related

How can I add different names to a vector using classes?

#include <iostream>
#include <string>
#include <vector>
class Enemy
{
private:
std::string rank = "Boss";
std::string rank2 = "Miniboss";
public:
std::string type;
std::string get_rank(){
return rank;
}
std::string get_rank2(){
return rank2;
}
};
int add_enemy(std::vector<Enemy>&enemies, Enemy enemy) // I wanna pass by reference because I want to modify the vector
{
for(size_t i; i < enemies.size(); i++) {
if(enemies.at(i).type == enemy.type){ // here I'm saying, if I add an enemy that's of the same type, I don't wanna add it anymore
return 1; // it returns an error, because they are the same type, so it shouldn't add it?
}
}
enemies.push_back(enemy);
}
int main()
{
Enemy enemy;
enemy.type = "Dragon";
std::cout << enemy.type << " is a " << enemy.get_rank() << std::endl;
Enemy nrone, nrtwo, nrthree, nrfour, nrfive;
// I want to add these and keep them in a vector
std::vector<Enemy> enemies;
nrone.type = "Orc";
nrtwo.type = "Goblin";
nrthree.type = "Troll";
nrfour.type = "Ogre";
nrfive.type = "Orc";
std::cout << nrfour.type << " is of rank " << nrfour.get_rank2() << std::endl;
enemies.push_back(nrone);
enemies.push_back(nrtwo);
enemies.push_back(nrthree);
enemies.push_back(nrfour);
enemies.push_back(nrfive);
std::cout << add_enemy(enemies, enemy) << std::endl;
return 0;
}
Hi, I am studying Classes & Objects in C++ right now, and I'm trying to achieve the following: create a vector of NPC monsters and add a bunch of monster types to the vector. However, if the monster/enemy is of the same type, I don't want to add it to the vector, but discard it.
In my case, I have two Orcs, so the vector should discard one of the orcs, but it doesn't, and instead if showing me a strange number on the screen.
I tried it this way and I still can't figure it out :( Any solutions?
So the reason that both Orcs are added is because by the time you run add_enemy, you've already added them. All the enemies should be using the add_enemy function instead of push_back:
int main()
{
Enemy enemy;
enemy.type = "Dragon";
std::cout << enemy.type << " is a " << enemy.get_rank() << std::endl;
Enemy nrone, nrtwo, nrthree, nrfour, nrfive;
// I want to add these and keep them in a vector
std::vector<Enemy> enemies;
nrone.type = "Orc";
nrtwo.type = "Goblin";
nrthree.type = "Troll";
nrfour.type = "Ogre";
nrfive.type = "Orc";
std::cout << nrfour.type << " is of rank " << nrfour.get_rank2() << std::endl;
enemies.push_back(nrone); //Add one Orc
enemies.push_back(nrtwo);
enemies.push_back(nrthree);
enemies.push_back(nrfour);
enemies.push_back(nrfive); //Add another Orc
std::cout << add_enemy(enemies, enemy) << std::endl; //The Orcs are already in enemies!
return 0;
}
The reason you're seeing a strange number on the screen is that if you DO successfully add an enemy, the function doesn't return anything:
int add_enemy(std::vector<Enemy>&enemies, Enemy enemy) // I wanna pass by reference because I want to modify the vector
{
for(size_t i; i < enemies.size(); i++) {
if(enemies.at(i).type == enemy.type){
return 1; // Return an error
}
}
enemies.push_back(enemy); //OK, so we added the enemy, but where's the return?
}
Your add_enemies function must return a value, since it is declared as type int.
P.S... consider using a range based loop to make things a little easier:
for(Enemy& existingEnemy: enemies) {
if(enemy.type == existingEnemy.type) {
return 1;
}
}
The main problem is that you are not initializing the loop variable (i) in your add_enemy function (so the loop may never run, or it may skip some elements). Also, that function must return a value (presumably, 0) if the loop ends.
Try this:
int add_enemy(std::vector<Enemy>& enemies, Enemy enemy) // I wanna pass by reference because I want to modify the vector
{
for (size_t i = 0; i < enemies.size(); i++) { /// You forgot to initialize "i"!
if (enemies.at(i).type == enemy.type) { // here I'm saying, if I add an enemy that's of the same type, I don't wanna add it anymore
return 1; // it returns an error, because they are the same type, so it shouldn't add it?
}
}
enemies.push_back(enemy);
return 0; // The function MUST return an int value!
}
The strange number is easily explained. In your function you fail to return anything in the case where you do add the enemy. Add a return value and the strange number will go away.
int add_enemy(std::vector<Enemy>&enemies, Enemy enemy)
{
for(size_t i = 0; i < enemies.size(); i++) {
if(enemies.at(i).type == enemy.type){
return 1;
}
}
enemies.push_back(enemy);
return 0; // added a return value
}
The second problem with two orcs is also easily explained. You didn't use your add_enemy function when you added the orcs, you just used the regular vector push_back method so both orcs got added to the vector. You only used your add_enemy method for the dragon.
Also you fail to initialise i in the loop. I didn't spot that but I've corrected the code above.

Return struct element from vector c++

I'm new to C++ and I'm trying to return a struct from a vector of structs by using 2 search criteria.
The function find_city is returning me everything from the defined range, regardless of whether it exists inside the vector of struct.
Here's my code:
struct cityLoc
{
int hRange;
int vRange;
int cityCode;
string cityName;
};
vector<cityLoc> cl1;
// the vector has already been preloaded with data
// function to return my struct from the vector
cityLoc find_city(int hRange, int vRange)
{
for (size_t i = 0; i < cl1.size(); i++)
{
if ((cl1[i].hRange = hRange) && (cl1[i].vRange = vRange))
{
return cl1[i];
}
}
}
int main()
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j <= 8; j++)
{
cityLoc this_city;
this_city = find_city(i, j);
cout << this_city.hRange << ", " << this_city.vRange << endl;
}
}
return 0;
}
Also, aside from this question, I was previously looking into std::find_if and didn't understand it. If I have the following code, what is the output? How do I modify it such that it returns a struct?
auto it = find_if(cl1.begin(), cl1.end(), [](cityLoc& cl) { return cl.hRange == 1; } );
You have a bug here:
if ((cl1[i].hRange = hRange) && (cl1[i].vRange = vRange))
Those = are assignments, not comparisons! Please enable compiler warnings and you won't be hurt by such obvious typos in future.
std::find_if will return the iterator to the found struct entry if it is successful, std::vector::end() otherwise. So, you should first validate the returning iterator if it is valid or not.
For example:
auto it = std::find_if( cl1.begin(), cl1.end(),
[](const cityLoc& cl) { return cl.hRange == 1; } );
if ( it == cl1.end() )
{
// ERROR: Not found! Return error code etc.
return -1;
}
// And, if found, process it here...
std::cout << it->hRange << '\n';
std::cout << it->vRange << '\n';
The criteria (predicate) part in std::find_if is a lambda expression.

C++ Calculating Shortest Path in a Directed Graph

I am tasked with writing a program to maintain the representation of a simple network(weighted directed graph) and compute the best path between two given nodes upon request.
Currently, I am attempting to write a function to compute the simplest between two nodes, however, when attempting to run my program, I get two specific error
Severity Code Description Project File Line Suppression State
Error C3863 array type 'bool [openNode]' is not assignable P 127
and
Severity Code Description Project File Line Suppression State
Error C3863 array type 'int [openNode]' is not assignable
I am unable to debug since these two primary errors are not allowing my program to run. Is there any particular reason for these errors?
Thanks in advance!
This is the node structure defined in Graph.h
struct GraphNode
{
char ID;
std::string name;
int inNodes = 0;
int outNodes = 0;
std::vector<std::pair<GraphNode*, int>> connection;
int connections = 0;
};
And here is the particular code that causes the errors.
#include "Graph.h"
std::vector<GraphNode*> _graph;
int openNode = 0;
//Obligatory constructor
void Graph()
{
}
void shortestPath(char fromNode, char toNode)
{
bool known[openNode];
int distance[openNode];
GraphNode* previous[openNode];
int numbChecked = 0;
for (int i = 0; i < openNode; i++)
{
known[i] = false;
distance[i] = 999999;
previous[i] = nullptr;
}
distance[findNode(fromNode)] = 0;
while (numbChecked < openNode)
{
int smallestUnknown = 9999999;
int locationOfSmall = 0;
for (int i = 0; i < openNode; i++)
{
if (known[i] == false && distance[i] < smallestUnknown)
{
smallestUnknown = distance[i];
locationOfSmall = i;
}
}
if (distance[locationOfSmall] == 0)
{
previous[locationOfSmall] = nullptr;
}
known[locationOfSmall] = true;
numbChecked++;
if (_graph[locationOfSmall]->outNodes > 0)
{
for (int i = 0; i < _graph[locationOfSmall]->outNodes; i++)
{
int newDistanceLocation = findNode(_graph[locationOfSmall]->connection[i].first->ID);
if (known[newDistanceLocation] == false && (distance[locationOfSmall] + _graph[locationOfSmall]->connection[i].second) < distance[newDistanceLocation])
{
distance[newDistanceLocation] = distance[locationOfSmall] + _graph[locationOfSmall]->connection[i].second;
previous[newDistanceLocation] = _graph[locationOfSmall];
}
}
}
}
int destination = findNode(toNode);
std::string output;
std::string charTransfer;
charTransfer = toNode;
output = charTransfer;
while (previous[destination] != nullptr)
{
destination = findNode(previous[destination]->ID);
charTransfer = _graph[destination]->ID;
output = charTransfer + "->" + output;
}
if (_graph[destination]->ID != fromNode)
{
std::cout << "The nodes are not connected." << std::endl;
}
else
{
std::cout << "The path is: " << output << std::endl;
std::cout << "The distance is: " << distance[findNode(toNode)] << std::endl;
}
}
Any change suggestions would be much appreciated!
You have invalid code at the beginning of your shortestPath function:
bool known[openNode];
int distance[openNode];
GraphNode* previous[openNode];
You cannot use variables to create arrays on the stack (which is what you are trying to do there), because the compiler doesn't know the value of openNode at compile time (which is needed to determine the stack size).
Why don't you use a vector, like:
std::vector<bool> known(openNode, false);
std::vector<int> distance(openNode, 999999);
std::vector<GraphNode*> previous(openNode, nullptr);
Using this method makes the for loop below obsolete aswell.

How to create and increase the size of an array at runtime in C++

I want to create an array whose size I will only know at runtime, and then further increase that size during execution of the program.
This is from an /r/dailyprogrammer challenge which can be found here https://www.reddit.com/r/dailyprogrammer/comments/3twuwf/20151123_challenge_242_easy_funny_plant/
MSVisual gives me the error std::badd_array_new_length which means that it's having trouble instantiating the array?
I'm so tired with oftentimes copying code letter for letter from websites where it works and I constantly get errors. Is Visual a bad platform for learning C++? Should I try QT?
#include <iostream>
#include <string>
void main(int argc, char* argv[]) {
int currentPlants = std::stoi(argv[2]), targetPeople = std::stoi(argv[1]), currentProduce = 0, week = 0;
int * plants;
plants = new int[currentPlants];
for (int i = 0; i < currentPlants; i++) {
plants[i] = 0;
}
if (plants == nullptr) EXIT_FAILURE;
while (currentProduce < targetPeople) {
currentProduce = 0;
for (int i = 0; i < currentPlants; i++) {
currentProduce += plants[i];
plants[i]++;
}
if (currentProduce >= targetPeople) break;
else {
plants = new int[currentProduce];
for (; currentPlants < currentProduce; currentPlants++) {
plants[currentPlants] = 0;
}
}
week++;
}
std::cout << week;
}
You should use an std::vector.
As a summary :
// Create an array of size 10
std::vector<int> my_vector(10);
// Add '3' to my_vector
my_vector.push_back(3);
// Remove the last element
my_vector.pop_back();
Explanation and example here : www.cplusplus.com/reference/vector/vector/
Edit : you don't need to specify the array size when you construct your object.
// Create an array
std::vector<int> my_vector;
You can't increase the size of an array at runtime. You can create a new bigger array, and copy the contents of the old array to the new array.
The problem with your code is that on the first pass through plants all of your plants[x] are zero. You add all of these together and get zero => currentProduce == 0. You then try to new plants[currentProduce aka 0] which is illegal.
Your second problem is that each time you new you create a new array discarding the old values; new creates a new array, it doesn't know anything about the old one.
I rewrote your code using std::vector, which fixes the crash but produces an endless loop because on the first pass, currentProduce comes out to zero so the array is truncated.
#include <iostream>
#include <string>
#include <vector>
int main(int argc, const char* argv_real[])
{
const char* argv[] = { "programname", "5", "25" };
int currentPlants = std::stoi(argv[2]), targetPeople = std::stoi(argv[1]), currentProduce = 0, week = 0;
std::cout << "targetPeople = " << targetPeople
<< ", currentPlants = " << currentPlants
<< "\n";
std::vector<int> plants;
// Option 1:
// plants.resize(currentPlants);
// Option 2:
for (auto i = 0; i < currentPlants; ++i) {
plants.push_back(0);
}
while (currentProduce < targetPeople) {
std::cout << "cp: " << currentProduce
<< ", tp: " << targetPeople
<< "\n";
currentProduce = 0;
// plantCount is a reference to plants[i] for each i
for (auto& plantCount : plants) {
std::cout << plantCount << ", ";
currentProduce += plantCount;
plantCount++;
}
std::cout << " cp: " << currentProduce << "\n";
if (currentProduce >= targetPeople)
break;
// Option 1:
plants.resize(currentProduce);
// Option 2:
// while (currentPlants < currentProduce) {
// plants.push_back(0);
// }
week++;
}
std::cout << week;
}
Live demo: http://ideone.com/xGpoF6
Outside of using std::vector, you would need to allocate a new array on the heap, copy the contents over, and delete the old one. Then point your int* to the newly allocated array.
This wouldn't technically change the array size, but those accessing the object would see it as though it was changing.
This is dangerous:
int * plants;
plants = new int[currentPlants];
for (int i = 0; i < currentPlants; i++) {
plants[i] = 0;
}
if (plants == nullptr) EXIT_FAILURE;
This is what happens (if you are lucky):
the program attempts to create some memory and returns nullptr if it can't
the program then uses the memory in a loop even if nullptr was returned. (If nullptr was returned this will crash the program, silently corrupt the memory so you get the wrong results or otherwise doing something you don't want)
the program then checks to see if nullptr was returned.
If you are unlucky the compiler does time travel and destroys the entire universe. I am not kidding, have a look at:
https://blogs.msdn.microsoft.com/oldnewthing/20140627-00/?p=633
Undefined behavior causing time travel

C++ Returning results from several threads into an array

I've a pattern-matching program which takes as input a string and returns a string closely matched by a dictionary. Since the algorithm takes several seconds to run one match query, I am attempting to use multi-threading to run batch queries.
I first read in a file containing a list of queries and for each query dispatch a new thread to perform the matching algorithm, returning the results into an array using pthread_join.
However, I'm getting some inconsistent results. For example, if my query file contains the terms "red, green, blue", I may receive "red, green, green" as the result. Another run may generate the correct "red, green, blue" result. It appears to sometimes be writing over the result in the array, but why would this happen since the array value is set according to the thread id?
Dictionary dict; // global, which performs the matching algorithm
void *match_worker(void *arg) {
char* temp = (char *)arg;
string strTemp(temp);
string result = dict.match(strTemp);
return (void *)(result.c_str());
}
void run(const string& queryFilename) {
// read in query file
vector<string> queries;
ifstream inquery(queryFilename.c_str());
string line;
while (getline(inquery, line)) {
queries.push_back(line);
}
inquery.close();
pthread_t threads[queries.size()];
void *results[queries.size()];
int rc;
size_t i;
for (i = 0; i < queries.size(); i++) {
rc = pthread_create(&threads[i], NULL, match_worker, (void *)(queries[i].c_str()));
if (rc) {
cout << "Failed pthread_create" << endl;
exit(1);
}
}
for (i = 0; i < queries.size(); i++) {
rc = pthread_join(threads[i], &results[i]);
if (rc) {
cout << "Failed pthread_join" << endl;
exit(1);
}
}
for (i = 0; i < queries.size(); i++) {
cout << (char *)results[i] << endl;
}
}
int main(int argc, char* argv[]) {
string queryFilename = arg[1];
dict.init();
run(queryFilename);
return 0;
}
Edit: As suggested by Zac, I modified the thread to explicitly put the result on the heap:
void *match_worker(void *arg) {
char* temp = (char *)arg;
string strTemp(temp);
int numResults = 1;
cout << "perform match for " << strTemp << endl;
string result = dict.match(strTemp, numResults);
string* tmpResult = new string(result);
return (void *)((*tmpResult).c_str());
}
Although, in this case, where would I put the delete calls? If I try putting the following at the end of the run() function it gives an invalid pointer error.
for (i = 0; i < queries.size(); i++) {
delete (char*)results[i];
}
Without debugging it, my guess is that it has something to do with the following:
void *match_worker(void *arg)
{
char* temp = (char *)arg;
string strTemp(temp);
string result = dict.match(strTemp); // create an automatic
return (void *)(result.c_str()); // return the automatic ... but it gets destructed right after this!
}
So when the next thread runs, it writes over the same memory location you are pointing to (by chance), and you are inserting the same value twice (not writing over it).
You should put the result on the heap to ensure it does not get destroyed between the time your thread exits and you store it in your main thread.
With your edit, you are trying to mix things up a bit too much. I've fixed it below:
void *match_worker(void *arg)
{
char* temp = (char *)arg;
string strTemp(temp);
int numResults = 1;
cout << "perform match for " << strTemp << endl;
string result = dict.match(strTemp, numResults);
string* tmpResult = new string(result);
return (void *)(tmpResult); // just return the pointer to the std::string object
}
Declare results as
// this shouldn't compile
//void* results[queries.size()];
std::string** results = new std::string[queries.size()];
for (int i = 0; i < queries.size(); ++i)
{
results[i] = NULL; // initialize pointers in the array
}
When you clean up the memory:
for (i = 0; i < queries.size(); i++)
{
delete results[i];
}
delete [] results; // delete the results array
That said, you would have a much easier time if you used the C++11 threading templates instead of mixing the C pthread library and C++.
The problem is caused by the lifetime of the local variable result and the data returned by the member function result.c_str(). You make this task unnecessary difficult by mixing C with C++. Consider using C++11 and its threading library. It makes the task much easier:
std::string match_worker(const std::string& query);
void run(const std::vector<std::string>& queries)
{
std::vector<std::future<std::string>> results;
results.reserve(queries.size());
for (auto& query : queries)
results.emplace_back(
std::async(std::launch::async, match_worker, query));
for (auto& result : results)
std::cout << result.get() << '\n';
}