Auto generate ID in C++ - 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

Related

Getting write access violation when trying to re-allocate memory

I am writing a program that takes some contact information from user and grows the array dynamically when it gets full. But when I am trying to run the program I get Write access violation popping up a line from "iosfwd standard header". I don't know where I went wrong. Please do help.
My code looks like this:
# include "pch.h"
# include <iostream>
# include <string>
using namespace std;
struct Contact {
string name;
string number;
string address;
string exit;
};
void userPrompt(Contact &contact) {
cout << "Name: ";
getline(cin, contact.name);
cout << "Phone number: ";
getline(cin, contact.number);
cout << "Address: ";
getline(cin, contact.address);
cout << "Exit? (y/n): ";
getline(cin, contact.exit);
}
void printContact(Contact &contact) {
cout << "Name: " << contact.name << endl;
cout << "Phone number: " << contact.number << endl;
cout << "Address: " << contact.address << "\n" << endl;
}
void growArray(int &currentLength, Contact *contacts) {
int multiplyer = 2;
Contact *new_array = new Contact[currentLength * multiplyer];
for (int i = 0; i < currentLength; i++) {
new_array[i] = contacts[i];
}
delete[] contacts;
contacts = new_array;
currentLength *= multiplyer;
}
void showAllContacts(Contact *contacts, int length) {
for (int i = 0; i < length; i++) {
if (contacts[i].name.length() != 0) {
printContact(contacts[i]);
}
}
}
int main() {
// Prompt the user to fill in the address book.
// If the array gets full, make it bigger.
Contact *contacts = new Contact[1];
int currentLength = 1;
int i = 0;
while (true) {
userPrompt(contacts[i]);
if (contacts[i].exit == "y" or contacts[i].exit == "Y") {
break;
}
i++;
if (i == currentLength) {
growArray(currentLength, contacts);
}
}
// Show the address book
showAllContacts(contacts, currentLength);
}
But when I am running the code it throws exception like this:
enter image description here
"Write Access Violation"
I think the bug is in the growArray function. But I can't fugure out where did I screw up. Please do help.
In
growArray(currentLength, contacts);
a copy of the pointer contacts is modified inside the function; but outside, the pointer's value stays the same. After growArray returns, contacts points to deleted memory, hence UB, hence the crash.
==> Full program demonstration of the issue <==
There are basically two solutions: the bad one and the good one. The bad one is to change the signature of growArray to take a reference to the pointer:
void growArray(int &currentLength, Contact *&contacts)
The good one is to stop this manually allocated memory non-sense and use a std::vector<Contact>!

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...

C++: When using a value called from a getter method of an object, a random negative int is outputted?

The following is my file TotalTemplate.cpp:
#include <iostream>
#include "conio.h"
using namespace std;
template<class T>
class TotalTemplate{
public:
//protected:
T* items;
int itemsAdded;
int amountOfItems;
//public:
//Exception for trying to add items when its passed its limit
class TooManyItems{ };
//Exception for trying to call total before the total has been reached
class IncompleteTotal{ };
TotalTemplate(int amountOfItems){
TotalTemplate::amountOfItems = amountOfItems;
items = new T[amountOfItems];
itemsAdded = 0;
}
TotalTemplate(int amountOfItems, T firstItem){
TotalTemplate::amountOfItems = amountOfItems;
items[] = new T[amountOfItems];
items[0] = firstItem;
itemsAdded = 1;
}
void addItem(T item){
if (itemsAdded >= amountOfItems)
throw TooManyItems();
else{
items[itemsAdded-1] = item;
itemsAdded++;
}
}
//Returns the amount of items added so far
int getAmountAdded(){
return itemsAdded;
}
T getTotal(){//Here is the method definition that is giving me problems
if (itemsAdded < amountOfItems)
throw IncompleteTotal();
else{
T total=items[0];
for (int i = 1; i < itemsAdded; i++)
total += items[i];
return total;
}
}
};
void main(){
//using int to fill the generic type T
cout << "Enter the amount of items to be totaled: ";
int totalAmountOfItems = getInt();
TotalTemplate<int> *total=new TotalTemplate<int>(totalAmountOfItems);
while (true){
cout << total->getAmountAdded() << " items added so far!\nSelect one of the following actions to take.\n";
cout << "(1) Add an item.\n";
cout << "(2) View total.\n";
cout << "(3) Exit Program.\n";
switch (menuSelect(3)){
case 1://Add an item
try{
cout << "Enter a number to add: ";
int item = getInt();
total->addItem(item);
}
catch (TotalTemplate<int>::TooManyItems){
cout << "\nItems given exceeds expected limit.\n\n";
}
break;
case 2://View Total
try{
int totalInt = total->getTotal(); //Here is my problem
cout << "The total is: " << totalInt << endl<<endl;
}
catch (TotalTemplate<int>::IncompleteTotal){
cout << "\nRunning Total has not yet reached total amount of items yet.\n\n";
}
break;
case 3: //Exit program
return;
}
}
cout << "\n\nExiting program...";
_getch();
}
The problem I'm getting is in the main method, when I call total.getTotal(), instead of return an expected int, being the total of all the items added together, I get a totally random int outputted: -842150451
My guess is that it's outputting something instead of the value returned from getTotal(), but I'm not sure how or why or how to fix it. I come from a Java background so I feel like I'm out of habit doing improper oop C++ practice.
Also, getInt() and menuSelect() are methods I have reused from previous codes multiple times, so I excluded them from the file for simplicity sake.
Does anyone know what I'm doing wrong?
this line in addItem
items[itemsAdded-1] = item;
should be
items[itemsAdded] = item;

