Keep a state when parsing text - c++

I'm trying to make a program that looks for syntax and everytime it goes from state to state
It needs to indicate that state. I'm getting different output that I shouldn't have got.
using namespace cppfsm;
#include <vector>
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
using std::vector;
int cppfsm::updateState(int& state, char c) {
const int state1 = 1;
const int state2 = 2;
switch (state) {
case state1:
if (c == '/')
cout << "1" << endl;
// do stuff; update state
else if (c == '"')
cout << "1" << endl;
// do something else; update state
case state2:
if (c == '/')
cout << "1" << endl;
// do stuff; update state
else if (c == '"')
cout << "1" << endl;
// do something else; update state
}
return 0;
}
void testFSM(string s) {
vector<int> stlist; // list of states.
int cstate = start;
for (unsigned long i = 0; i < s.length(); i++) {
stlist.push_back(updateState(cstate,s[i]));
}
// push the last state:
stlist.push_back(cstate);
cout << s << endl;
for (unsigned long i = 0; i < stlist.size(); i++) {
cout << stlist[i];
}
cout << endl;
}
int main() {
// the finite state machine:
string input;
while(getline(cin,input)) {
cout << " ";
testFSM(input);
}
return 0;
}
the output should be looking like this.
the numbers are the states when going from 1 to another
$ echo "int x; // holds stuff" | ./fsm
int x; // holds stuff
0111010042222222222222
$ echo 'cout << "some string";' | ./fsm
cout << "some string";
01111000033333333333300
$ echo 'cout << "\"escape\" chars are fun";' | ./fsm
cout << "\"escape\" chars are fun";
011110000353333333533333333333333300
But my output comes out to be all 0000......s. How do I fix this problem?

If you're wondering why stlist is all 0's, take a look at the return statement for updateState:
return 0;
}
Compare this with your code for populating stlist:
stlist.push_back(updateState(cstate,s[i]));
As far as I can tell, all 0's is the correct behavior of this code. Obviously, this is not the expected or logical behavior, so I suggest changing updateState:
int cppfsm::updateState(int& state, char c) {
// ...
return state;
}
Now when you run the code stlist should contain each state change as intended.

It looks like you aleays call updateState with the same value, start. That value ist not handled in the switch, so the function returns zero. This means tha you just keep appending zeros to the stlist vector.
Try handling the start state in the switch, and the return value of the updateState function should be assigned to the cstate variable.

Your code never checks you start state:
switch (state) {
case state1: /* ... */
case state2: /* ... */
case start : /* ... */
}

Related

Parsing HTTP data in C using MCU

