C++ Strings In Class Becoming Empty after Construction - c++

I'm creating a program where part of its job is to store class objects labeled Client() in a binary tree.
I create the object within a switch statement with
Client newClient = Client (first, last, iD);
transactionsTree.Insert(newClient);
The switch statement is in a loop that is reading data, so after this case is executed and the program continues, the strings within that class get set to empty "" strings. I found this out in stepping through debugging and as soon as that case block executes the strings change to empty. Any other data that gets put into that class remains but those strings will not. Even if I declare those string names in the Client.h file they are still empty after the switch case where it was created. The code where I create the newClient shown above is in a Transactions.cpp, the transactionsTree is a class object of BSTree.cpp, and there's also Client.cpp, all these classes share a connection but I'm assuming my problem has to do with how I'm inserting the objects into the binary tree.
Here is the code with the switch statement case:
case 'O': // open an account
{
string first = list.front();
list.pop();
string last = list.front();
list.pop();
stringstream getiD(list.front()); // transfer string to int
list.pop();
int iD = 0;
getiD >> iD; // transferring string to int
if (transactionsTree.Retrieve(iD)) // if Client is already in tree, prints error message
{
cout << "ERROR: Account " << iD << " is already open. Transaction refused." << endl;
}
else // else creates new Client
{
Client newClient = Client (first, last, iD);
transactionsTree.Insert(newClient);
}
break;
}
And here is my insert method for the binary tree:
void BSTree::Insert(Client &newClient)
{
if (isEmpty())
{
Node *newNode = new Node(newClient);
this->root = newNode;
}
else
add(this->root, newClient);
}
BSTree::Node* BSTree::add(Node *node, Client &newClient) // helper function for Insert()
{
if (node == nullptr)
{
Node *newNode = new Node(newClient);
return newNode;
}
if (newClient.clientID < node->pClient->clientID)
node->left = add(node->left, newClient);
else
node->right = add(node->right, newClient);
}
edit1: Upon further examination, none of the strings in the class that are declared in the header or constructor hold, although here are string vectors that hold. I also have an array of strings with the whole array declared in the header of Client.cpp but when I try and print out any strings from any Client object it only prints out an address.
edit2: I've isolated my problem to two areas, one where I try to access the Client within the tree using:
Client *ptrClient; // create pointer to access the Client once found
ptrClient = &transactionsTree.getClient(iD);
and two within my getClient method which is within my binary tree class:
Client& BSTree::getClient(int id) // returns a Client object from the tree to process() in Transactions.cpp
{
return getTheClient(this->root, id);
}
Client& BSTree::getTheClient(Node * node, int iD) // helper function for getClient that returns a Client object in the tree
{
// no need for the if condition of iD not being found because I check if the iD is in the tree before this function is executed
if (node->pClient->clientID == iD)
{
cout << node->pClient->firstName << " PRINTED HERE~~~~~~~~~~~~~" << endl;
return *node->pClient; // return client if found
}
if (iD < node->pClient->clientID)
return getTheClient(node->left, iD);
else
return getTheClient(node->right, iD);
}
Does this updated information help you help me solve my problem?

I solved my problem, it was with the two lines:
Client newClient = Client (first, last, iD);
transactionsTree.Insert(newClient);
I changed it to:
Client *newClient = new Client (first, last, iD);
transactionsTree.Insert(*newClient);
This mattered because I was creating a new object in the stack and not the heap.

Related

Creating A Client Connect Log-How To Change Code For Last Connect