Linker error undefined reference to (all of my defined functions when called)

I wrote this program a few days ago as a kind of proof-of-concept. Now that I know it works, I am trying to clean up the code and make things flow better. The biggest change from the original program I wrote and this new version of it is I turned anything I used more than once into a function. The problem I am having is for every place I call any of my functions, I get a linker error. I believe that the program is finished now except for this error.
The trickiest bit is that last night--before I ran into this error and was dealing with a different one having to do with char* and char...--I managed to fix my error and my code worked fine, even the one function that was written at the time. When I started working on it today I somehow found that I had somehow lost that progress and went to re-fix it. Once I fixed the error again--to my knowledge I did it in the exact same way--I had this linker error for each time that I called the function and for each new function as I wrote them and called them in main().
Here is the code:
//******************************************************************************
// David Ewing
// This program is an improvement on the original Cypher program which cyphered
// upto 255 characters of inputed text according to a provided keyphrase. This
// version seeks to improve the flow of the code and allow for a larger input of
// text.
//******************************************************************************
#include <iostream>
using namespace std;
// Declair global variables
char keyphrase[8192];
char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
char cypherAlphabet[8192];
char sourceText[8192];
char cypherText[8192];
int sizeKeyphrase;
int sizeCypherAlphabet;
int sizeSourceText;
// ...Counters
int counter1;
int counter2;
int counter3;
// Declair functions
void cypher (char, int);
void eliminateDuplicates (char, int);
int getSize(char);
void handleSpaces (char, bool);
void reduceCase (char, int);
//******************************************************************************
// MAIN
//******************************************************************************
int main( void )
{
// Describe program
cout << "This program cyphers whatever text the user wishes according to a " << endl;
cout << "keyphrase that the user provides." << endl << endl;
// Retrieve keyphrase
cout << "Please enter the keyphrase that you would like to use for your cypher." << endl;
cout << "The keyphrase may include spaces, repeated letters, and capitals, but " << endl;
cout << "they will be removed before it is applied to the provided text." << endl;
cout << "Enter \"DONE\" when you have finished typing your keyphrase." << endl;
// Call function to remove spaces from keyphrase
handleSpaces (keyphrase[8192], false);
// Call function to get size of keyphrase
sizeKeyphrase = getSize (keyphrase[8192]);
// Call function to remove repeated letters from keyphrase
eliminateDuplicates (keyphrase[8192], sizeKeyphrase);
// Call function to normalize case of keyphrase
reduceCase (keyphrase[8192], sizeKeyphrase);
// Apply keyphrase to alphabet
strcpy (cypherAlphabet, keyphrase); // Copy the keyphrase to the beginning of cypherAlphabet
strcat (cypherAlphabet, alphabet); // Add the rest of the alphabet after the keyphrase to cypherAlphabet
// Call function to get size of cypherAlphabet
sizeCypherAlphabet = getSize (cypherAlphabet[8192]);
// Call function to remove repeated letters from cypherAlphabet
eliminateDuplicates(cypherAlphabet[8192], sizeCypherAlphabet);
// Retrieve sourceText
cout << endl << "Please enter the text which you wish to be cyphered. Capitals will be" << endl;
cout << "removed but punctuation and any other non-alphanumeric characters will" << endl;
cout << "be ignored." << endl;
cout << "Enter \"DONE\" when you have finished typing your text." << endl;
// Call function to take input for sourceText and to handle spaces
handleSpaces(sourceText[8192], true);
// Call function to get size of sourceText
sizeSourceText = getSize (sourceText[8192]);
// Call function to normalize case of sourceText
reduceCase(sourceText[8192], sizeSourceText);
// Cypher sourceText
cypher(sourceText[8192], sizeSourceText);
// Display cypherText
cout << endl << "Your cyphered text is as follows:" << endl;
cout << cypherText << endl << endl;
// Pause program
system ("pause");
// End program
return 0;
} // End main
//******************************************************************************
// CYPHER
//******************************************************************************
void cypher (char text[8192], int size)
{
// Declare counters
counter1 = 0;
counter2 = 0;
// Search alphabet for address of each letter
while (counter1 < size)
{
counter2++;
if (sourceText[counter1] == alphabet[counter2-1])
{
cypherText[counter1] = cypherAlphabet[counter2 - 1];
counter1++;
counter2 = 0;
} // End if
if (counter2 > 25) // If all the letters in the alphabet are checked
{
cypherText[counter1] = sourceText[counter1]; // give up on the letter, transcribing it over
counter1++; // and continue with the rest of the soureText
counter2 = 0; // Allows for punctuation, spaces, strange symbols, etc.
} // End if
} // End while
} // End cypher
//******************************************************************************
// ELIMINATE DUPLICATES
//******************************************************************************
void eliminateDuplicates (char text[8192], int size)
{
// Initialize counters
counter1 = 0;
counter2 = 1;
counter3 = 1;
// Initialize flag
//bool flag = false;
while (counter1 < size)
{
if (text[counter1] == text[counter1+counter2] && text[counter1] != NULL)
{
// Delete text[i+j]
for (counter3 = 1; counter3 < size; counter3++)
{
text[counter1+counter2+counter3-1] = text[counter1+counter2+counter3]; // Shift array left at repeated letter. Final value is doubled.
//if (counter3 == size - 1)
//{
// flag = true;
//} // End if
} // End for
} // End if
else if (counter2 == size)
{
counter1++;
counter2 = 1; // Reset counter
//flag = false; // Reset flag
} // End else if
else
{
counter2++;
//flag = false;
} // End else
} // End while
} // End eliminateDuplicates
//******************************************************************************
// GET SIZE
//******************************************************************************
int getSize (char text[8192])
{
int size = 0; // Declair counter/result variable
while (text[size] != NULL)
{
size++;
} // End while
return size;
} // End getSize
//******************************************************************************
// HANDLE SPACES
//******************************************************************************
void handleSpaces (char text[8192], bool includeSpaces)
{
// Declare temporary input holder
char temp[8192];
// Initialize flag
bool flag = false;
cin >> text;
while (flag == false)
{
cin >> temp;
if (strcmp(temp, "DONE"))
{
if (includeSpaces == true)
{
strcat(text, " "); // Add space after last word
} // End if
strcat(text, temp); // Add the next word to the last
} // End if
else
{
flag = true;
} // End else
} // End while
} // End handleSpaces
//******************************************************************************
// REDUCE CASE
//******************************************************************************
void reduceCase (char text[8192], int size)
{
// Declare counter
int counter1 = 0;
while (counter1 < size)
{
sourceText[counter1] = tolower(sourceText[counter1]); // Use tolower for each item in the array
counter1++;
} // End while
} // End reduceCase
The declarations and the definitions differ:
declaration:
void cypher (char, int);
definition:
void cypher (char text[8192], int size)
Just one example.
Also, the call is wrong:
cypher(sourceText, sizeSourceText);
instead of
cypher(sourceText[8192], sizeSourceText);
When you write:
void cypher (char text[8192], int size)
it means the function takes an array as parameter.
And when you call it with
cypher(sourceText[8192], sizeSourceText);
it means you're calling the function with the character at position 8192 from that char array.

Keep a state when parsing text

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 : /* ... */
}