I am trying to parse the data obtained from GET / POST request using C in a MCU based project. I must say upfront that I haven't work with c and c++ for some time, so any suggestion is welcome.
So, the data arriving the MCU has the following markup:
HTTP/1.1
Authorization: Basic blablah
Content-Type: application/json
{
redLedBrightness:50,
redLedIsOn:true,
greenLedBrightness:70,
greenLedIsOn:false,
}
where the end beginnning of the lines are given respectively by \r and \n.
My approach entailed processing line by line, and searching the corresponding key (e.g. Authorization or redLedBrightness) and its value (e.g. blahblah or 50). I wrote the following code, which seemed to be working fine in the compiler I was using, but not in the MCU.
One of problems seems to be in the statement *tempInDataP = *index; since the MCU stops hanging if I comment it out. Of course I need this line, but I cannot figure out where the problem(s) is (are). I suspect the compiler I am using is not showing all the errors.
Here is an adaption of the code:
#include <iostream>
#include <string>
#include <cstring>
#define IN_DATA_SIZE 100
#define TEMP_IN_DATA_SIZE 10
using namespace std;
char mock[] = "Authentication:YERL90,\r\nredLedBri:400,\r\nredLedOn:true\r\n";
char * mockP = mock;
char inData[IN_DATA_SIZE];
char * inDataP = inData;
char tempInData[TEMP_IN_DATA_SIZE];
char * tempInDataP = tempInData;
const char * auth = "YERL90";
bool isAuthenticated = false;
void printBuffer(char * buf) {
for (char *p = buf; *p; p++) {
cout << *p;
}
}
void resetBuffer(char * buf, int _size)
{
memset(buf, 0, _size);
}
/**
* Returns true if keyWord exists and update the variable tempInData
* with the response / value
*/
bool parseResponse(char * res, const char * keyWord, int dataShift ) {
cout << "\nParsing:" << res << endl;
char * index;
// Reset temp in data buffer and its pointer
resetBuffer(tempInData, TEMP_IN_DATA_SIZE);
tempInDataP = &tempInData[0];
// Search for a member /keyword inside the response
index = strstr(res, keyWord);
if (index) {
// Keyword exists in the response
// Move the index to the beginning of the value (key:value)
index = index + strlen(keyWord) + dataShift;
while ((*index != '\r') && (*index != ',')) {
*tempInDataP = *index;
tempInDataP++;
index++;
}
// Terminate the string with a null
*tempInDataP = '\0';
return true;
} else {
cout << "-bul" << endl;
//Object was not found
return false;
}
}
bool checkAuth(const char * _auth) {
if (strcmp (auth, _auth) == 0)
return true;
else
return false;
}
int main()
{
while(*mockP) {
// Simulating, reading data from the channel
*inDataP=*mockP;
//Parsing line by line
if (*inDataP == '\n') {
//Check for authentication if not done yet
if(!isAuthenticated) {
cout << "Authenticating ..." << endl;
if(parseResponse(inData, "Authentication", 1)) {
cout << "Key exists ..." << endl;
if(checkAuth(tempInData)) {
cout << "Correct Password" << endl;
isAuthenticated = true;
} else {
cout << "Password Invalid" << endl;
// Prepare headers
// Send response with unauthorized access
// stop connection
break;
}
} else {
cout << "Data not found" << endl;
}
} else {
// User is logged in
cout << "User is logged in" << endl;
if(parseResponse(inData, "redLedBri", 1)) {
cout << "Data exists:" << tempInData << endl;
// update local variables
} else {
cout << "Data not found" << endl;
}
}
resetBuffer(inData, IN_DATA_SIZE);
inDataP = &inData[0];
}
else {
inDataP++;
}
mockP++;
}
//close connection and log the user out
return 0;
}
I am open for other alternatives, as this implementation seems a bit cumbersome depending on the JSON file sent to the MCU.
I see potential buffer overruns. You trust your input too much. You assume it will end with '\r' or ',' characters, and if it doesn't then you will overrun the bounds of your array(s) and access arbitrary memory.
At the very least, pass the maximum length with each array pointer, and check in each loop iteration that you NEVER access an element beyond the last address of the array.

How to reset std::count return value

std::count returns a value and I need this value to reset to 0 for all characters in the variable 'counter' after executing the inner for loop. Goal is to count how many times a character appears. If this character appears twice in the string, add one to variable 'd'. If it appears three times, add one to variable 'e'.
Not sure what else to try or if there is potentially a better function to achieve my result.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cstring>
int main() {
std::string data;
std::vector<std::string> myString;
std::vector<char> myChar;
int d = 0, e = 0;
std::ifstream inFile;
inFile.open("C:\\Users\\Administrator\\Desktop\\c++ files\\input2.txt");
if (!inFile) {
std::cout << "oops";
}
for (int i = 0; i < 1; i++) {
inFile >> data;
std::copy(data.begin(), data.end(), std::back_inserter(myChar)); //copy from string data to vector myChar via back inserter.
char counter = 'a';
for (int i = 0; i < 26; i++) {
int myCount = std::count(myChar.begin(), myChar.end(), counter);
if (myCount == 2) {
d++;
}
else if (myCount == 3) {
e++;
}
std::cout << "Counter : " << counter << " myCount : " << myCount << "\n";
counter++;
}
}
std::cout << "d is: " << d << "\n";
std::cout << "e is: " << e << "\n";
return 0;
}
input file -- https://adventofcode.com/2018/day/2
The program works correctly on first inner for loop, but second and after return values that are too high (albeit correct) for the 'myCount' variable.
std::count doesn't just give you a random value, it gives you a specific value based on the contents of the range you give it. You can't change that behaviour, not should you want to.
Instead, look at that range. Why does std::count gives values that you don't expect? They are either "too high" or they are "correct" and cannot be both; fortunately they are the latter.
This is because you repeatedly std::back_insert to the vector inside your loop. As the loop progresses, you keep counting the old characters from the last time!
If you first cleared myChar then you wouldn't have the problem. Or, ideally, bring the declaration of myChar inside the loop.
A few fixes
1) On error the program should end, not continue:
if (!inFile)
{
std::cout << "oops";
return 1;
}
2) a)myChar is accumulating all the chars of all previously read words, so it has to be cleared before use with every pass of the loop, best to move it's declaration into the block required;
b) if you're using a counter just to count but not using it, better to iterate over the data - in this case get rid of i and iterate with chars checked_char:
while (inFile >> data)
{
std::vector< char > myChar;
std::copy(data.begin(),
data.end(),
std::back_inserter(myChar)); //copy from string data to vector myChar via back inserter.
for (char checked_char = 'a'; checked_char <= 'z'; ++checked_char)
{
int myCount = std::count(myChar.begin(), myChar.end(), checked_char);
if (myCount == 2)
{
d++;
}
else if (myCount == 3)
{
e++;
}
std::cout << "Counter : " << checked_char << " myCount : " << myCount << "\n";
}
}