This is the standard routine found all over the internet for
obtaining the IP/MAC address of an connected client. It works.
What I can't figure out is how to get only the last MAC to access to keep an access log.
I don't want a repeat of every connect, each time there's a new connect.
I can't find docs on STAILQ_NEXT, so I don't know what it is doing.
Help appreciated.
unsigned char number_client;
struct station_info *stat_info;
// struct ip_addr *IPaddress;
struct ip4_addr *IPaddress;
IPAddress address;
int i=1;
number_client= wifi_softap_get_station_num();
stat_info = wifi_softap_get_station_info();
Serial.print(" Total Connected Clients are = ");
Serial.println(number_client);
while (stat_info != NULL) {
IPaddress = &stat_info->ip;
address = IPaddress->addr;
Serial.print(stat_info->bssid[0],HEX);Serial.print(':');
Serial.print(stat_info->bssid[1],HEX);Serial.print(':');
Serial.print(stat_info->bssid[2],HEX);Serial.print(':');
Serial.print(stat_info->bssid[3],HEX);Serial.print(':');
Serial.print(stat_info->bssid[4],HEX);Serial.print(':');
Serial.print(stat_info->bssid[5],HEX);Serial.print(' ');
stat_info = STAILQ_NEXT(stat_info, next);
i++;
Serial.println();
}
delay(500);
}```
================================
Thanks Majenko. This gives me the MAC, but if I got the rest of the code correct, this is always giving me the last MAC to connect, rather than the last MAC to access the page. If there are 3 connected A, B, C and A refreshes, the log shows C. Not sure if the list if FIFO or LIFO or FILO or ??? or there's something else I am missing. Maybe I am looking at the wrong variable or ???
```void clientMAC(){
struct station_info *scan = wifi_softap_get_station_info();
byte MAClast[5];
if (scan != NULL) { // Check there is at least one entry
while (STAILQ_NEXT(scan, next) != NULL) {
scan = STAILQ_NEXT(scan, next);
}
// scan now points to the last entry
Serial.print(scan->bssid[0],HEX);Serial.print(':');
Serial.print(scan->bssid[1],HEX);Serial.print(':');
Serial.print(scan->bssid[2],HEX);Serial.print(':');
Serial.print(scan->bssid[3],HEX);Serial.print(':');
Serial.print(scan->bssid[4],HEX);Serial.print(':');
Serial.print(scan->bssid[5],HEX);Serial.print(' ');
}else { // We have no entries
}
}
```
stat_info is a simple linked list of type struct station_info *, with a predefined structure imposed by the SDK. Here's the full chain of implementation:
struct station_info {
STAILQ_ENTRY(station_info) next;
uint8 bssid[6];
struct ipv4_addr ip;
};
The STAILQ_ENTRY(station_info) next macro expands to:
struct {
struct station_info *stqe_next; /* next element */
} next;
So you have a linked list that is based around stat_info->next.stqe_next.
The macro STAILQ_NEXT(stat_info, next) just wraps that in a bit of abstraction to make iterating easier. It expands out to ((stat_info)->next.stqe_next.
To get the last element of a linked list you need to iterate through the list until ->next.stqe_next is null, at which point you know you are at the end of the list. For example:
struct station_info *scan = wifi_softap_get_station_info();
if (scan != NULL) { // Check there is at least one entry
while (STAILQ_NEXT(scan, next) != NULL) {
scan = STAILQ_NEXT(scan, next);
}
// scan now points to the last entry
} else {
// We have no entries
}

how to check if personID is in my_customers (see my example)

In C++, the interface for this file says
*If no soup left returns OUT_OF_SOUP
* If personID not found in my_customers AND numbBowlsSoupLeft>0 then give this person a bowl of soup (return BOWL_OF_SOUP)
* and record it by creating new customer struct using personID, numbBowlsSoup=1 and adding this struct to my_customers, be sure to decrement numbBowlsSoupLeft.
for my implementation, I'm trying to put
int Soupline::getSoup(int personID) {
if (numBowlsSoupLeft == 0) {
return OUT_OF_SOUP;
}
if (!(personID : my_customers) && numbBowlsSoupLeft > 0) {
}
But that second if statement is giving me syntax errros, I just want to know how to check to see if the personID is IN my_customers?
my_customers was created in the soupline interface using:
std::vector<customer> my_customers; // keeps track of customers
First you want to use find() to search a vector.
Second, please handle the case if numbBowlsSoupLeft < 0, because that can be a huge source of problem.
Third, your syntax error is the (personID : my_customers), the : is for iteration.
int Soupline::getSoup(int personID) {
if (numBowlsSoupLeft <= 0) { // handles negative numBowlsSoupLeft
return OUT_OF_SOUP;
}
bool found_customer = false;
for (auto c : my_customers) {
if (personID == c.person_id()) { // This is my guess on how the id is stored in customer class
// Logic to process soup for customer
found_customer = true;
break;
}
}
if (!found_customer) {
// Logic to process non-customer asking for soup?
}
}
Sorry i dunno what is the return integer is supposed to be, so it is not defined in my code example.

Trouble inserting BST node into a List node

I'm creating a customer loyalty program type code using a Linked list and BST's. It uses a list of loyalty programs, each node containing a BST of customer ID's. Currently I am attempting to create a function that searches the list for a loyalty program, once found (creates if not) adds the customer ID into the BST of that node. However when testing, im running into a reading violation on the insert new list node (insert_at_front) function.
Any help would be greatly appreciated!
Ive tried altering the function type of the find_list function and creating wrapper functions for it as I have previously done with similar functions for BST's, but I keep getting lost in the code and it seems to break it more.
list.h header file:
typedef struct listNode {
char* name; //Name of company
BST *customer; //Tree of customer ID's
struct listNode *next; //Pointer for next compnay
} *ListNodePtr;
void option_insert(List *self) {
char* input_loyalty;
int input_ID;
printf("What loyalty program do you wish to add a customer to? \n");
scanf("%s", &input_loyalty);
printf("What is the customer ID \n");
scanf("%d", &input_ID);
find_list(self, input_loyalty, input_ID);
}
void find_list(List *self, char* data, int ID) {
ListNodePtr current = self->head;
if (current != NULL) {
if (current->name == data) {
insert_bst(self->head->customer, ID);
}
else {
current = current->next;
}
}
else {
insert_at_front(self, data);
insert_bst(self->head->customer, ID);
}
}
void insert_at_front(List *self, char* data) {
int n = strlen(data);
ListNodePtr new_node = malloc(n * sizeof(char*));
strcpy(new_node->name, data);
new_node->next = self->head;
self->head = new_node;
}
I have included the functions being utilised in the problem but note that they are separated in different .c files. (however this should cause no difference) and I can certainly provide more code if needed
The answer is probably in your use of malloc(). You are creating memory based off the size of data, and not the size of a struct.
I should also mention that if you are using C++ (and not C) it is probably better to learn how to use the new keyword instead.
Anyway, if you still decide to use malloc, try this instead:
void insert_at_front(List *self, char* data) {
int n = strlen(data);
ListNodePtr new_node = malloc(sizeof(listNode)); // note, we're using the size of a node instead
new_node->name = malloc(n * sizeof(char)); // now, we need to allocate the string too.
strlcpy(new_node->name, data, n); // if you want to use a "secure" copy
new_node->next = self->head;
self->head = new_node;
}

How do I cycle through a linked list to reduce a value?

I have a class called SensorNode, which contains (among other things) a linked list of sensor objects. The node has a data member for the amount of battery power it has left, and the sensors each have a data member for how much power they draw. I have a function called processTimeClick that is supposed to go through the entire linked list of sensors in the node, and subtract the amount of power that they use from the battery that the node has left. Unfortunately I get an "Error, bad access code" and I don't know why. Here's the function I have, I was hoping someone could see where my logic is wrong.
void SensorNode::processTimeClick() {
if (batt == 0) {
}
else {
temp = mySensors;
do {
if (batt <=0) {
cout << "\nThis node has run out of battery\n";
func = 0;
break;
}
batt = (batt - (temp->SensEl->getPC()));
temp = temp->LLelement;
} while (temp->LLelement != NULL); //My code stops here and says "Thread 1:EXC_BAD_ACCESS (code=1, address=0x0)
}
}
to make it easier to understand:
temp and mySensors are both pointers (declared in the SensorNode class) of type "SensorBlock" (which is the linked list object). batt is a float data member in the SnesorNode class.
Here's the declaration for the SensorBlock class:
class SensorBlock {
friend class SensorNode;
SensorBlock * LLelement;
sensor * SensEl;
SensorBlock(sensor* senspoint);
};
SensorBlock::SensorBlock(sensor* senspoint) {
SensEl = senspoint;
LLelement = NULL;
}
Thanks for the help!
I think you want your loop to look more like this:
while (temp) {
if (batt <=0) {
cout << "\nThis node has run out of battery\n";
func = 0;
break;
}
batt = (batt - (temp->SensEl->getPC()));
temp = temp->LLelement;
}
This way, temp is checked to make sure it isn't null before you try to use it.
If you have a loop like this:
do {
// use temp
temp = temp->LLelement;
} while (temp->LLelement);
it is equivalent to
beginning_of_loop:
// use temp -- oops it might be null!
temp = temp->LLelement;
// temp might be null here
if (temp->LLelement) goto beginning_of_loop;
If you put the while at the top it is equivalent to this:
beginning_of_loop:
if (!temp) goto end_of_loop:
// use temp -- can't be null
temp = temp->LLelement;
// temp might be null here, but we aren't using it
goto beginning_of_loop;
end_of_loop:

Member variables of a object get overridden when creating another object in the object

I have a memory issue with a class of mine. The issue occurs when I create an object in a member function of a class. It is about the class below. I removed the member functions because they aren’t necessary:
class User
{
private:
bool locked;
bool active;
std::vector<City> * userCitys;
UserData userData;
Credentials credentials;
The problem occurs when I call this function:
int User::addCity(CityData cityData)
{
lockUserObject(); //Everything is fine here
City cityToAdd; //When this object is created, the memory of userCitys will get overridden
cityToAdd.activate();
userCitys->push_back(cityToAdd);
int cityID = userCitys->size() - 1;
userCitys->at(cityID).editCityData(cityData);
unlockUserObject();
return cityID;
}
In the first place I created userCitys on the stack. For test purpose I placed it on the Heap. The address of userCitys get overridden by some data. I can’t find the problem. the City is just a basic class:
Part of the header:
class City
{
private:
bool active;
Supplies supplies;
std::vector<Building> buildings;
std::vector<Company> companies;
std::vector<Share> shares;
std::vector<Troop> troops;
CityData cityData;
Constructor:
City::City()
{
active = false;
}
How is it possible that userCitys get overridden? This all happens on a single Thread so that can’t be a problem. I tried a lot of thing, but I can’t get it to work. What is the best approach to find the problem?
Edit:
Lock function:
void User::lockUserObject()
{
for( int i = 0; locked ; i++)
{
crossSleep(Settings::userLockSleepInterval);
if( i >= Settings::userLockMaxTimes )
Error::addError("User lock is over userLockMaxTimes",2);
}
locked = true;
}
I call the code here (Test function):
City * addCity(User * user)
{
Location location;
location.x = 0;
location.y = 1;
CityData citydata;
citydata.location = location;
citydata.villagers = 0;
citydata.cityName = "test city";
int cityID = user->addCity(citydata); //addCity is called here
City * city = user->cityAction(cityID);;
if( city == NULL)
Error::addError("Could not create a city",2);
return city;
}
The add user (Test code):
User * addUser()
{
UserData test;
test.name = "testtest";
Credentials testc("testtest",3);
//Create object user
int userID = UserControle::addUser(test,testc);
User * user = UserControle::UserAction(userID);
if( user == NULL)
Error::addError("Could not create a user",2);
return user;
}
My test function:
void testCode()
{
User * user = addUser();
City * city = addCity(user);
}
This function in called in main:
int main()
{
testCode();
return 0;
}
Here are UserAction and addUser in UserControle:
int UserControle::addUser(UserData userdata, Credentials credentials)
{
int insertID = -1;
for( int i = 0; i < (int)UserControle::users.size(); i++)
{
if( !UserControle::users.at(i).isActive() )
{
insertID = i;
break;
}
}
User userToInsert(userdata,credentials);
if( insertID != -1 )
{
UserControle::users.insert( UserControle::users.begin() + insertID,userToInsert);
return insertID;
}
else
{
UserControle::users.push_back(userToInsert);
return UserControle::users.size() - 1;
}
}
User* UserControle::UserAction(int userID) //check all indexes if greater then 0!
{
if( (int)UserControle::users.size() <= userID )
{
Error::addError("UserAction is out of range",3);
return NULL;
}
if( !UserControle::users.at(userID).isActive())
{
Error::addError("UserAction, the user is not active.",3);
return NULL;
}
return &UserControle::users[userID];
}
There's a few things you could try:
Remove code until the fault goes away. In other words, distill a minimal example from your code. I guess you'll then see the error yourself, otherwise post that small example program here and others will.
Don't use raw pointers. The question with those is always who owns what they point to. Use smart pointers instead, e.g. unique_ptr (C++11) or auto_ptr (C++98) for exclusive ownership.
If you have pointer members like "userCities", you need to think about what happens when copying instances of that class (you already wrote a proper destructor, or?). So, either prevent copying (make copy-constructor and assignment operator private and without implementing it) or implement them in a way that the vectors are properly cloned and not shared between different instances.
Don't use C-style casts. If those are necessary to get anything through the compiler, the code is probably broken.