Reading into an Array Multiple Times

I'm having a little trouble with my code. It's pretty much supposed to open two files, and compare the first twenty line of the file "StudentAnswers.txt" [inputted as a char into a char array] against a char value in (each line of another file) "CorrectAnswers.txt" in another array at the same position (index). It's like a linear search, but the same position in the arrays. Then a report should be displayed, detailing which question the student missed, the given answer, the correct answer, and if the student passed (got >= 70%) or not, like the following:
Report for Student X:
2 (A/D), 3 (C/D), 5(D/A)
This student passed the exam!
Then it should clear the SAArray, and feed the next twenty lines from StudentAnswers.txt, and start the process all over again. I guess the program has to determine the number of students from (lines of 'StudentAnswers.txt' file / 20).
I'm having trouble displaying the report, and having the array clear itself after the program. I'm guessing this can be done with a while loop and an accumulator for the number of students (to be determined by above equation).
Also, Visual Studio seems to go to "Missed __ questions for a total of ___ %", and then keep looping -858993460.
Any help would be appreciated.
#include <iostream>
#include <fstream>
#include <string>
#include <array>
#include <algorithm>
using namespace std;
void GradeReturn(char[], char[], int, int, int);
string PassFail(float);
int main()
{
ifstream SA("StudentAnswers.txt");
ifstream CA("CorrectAnswers.txt");char CAArray[20];
char SAArray[20];
// char SA2Array[20];
bool isCorrect;
int correct;
int incorrect;
int counter;
correct = 0;incorrect = 0;
counter = 0;
cout << endl;
if (!SA.fail())
{
cout << "'StudentAnswers.txt' file opened successfully." << endl;
cout << "'CorrectAnswers.txt' file opened successfully." << endl << endl;
int a = 0;
int b = 0;
while (a < 20)
{
CA >> CAArray[a];
a++;
} // while loop to feed char into the array
while (b < 20)
{
SA >> SAArray[b];
b++;
}
} // while loop to feed char into array
CA.close(); // closing "CorrectAnswers.txt"
SA.close(); // closing "StudentAnswers.txt"
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter);
return 0;
}
void GradeReturn(char CAArray[], char SAArray[], int correct, int incorrect, int counter)
{
float percent;
float hundred;
int student;
int catcher[20];
int writeCatcher; int starter;
int catcher_size;
student = 0;
writeCatcher = 0;
catcher_size = ((sizeof catcher) / 4);
while (counter < 20)
{
if ((CAArray[counter]) == (SAArray[counter]))
{
correct++;
cout << "Good job!" << endl;
} // correct handling
else
{
incorrect++;
cout << "You got question " << counter << " wrong." << endl;
counter >> catcher[writeCatcher];
writeCatcher++;
} // incorrect handling
counter++;
} // while loop to determine if a student got a question right or wrong
static_cast <float> (incorrect); // float conversion
cout << endl; // for cleanliness
percent = ((static_cast <float> (correct)) / 20); // percentage
hundred = percent * 100;
PassFail(percent);
if (PassFail(percent) == "pass")
{
student++;
cout << "Report for Student " << student << ":" << endl;
cout << "-----------------------------" << endl;
cout << "Missed " << incorrect << " questions out of 20 for ";
cout << hundred << " % correct." << endl << endl;
starter = 0;
while (starter < (sizeof catcher)
{
if(1=1)
{
catcher_size
}
else
{
cout << "";
starter++;
}
}
}
else if (PassFail(percent) == "fail")
{
student++;
cout << "Missed " << incorrect << " questions out of 20 for ";
cout << hundred << " % correct." << endl << endl;
while (starter < catcher_size)
{
if ((catcher[starter]) == -858993460)
{
starter++;
}
else
{
cout << "";
starter++;
}
}
}
return;
}
string PassFail(float percent)
{
if (percent >= 0.70) // if <pass>
{
return "pass";
}
else // if <fail>
{
return "fail";
}
cout << endl;
}
To get a loop you should keep streams open instead of closing them after reading 20 lines.
As pseudo code that would be:
a = 0;
while(streams_not_empty)
{
CA >> CAArray[a];
SA >> SAArray[a];
++a;
if (a == 20)
{
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter);
a = 0; // Reset a
}
}
CA.close(); // closing "CorrectAnswers.txt"
SA.close(); // closing "StudentAnswers.txt"
You would also need to pass correct, incorrect, counter by reference so that the GradeReturn can change their value and their by do the accumulation.
Like:
void GradeReturn(char CAArray[], char SAArray[], int& correct, int& incorrect, int& counter)
Further you shouldn't rely on being able to read exactly Nx20 lines from the files every time. A file could have, e.g. 108 (5x20 + 8) lines, so you code should be able to handle the with only 8 lines. In other words, don't hard code 20 in your function like while (counter < 20). Instead pass the number of lines to be handled and do while (counter < number_to_handle).
Something like this as pseudo code:
a = 0;
while(streams_not_empty)
{
CA >> CAArray[a];
SA >> SAArray[a];
++a;
if (a == 20)
{
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter, a);
// ^
a = 0; // Reset a
}
}
if (a != 0)
{
// Process the rest
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter, a);
}
CA.close(); // closing "CorrectAnswers.txt"
SA.close(); // closing "StudentAnswers.txt"
One problem you have is you're trying to compare C-style strings with the == operator. This will compare them essentially as if they were pointers to char, i.e. compare whether they point at the same location in memory, not compare the contents of the string. I urge you to look up array-decay and c-string variables to understand more.
Specifically, if (PassFail(percent) == "pass") isn't going to do what you want it to. strcomp doc, strncmp doc using std::string variables instead of c-style strings would all work, but it would be better simply to compare percent to a value, i.e. if(percent >= 0.70 directly instead of calling PassFail and comparing a string.
There are many other issues here also, you at one point call PassFail but do nothing with the return value. The only side affect of PassFail is cout << endl, if that's what you intend, it's a poor decision and hard to read way to put a newline on the console.
Try asking your compiler for more warnings, that's often helpful in finding these types of issues. -Wall -Wextra work for gcc, you may have to read your compiler manual...

Auto generate ID in C++

// AnE.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<conio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
// The maximum number of patients in queue
#define MAXPATIENTS 30
// define structure for patient information
struct patient
{
char FirstName[50];
char LastName[50];
char ID[20];
};
// define class for queue
class queue
{
public:
queue (void);
int RegisterPatien (patient p);
int RegisterPatientAtBeginning (patient p);
patient GetNextPatient (void);
int CancelAll (patient * p);
void OutputList (void);
char DepartmentName[50];
private:
int ShowAllPatient;
patient List[MAXPATIENTS];
};
// declare member functions for queue
queue::queue ()
{
// Constructor
ShowAllPatient = 0;
}
int queue::RegisterPatien (patient p)
{
// To add a patient (normally) to the queue (to the end).
// returns 1 if successful, 0 if queue is full.
if (ShowAllPatient >= MAXPATIENTS)
{
// queue is full
return 0;
}
// put in new patient
else
List[ShowAllPatient] = p; ShowAllPatient++;
return 1;
}
int queue::RegisterPatientAtBeginning (patient p)
{
// adds a critically ill patient to the beginning of the queue.
// returns 1 if successful, 0 if queue is full.
int i;
if (ShowAllPatient >= MAXPATIENTS)
{
// queue is full
return 0;
}
// move all patients one position back in queue
for (i = ShowAllPatient-1; i >= 0; i--)
{
List[i+1] = List[i];
}
// put in new patient
List[0] = p; ShowAllPatient++;
return 1;
}
patient queue::GetNextPatient (void)
{
// gets the patient that is first in the queue.
// returns patient with no ID if queue is empty
int i; patient p;
if (ShowAllPatient == 0) {
// queue is empty
strcpy(p.ID,"");
return p;}
// get first patient
p = List[0];
// move all remaining patients one position forward in queue
ShowAllPatient--;
for (i=0; i<ShowAllPatient; i++)
{
List[i] = List[i+1];
}
// return patient
return p;
}
int queue::CancelAll (patient * p)
{
// removes a patient from queue.
// returns 1 if successful, 0 if patient not found
int i, j, found = 0;
// search for patient
for (i=0; i<ShowAllPatient; i++)
{
if (stricmp(List[i].ID, p->ID) == 0)
{
// patient found in queue
*p = List[i]; found = 1;
// move all following patients one position forward in queue
ShowAllPatient--;
for (j=i; j<ShowAllPatient; j++)
{
List[j] = List[j+1];
}
}
}
return found;
}
void queue::OutputList (void)
{
// lists entire queue on screen
int i;
if (ShowAllPatient == 0)
{
cout<< "Queue is empty";
}
else
{
for (i=0; i<ShowAllPatient; i++)
{
cout << "First Name : " << List[i].FirstName<<endl;
cout << "Last Name : " << List[i].LastName<<endl;
}
}
}
// declare functions used by main:
patient InputPatient (void)
{
// this function asks user for patient data.
patient p;
cout<<endl<<endl;
cout << "Please enter the information of the Patient"<<endl<<endl;
cout << "First name: "<<endl<<endl;
cin.getline(p.FirstName, sizeof(p.FirstName));
cout << "Last name: "<<endl<<endl;
cin.getline(p.LastName, sizeof(p.LastName));
// check if data valid
if (p.FirstName[0]==0 || p.LastName[0]==0 || p.ID[0]==0)
{
// rejected
strcpy(p.ID,"");
cout << "Error: Data not valid. Operation cancelled.";
getch();
}
return p;
}
void OutputPatient (patient * p)
{
// this function outputs patient data to the screen
if (p == NULL || p->ID[0]==0)
{
cout << "No patient";
return;
}
else
cout << "Patient Information:"<<endl<<endl;
cout << "First name: " << p->FirstName<<endl<<endl;
cout << "Last name: " << p->LastName<<endl<<endl;
}
int ReadNumber()
{
// this function reads an integer number from the keyboard.
// it is used because input with cin >> doesn't work properly!
char buffer[20];
cin.getline(buffer, sizeof(buffer));
return atoi(buffer);
}
void DepartmentMenu (queue * q)
{
// this function defines the user interface with menu for one department
int choice = 0, success; patient p;
while (choice != 6)
{
// print menu
system("CLS");
cout << "<< || Welcome || >> "<<endl << q->DepartmentName<<endl;
cout << "Please enter your choice:"<<endl<<endl;
cout << "1: Register patient"<<endl;
cout << "2: Serve patient "<<endl;
cout << "3: Cancel all patients from queue"<<endl;
cout << "4: Show all patient"<<endl;
cout << "5: Exit"<<endl<<endl<<endl<<endl<<endl<<endl<<endl<<endl;
choice = ReadNumber();
switch (choice)
{
case 1: // Add new patient
p = InputPatient();
if (p.ID[0])
{
success = q->RegisterPatien(p);
system("CLS");
if (success)
{
cout << "Patient added:"<<endl<<endl;
}
else
{
// error
cout << "Sorry: The queue is full. We Cannot add any patient:";
}
OutputPatient(&p);
cout << "Press any key";
getch();
}
break;
case 2: // Call patient for operation /First Come First Surve
p = q->GetNextPatient();
system("CLS");
if (p.ID[0])
{
cout << "Patient to operate:";
OutputPatient(&p);
}
else
{
cout << "Currently there is no patient to operate.";
}
cout << "Press any key to contiune";
getch();
break;
case 3: // Cancel all from queue
p = InputPatient();
if (p.ID[0])
{
success = q->CancelAll(&p);
system("CLS");
if (success)
{
cout << "Patient removed:";
}
else
{
// error
cout << "Sort: We cannot find patient:";
}
OutputPatient(&p);
cout << "Press any key to contiune";
getch();
}
break;
case 4: // Show all patient -> queues
system("CLS");
q->OutputList();
cout << "Press any key";
getch(); break;
}
}
}
// the main function defining queues and main menu
void main ()
{
int i, MenuChoice = 0;
// define queue
queue department[1];
// set department name
strcpy_s (department[0].DepartmentName, "To Emergency Department");
while (MenuChoice != 2)
{
system("CLS");
// Cout menu
cout<<"\n------------------------------------\n";
cout << "Welcome to Waiting Room Management System"<<endl;
cout<<"---------------------------------------\n";
cout << "Please Select a Number from the following menu:"<<endl<<endl;
for (i = 0; i < 1; i++)
{
// write menu item for department i
cout<< "" << (i+1) << ": "<< department[i].DepartmentName;
cout<<endl;
}
cout << "2: Exit"<<endl;
// get user choice
MenuChoice = ReadNumber();
// is it a department name?
if (MenuChoice >= 1 && MenuChoice <= 1)
{
// call submenu for department
// (using pointer arithmetics here:)
DepartmentMenu (department + (MenuChoice-1));
}
}
}
Okay, it's Vc++ for waiting room. You can see the code is working well, but I have problem with generating ID! I need to generate ID for each patient (auto-generate by system). How I can generate ID for my queue?
Thanks alot !
Usually, you'd do it by putting a static variable in that class, and each time you get a new patient, you assign its current value to the current patient, then increment it.
class patient {
// ...
int id;
static int current_id; // added
patient() : id(current_id++) {} // added
};
int patient::current_id; // added
The other answers are great, but the currently accepted one isn't actually thread safe as pointed out by another user.
To make a thread safe ID generation function, we can use atomics! Here is a modification of the currently accepted answer that makes it thread safe.
#include <atomic> //std::atomic_uint32_t
class patient
{
// ...
uint32_t id;
static std::atomic_uint32_t current_id; // added
patient() : id(current_id++) {} // added
};
uint32_t patient::current_id; // added
std::atomic_uint32_t is a 32 bit unsigned integer, that (because its atomic) wont have any data races if written to at the same time by two different threads.
I also changed the integer to be unsigned. This is because the ID will never be negative, so it makes sense to make it unsigned.
https://en.cppreference.com/w/cpp/atomic/atomic
If you want unique ids, you can generate a GUIDs. For VC++, you can use:
extern C
{
#include <Rpc.h>
}
//...
UUID id;
UuidCreate ( &id );
You can use a static variable when you create a patient (if you want it there) that increment itself in the constructor, or a variable in you're queue that increment when you add a patient (if you want to only assign an ID when in the queue).
But in your case, I think you want the first solution (static variable in the constructor).
I had the same need for an SQL-database and ended up with this...
Warning: Mostly an example of bad programming with mixing C and C++ (still need to convert old code), but it was meant to convey the idea. I am sure better solutions exist...
It generates (unfortunately) large character based ID's, based on current date and time. This means that every next auto-generated ID needs to be bigger: if it is equal or smaller, a millisecond timer is appended and the code will wait until the ID has become unique. It works without the milliseconds as well, but this will lead to long delays if you need to generate many ID's at once (a second for each pause). If desired, it will also add an optional postfix (can help omit the milliseconds).
My experience with simple counters is, that they might duplicate under certain circumstances, which had me look for an alternative.
Careful: Another user on another computer might generate equal ID's... (same second or millisecond)
TUID::TUID()
{
*LastID = 0; // char [80] - Global within object
}
void TUID::GetToday (int *d, int *m, int *y)
{
time_t now;
struct tm *ltm;
time (&now);
ltm = localtime (&now);
*y = ltm->tm_year + 1900;
*m = ltm->tm_mon + 1;
*d = ltm->tm_mday;
}
void GetTime (int *h, int *m, int *s)
{
time_t t = time(0); // get time now
struct tm * now = localtime( & t );
*h = now->tm_hour;
*m = now->tm_min;
*s = now->tm_sec;
}
const char *TUID::NewUID (bool bPreviousAttemptFailed, const char *_postfix)
{
int d, m, y,
_h, _m, _s;
bool bSameAsLastUID;
char _uid [80];
GetToday (&d, &m, &y);
do
{
GetTime (&_h, &_m, &_s);
sprintf (_uid, "%04d%02d%02d_%02d%02d%02d%s", y, m, d, _h, _m, _s, _postfix);
bSameAsLastUID = (strcmp (_uid, LastUID) <= 0);
if (bPreviousAttemptFailed || bSameAsLastUID)
sprintf (_uid + strlen (_uid), "_%d",
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count());
}
while (strcmp (_uid, LastUID) <= 0);
strcpy (LastUID, _uid);
return LastUID;
}
This results in ID's like this:
20170816_115904 (no post-fix)
20170816_115904i (with post-fix keeping id unique, preventing milliseconds)
20170816_115904i_6427264 (auto-added milliseconds to keep ID unique)
20170816_115904i_6427265
20170816_115904i_6427266

(C++ Query) Accessing the instantiated objects globally

This is a basic program to get two 5-digit numbers as string and use addition on the 2 numbers utilising operator overloading on '+' .
#include <iostream>
#include <limits>
#include <cstdlib>
#include <cstring>
#include <sstream>
using namespace std;
class IntStr
{
int InputNum;
public:
//IntStr();
IntStr::IntStr(int num);
IntStr operator+ (const IntStr &);
//~IntStr();
void Display();
};
IntStr::IntStr(int num)
{
InputNum = num;
}
void IntStr::Display()
{
cout << "Number is (via Display) : " << InputNum <<endl;
}
IntStr IntStr::operator+ (const IntStr & second) {
int add_result = InputNum + second.InputNum;
return IntStr(add_result);
}
int main()
{
string str;
bool option = true;
bool option2 = true;
while (option)
{
cout << "Enter the number : " ;
if (!getline(cin, str))
{
cerr << "Something went seriously wrong...\n";
}
istringstream iss(str);
int i;
iss >> i; // Extract an integer value from the stream that wraps str
if (!iss)
{
// Extraction failed (or a more serious problem like EOF reached)
cerr << "Enter a number dammit!\n";
}
else if (i < 10000 || i > 99999)
{
cerr << "Out of range!\n";
}
else
{
// Process i
//cout << "Stream is: " << iss << endl; //For debugging purposesc only
cout << "Number is : " << i << endl;
option = false;
IntStr obj1 = IntStr(i);
obj1.Display();
}
}//while
while (option2)
{
cout << "Enter the second number : " ;
if (!getline(cin, str))
{
cerr << "Something went seriously wrong...\n";
}
istringstream iss(str);
int i;
iss >> i; // Extract an integer value from the stream that wraps str
if (!iss) //------------------------------------------> (i)
{
// Extraction failed (or a more serious problem like EOF reached)
cerr << "Enter a number dammit!\n";
}
else if (i < 10000 || i > 99999)
{
cerr << "Out of range!\n";
}
else
{
// Process i
//cout << "Stream is: " << iss << endl; //For debugging purposes only
cout << "Number is : " << i << endl;
option2 = false;
IntStr obj2 = IntStr(i);
obj2.Display();
//obj1->Display();
}
}//while
//IntStr Result = obj1 + obj2; // --------------------> (ii)
//Result.Display();
cin.get();
}
Need clarification on the points (i) & (ii) in the above code ...
(1) What does (i) actually do ?
(2) (ii) -> Does not compile.. as the error "obj1 not declared (first use this function)" comes up. Is this because obj1 & obj2 are declared only inside the while loops? How do I access them globally?
1) From http://www.cplusplus.com/reference/iostream/ios/operatornot/ :
bool operator ! ( ) const; Evaluate
stream object
Returns true if either one of the
error flags (failbit or badbit) is set
on the stream. Otherwise it returns
false.
From http://www.cplusplus.com/reference/iostream/ios/fail/ :
failbit is generally set by an input
operation when the error was related
with the internal logic of the
operation itself, while badbit is
generally set when the error involves
the loss of integrity of the stream,
which is likely to persist even if a
different operation is performed on
the stream.
2) The two objects are not in scope, they exists only in the previous brackets.
calls the overloaded operator which evaluates the stream in boolean context. This checks the state of the stream to see if the previous operation had failed - if so, you cannot rely on the value in the integer variable i being valid because the input on the stream was not an integer.
the variables obj1 and obj2 are defined in the scope of the while loop - they are not available outside the scope. You can declare them outside the scope of the while in which case the variable will hold the last value it held in the while loop.
if (!iss)
tests if the stream is in a bad state, which will be the case if a conversion failed or if you are at the end of the stream
obj1 is defined here:
else
{
// Process i
//cout << "Stream is: " << iss << endl; //For debugging purposesc only
cout << "Number is : " << i << endl;
option = false;
IntStr obj1 = IntStr(i);
obj1.Display();
}
it is therefore local to the else-block & can't be accessed outside it. If you want to increase its scope, modve its definition outside of the block. It is not a good idea to move it outside of all blocks (i.e. make it global), however.