My english is not very good, but, I hope, you will understand me.
I know that turning string into code is impossible in C++, but I just can't see another way of solving my trouble.
I have an array of structures. You can say that it's a database. The task is that user should make combined request. In console a user chooses two parameters of structure and makes a combined request.
Something like this
cout<<"\nВыберите первый параметр для поиска:" // Choose first parameter
<<"\n1. processor"
<<"\n2. videocard"
<<"\n3. display"
<<"\n4. RAM"
<<"\n5. size"<<endl;
int first;
cin>>first;
cout<<"\nВыберите второй параметр для поиска:" // Choose second parameter
<<"\n1. processor"
<<"\n2. videocard"
<<"\n3. display"
<<"\n4. RAM"
<<"\n5. size"<<endl;
int second;
cin>>second;
cout<<"enter searchkey for first value: "
string search1;
cin>>search1;
cout<<"enter searchkey for second value: "
string search2;
cin>>search2;
string parameters[ 5 ] = { "processor", "videocard", "display", "RAM", "size" };
for ( i = 0; i < size; i++ ) // And that's where it all goes wrong.
if ( arrayOfStructs.parameters[ first ] == search1 && arrayOfStructs.parameters[ second ] == search2 )
cout<<"found a match"<<endl;
I know why code doesn't work. I'm really sure that exists a solution that looks similar to mine. My "solution" looks like enum, but enum in this case is not appropriate.
If you know the solution, please write it down below.
The full code of my program
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
struct computer
{
string processor;
string videocard;
string display;
string RAM;
string size;
string getFieldValue( int );
};
string computer::getFieldValue( int fieldNumber )
{
stringstream str;
switch (fieldNumber)
{
case 1: str<<this->processor;
case 2: str<<this->videocard;
case 3: str<<this->display;
case 4: str<<this->RAM;
case 5: str<<this->size;
}
return str.str();
}
void coutAndWrite( computer aStruct, ofstream &aFile );
int main()
{
setlocale( 0, "" );
computer sklad[ 30 ];
computer temp;
int i = 0, j;
ifstream fromFile("structury.txt");
while ( !fromFile.eof() )
{
fromFile>>sklad[ i ].processor
>>sklad[ i ].videocard
>>sklad[ i ].display
>>sklad[ i ].RAM
>>sklad[ i ].size;
i++;
}
fromFile.close();
ofstream rezultaty("rezultaty.txt");
for ( i = 0; i < 30; i++ )
for ( j = 0; j < 29; j++ )
if ( sklad[ j + 1 ].processor[ 0 ] < sklad[ j ].processor[ 0 ] )
{
temp = sklad[ j + 1 ];
sklad[ j + 1 ] = sklad[ j ];
sklad[ j ] = temp;
}
while ( 1 )
{
cout<<"\nВыберите тип запроса:"
<<"\n1. Простой"
<<"\n2. Составной"
<<"\n0. Выход из программы\n";
int prostoiIliSostavnoi;
cin>>prostoiIliSostavnoi;
if ( prostoiIliSostavnoi == 0 )
break;
if ( prostoiIliSostavnoi == 1 )
{
cout<<"\nВыберите параметр для поиска:"
<<"\n1. processor"
<<"\n2. videocard"
<<"\n3. display"
<<"\n4. RAM"
<<"\n5. size"<<endl;
int parametr;
cin>>parametr;
cout<<"Введите ключ поиска: ";
string poisk;
cin>>poisk;
cout<<"Результаты поиска: ";
for ( i = 0; i < 30; i++ )
if ( sklad[ i ].getFieldValue( parametr ) == poisk )
coutAndWrite( sklad[ i ], rezultaty );
}
}
system("pause");
}
void coutAndWrite( computer aStruct, ofstream &aFile )
{
cout<<"\nprocessor: "<<aStruct.processor
<<"\nvideocard: "<<aStruct.videocard
<<"\ndisplay: "<<aStruct.display
<<"\nRAM: "<<aStruct.RAM
<<"\nsize: "<<aStruct.size<<endl<<endl;
aFile<<setw( 15 )<<aStruct.processor
<<setw( 15 )<<aStruct.videocard
<<setw( 20 )<<aStruct.display
<<setw( 10 )<<aStruct.RAM
<<setw( 10 )<<aStruct.size<<endl;
}
Break it into pieces. Let's ignore the loop and the double search, and focus on the core problem: getting a field's value when you have its field number (or name):
string Computer::getFieldValue(int fieldNumber)
{
stringstream str;
switch (fieldNumber) {
case 1: str << this->processor; break;
case 2: str << this->videocard; break;
case 3: str << this->display; break;
case 4: str << this->RAM; break;
case 5: str << this->size; break;
}
return str.str();
}
Given this helper function, it's now possible to write the checking code.
for (int i = 0; i < size; ++i) {
if (computers[i].getFieldValue(first) == search1 &&
computers[i].getFieldValue(second) == search2)
{
cout << "found a match" << endl;
}
}
Related
I am building a program in OOP C++ that will convert an Infix to Postfix expression using predefined Stackitem and Stack classes ( these two classes work fine). But I have some problems in the implementation of conversion algorithm. I cannot get the expected output for some inputs.
I have tried to implement the following algorithm:
Basic steps, while parsing the infix expression:
if the item is an operand, output immediately
if the item is a left parenthesis, push onto the stack
if the item is a right parenthesis pop the stack and output the contents until a left parenthesis (parenthesis is popped but not output)
if the item is an operator, pop and output all the operators with higher or equal precendence, then push the item onto the stack
just push the item onto the stack, if the stack is empty or the top element is a left parenthesis or if the top element has a lower precendence.
Stackitem class implementation which helps in decesiding wheather the item is operator, operand, and its precedence (by giving an integer)
#include "StackItem.h"
StackItem::StackItem(bool isOp, int i) {
init(isOp, i);
next = 0;
}
StackItem::StackItem(string item) {
if(item.compare("+") == 0)
init(true, OPERATOR_PLUS);
else if(item.compare("-") == 0)
init(true, OPERATOR_MINUS);
else if(item.compare("*") == 0)
init(true, OPERATOR_MULTIPLICATION);
else if(item.compare("/") == 0)
init(true, OPERATOR_DIVISION);
else if(item.compare("(") == 0)
init(true, OPERATOR_LEFTPAR);
else if(item.compare(")") == 0)
init(true, OPERATOR_RIGHTPAR);
else
init(false, atoi(item.c_str()));
}
void StackItem::init(bool isOp, int i) {
isOperator = isOp;
if(isOp)
op = i;
else
n = i;
}
string StackItem::toString() {
stringstream ss;
if(!isOperator) {
ss << n;
} else {
switch(op) {
case OPERATOR_MINUS:
ss << "-";
break;
case OPERATOR_PLUS:
ss << "+";
break;
case OPERATOR_DIVISION:
ss << "/";
break;
case OPERATOR_MULTIPLICATION:
ss << "*";
break;
case OPERATOR_LEFTPAR:
ss << "(";
break;
case OPERATOR_RIGHTPAR:
ss << ")";
break;
}
}
return ss.str();
}
And here is the problematic code ( for conversion ). I am suspecting that the problem is with my ( fifth and sixth point of the algorithm steps)
#include "Calculator.h"
#include <iostream>
Calculator::Calculator( string expression ) {
infixExpression = expression;
stack = new Stack();
istringstream iss( expression );
string token;
iss >> token;
postfixExpression = "";
while ( token.compare( ";" ) != 0 ) {
cout << "token:" << token << endl;
StackItem *item = new StackItem( token );
if ( !item->isOperator ) {
postfixExpression += item->toString() + " ";
} else {
if ( item->op == OPERATOR_LEFTPAR )
stack->push( item );
else if ( item->op == OPERATOR_RIGHTPAR ) {
while ( !stack->isEmpty() && stack->top() != OPERATOR_LEFTPAR ) {
string s = stack->top()->toString();
delete stack->pop();
postfixExpression += s + " ";
}
string s = stack->top()->toString();
delete stack->pop();
} else {
while ( !stack->isEmpty() && ( item->op <= stack->top()->op ) ) {
if ( stack->top()->isOperator ) {
string s = stack->top()->toString();
delete stack->pop();
postfixExpression += s + " ";
}
break;
}
while ( ( stack->isEmpty() ) || ( stack->top()->op == OPERATOR_LEFTPAR ) || ( stack->top()->op < item->op ) ) {
stack->push( item );
}
}
}
iss >> token;
}
while ( !stack->isEmpty() ) {
string s = stack->top()->toString();
delete stack->pop();
postfixExpression += s + " ";
}
postfixExpression += ";";
}
string Calculator::getPostfix() {
return postfixExpression;
}
The required inputs and outputs has to be parsed according to ";" at the end and a white space has to be left between each input and output part.
Example:
Input: 1 + 2 + 3 ;
Output: 1 2 + 3 + ; ( this works fine)
However,
Input : ( 1 + 2 ) ;
Output : Nothing ( it gives return some memory address)
Also for:
Input : 10 + 10 * 40 - 45 / 5 ;
Output : 10 10 4 * 45 5 / + ;
Which is a wrong order!
Edit: The operator defines are as follows:
#define OPERATOR_LEFTPAR 0
#define OPERATOR_RIGHTPAR 1
#define OPERATOR_MINUS 2
#define OPERATOR_PLUS 3
#define OPERATOR_DIVISION 4
#define OPERATOR_MULTIPLICATION 5
Edit: This new code solved many problems with basic and short inputs, still very large and complicated expressions crash in the output.
#include "Calculator.h"
#include <iostream>
Calculator::Calculator(string expression)
{
infixExpression=expression;
stack = new Stack();
istringstream iss(expression);
string token;
iss >> token;
postfixExpression="";
while(token.compare(";") != 0)
{
//cout << "token:"<<token << endl;
StackItem* item=new StackItem(token);
if(!item->isOperator){
postfixExpression += item->toString() + " ";
}
else
{
if(item->op == OPERATOR_LEFTPAR)
stack->push(item);
else if(item->op == OPERATOR_RIGHTPAR)
{
while(!stack->isEmpty()&& stack->top()->op != OPERATOR_LEFTPAR)
{
string s = stack->top()->toString();
delete stack->pop();
postfixExpression +=s+" ";
}
string s = stack->top()->toString();
delete stack->pop();
}
else
{
while((!stack->isEmpty()) && item->op <= stack->top()->op)
{
string s = stack->top()->toString();
delete stack->pop();
postfixExpression +=s+" ";
}
while((stack->isEmpty()) || item->op > stack->top()->op || stack->top()->op==OPERATOR_LEFTPAR)
{
stack->push(item);
}
}
}
iss >> token;
}
while(!stack->isEmpty())
{
string s = stack->top()->toString();
delete stack->pop();
postfixExpression +=s+" ";
}
postfixExpression += ";";
}
string Calculator::getPostfix()
{
return postfixExpression;
}
This is my struct:
struct Event{
int day;
int month;
int year;
int weekday;
string event;
};
My events data file would be like this:
# Comment and empty lines are ignored
# ’$’ means LAST, ’*’ is wildcard
# Weekday on symbolic from Mon,Tue,Wed,Thu,Fri,Sat,Sun
# Events specs start
# Last day is payday
$.*.*:*:Payday
# Birthday at 1.3
1.3.*:*:Birthday Party
# Darts on Fridays
*.*.*:Fri:Darts evening
13.*.*:Fri:Friday the 13th
# EOF
I tried to write this function:
void readFile(vector<string> &data){
string line;
ifstream readFile("events.dat", ios::in);
if (!readFile) {
cerr<<"File COuld not be opened"<<endl;
exit(EXIT_FAILURE);
}
while (readFile && !readFile.eof()) {
getline(readFile,line);
if (line.length() == 0 or line[0] == '#' or line[0] == '/')
break;
data.push_back(line);
}
}
But now I don't know how to convert data vector to event vector?
You could do it with std::istringstream and std::getline, it has a third parameter which is a char at which it should stop consuming characters and return string. Other aproach is to use regexps, below is a way how you can parse it with regexps,I have tested it with only one string but it should give you a start how to do it.
http://coliru.stacked-crooked.com/a/d3aed577b2f72bd7
#include <iostream>
#include <string>
#include <regex>
struct Event{
int day;
int month;
int year;
int weekday;
std::string event;
};
int main()
{
std::regex pattern("([0-9\\$\\*]+)\\.([0-9\\$\\*]+)\\.([0-9\\$\\*]+):(\\w+):([\\w ]+)" );
std::string line = "13.*.*:Fri:Friday the 13th";
std::smatch sm;
Event evt;
if (std::regex_match(line, sm, pattern)) {
std::string val1 = sm[1];
if (val1 == "*")
evt.day = -1; // wildcard
else if (val1 == "$")
evt.day = -2; // last
else
evt.day = std::stoi(val1);
val1 = sm[2];
if (val1 == "*")
evt.month = -1; // wildcard
else if (val1 == "$")
evt.month = -2; // last
else
evt.month = std::stoi(val1);
val1 = sm[3];
if (val1 == "*")
evt.year = -1; // wildcard
else if (val1 == "$")
evt.year = -2; // last
else
evt.year = std::stoi(val1);
std::string weekDay = sm[4];
std::vector<std::string> weekdays = {"Mon", "Tue", "Wen", "Thr", "Fri", "Sat", "Sun"};
auto it = std::find(weekdays.begin(), weekdays.end(), weekDay);
evt.weekday = std::distance(weekdays.begin(), it);
evt.event = sm[5];
std::cout << evt.day << ", " << evt.month << ", " << evt.year << ", " << evt.weekday << ", " << evt.event << "\n";
}
}
on output :
13, -1, -1, 4, Friday the 13th
#include <iomanip>
#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <vector>
using namespace std;
string Day[7] = {"Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
// define struct Date to collect information for Date
struct Date {
int day; // variable to collect day
int month; // variable to collect month
int year; // variable to collect year
int weekday; // variable to store weekday value
string event; // string to hold events
int last;
};
struct Event{
int day;
int month;
int year;
int weekday;
string event;
};
vector<Event> myhappening;
vector<string> data;
void inputDate(Date &); // prototype of inputDate function
void checkYear(Date &); // prototype of checkYear function
void checkMonth(Date &); // prototype of checkMonth function
void checkDay(Date &); // prototype of checkDay function
void checkLast(Date &); // prototype of checkLast function
void increment(Date &); // prototype of increment function
void setWeekDay(Date &); // prototype of setWeekDay function
void setEvent(Date &,Event []); // prototype of setEvent function
void outputDate(Date &); // prototype of outputDate function
void setFirstWeekDay(Date &); // set weekday to the first day of the week
void decrement(Date &date); // Prototype of decrement function
void readFile(vector<string> &);
// main function
int main()
{
Date time; // intialiaze our struct
inputDate(time); // Ask from user to input a date
Event MyHappenings[] =
{
{ -1, 0, 0, 0, "Payday" },
{ 1, 3, 0, 0, "Birthday Party" },
{ 0, 0, 0, 5, "Darts evening" },
{13, 0, 0, 5, "Friday the 13th" },
// {2,3,0,0,"Hooooraaa another event"}, // You can add other events too here," no limits "
}; // Initialize the events,
setWeekDay(time);
setFirstWeekDay(time);
for (int i = 0; i < 7; i++)
{
setWeekDay(time); // Calculate the weekday of a date
checkLast(time); // check that if a date is the last date of the month or not
setEvent(time,MyHappenings); // compare the date and events, and set events related to that date
outputDate(time); // print date with weekdays and events
increment(time); // increment a date by one day
}
readFile(data);
}// end of main function
// inputDate function to get date from user and store it in Date struct
void inputDate(Date &date)
{
cout<<" Enter Your Date (Year starts from 1754) and Follow this format by space DD MM YYYY :"<<endl;
cin>>date.day>>date.month>>date.year;
checkYear(date);
checkMonth(date);
checkDay(date);
cout<< " Your Given Date is : "<<date.day<<" "<<date.month<<" "<<date.year<<endl;
}// end function inputDate
// checkYear Function to check year value to be correct and ask user for correct value if it is uncorrect
void checkYear(Date &date)
{
while (date.year<1754 or date.year>9999) {
cout<< " You pick wrong Year!(It should be between 1754 and 9999)Please Enter new Year Value : ";
cin>>date.year;
}
}// End checkYear function
// checkMonth Function to check month value to be correct and ask user for correct value if it is uncorrect
void checkMonth(Date &date)
{
while (date.month>12 or date.month<1) {
cout<< " You pick wrong Month!(You should pick months between 1-12) Please Enter new Month Value : ";
cin>>date.month;
}
}//End function checkMonth
//checkDay Function to check day value to be correct and ask user for correct value if it is uncorrect
void checkDay(Date &date)
{
switch (date.month) {
case 1: case 3: case 5: case 7: case 8: case 10: case 12 :
while (date.day>31 or date.day<1) {
cout<< " You pick wrong Day!(It should be in 1- 31 range) Please Enter new Day Value : ";
cin>>date.day;
}
break;
case 4: case 6: case 9: case 11:
while (date.day>30 or date.day<1) {
cout<< " You pick wrong Day!(It should be in 1- 30 range) Please Enter new Day Value : ";
cin>>date.day;
}
break;
case 2 :
if ((date.year % 4 ==0 and date.year%100 !=0) or date.year%400==0 ){
if (date.day>29 or date.day<1) {
cout<< " You pick wrong Day!(It should be in 1- 29 range) Please Enter new Day Value : ";
cin>>date.day;
}
}else{
while (date.day>28 or date.day<1) {
cout<< " You pick wrong Day!(It should be in 1- 28 range) Please Enter new Day Value : ";
cin>>date.day;
}
}
break;
default:
cout<<" The program should not get into this code"<<endl;
break;
}
}// End checkDay function
// checkLast funtion to find if a date is last day of the month or not
void checkLast(Date &date)
{
date.last = 0;
switch (date.month) {
case 1: case 3: case 5: case 7: case 8: case 10: case 12 :
if (date.day ==31)
date.last=-1;
break;
case 4: case 6: case 9: case 11:
if (date.day ==30)
date.last=-1;
break;
case 2 :
if ((date.year % 4 ==0 and date.year%100 !=0) or date.year%400==0 ){
if (date.day ==29)
date.last=-1;
}else{
if (date.day ==28)
date.last=-1;
}
break;
default:
cout<<" The program should not get into this code"<<endl;
break;
}
}// End checkLast function
// increment Function to calculate increment days respect to the user input
void increment(Date &date)
{
date.day= date.day + 1;
switch (date.month) {
case 1: case 3: case 5: case 7: case 8: case 10:
if (date.day > 31)
{
date.month++;
date.day= date.day- 31;
}
break;
case 4: case 6: case 9: case 11:
if (date.day > 30)
{
date.month++;
date.day= date.day- 30;
}
break;
case 2:
if ((date.year % 4 ==0 and date.year%100 !=0) or date.year%400==0 ){
if (date.day > 29){
date.month++;
date.day = date.day - 29;
}
}else {
if (date.day > 28){
date.month++;
date.day = date.day - 28;
}
}
break;
case 12 :
if (date.day > 31)
{
date.month = date.month - 11;;
date.year++;
date.day = date.day - 31;
}
break;
default:
cout<<"Program should not get into this error in increment Function!!!"<<endl;
break;
}
} // end increment Function
//setWeekDay function to calculate weekday
void setWeekDay(Date &date){
// find the algorithm here "https://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week"
int a = (14-date.month)/12;
int y = date.year-a;
int m = date.month+12*a-2;
date.weekday = (date.day + y + y/4 - y/100 + y/400 +(31 * m/12)) % 7;
}// end setWeekDay function
//setEvent function to set events related to their related events
void setEvent(Date &date,Event event[]){
date.event = "-";
string a;
for(int i=0 ; i<sizeof(event); i++){
if((date.day==event[i].day or event[i].day == 0 or event[i].day == date.last) and (date.month==event[i].month or event[i].month == 0) and (date.year==event[i].year or event[i].year == 0) and (date.weekday==event[i].weekday or event[i].weekday == 0)){
if(a.empty()){
date.event = event[i].event;
a = date.event;
continue;
}else{
date.event = event[i].event+","+ a;
a = date.event;
continue;
}
}
}
} // end of setEvent function
// outputDate function which use increment function to increment a date and also set event related to input date
void outputDate(Date &date)
{
cout<<setfill('0');
cout<<setw(2)<<date.day<<"."<<setw(2)<<date.month<<"."<<setw(4)<<date.year<<" "<<"[ "<<Day[date.weekday]<<" ]"<<" "<<date.event<<endl;
} // end of outputDate function
//setFirstWeekDay Function to find first day of the week related to given date
void setFirstWeekDay(Date &date){
switch (date.weekday) {
case 0:
for (int i = 1; i<7; i++)
decrement(date);
//date.day = date.day - 6;
break;
case 2:
decrement(date);
break;
case 3:
for (int i = 1; i<3; i++)
decrement(date);
break;
case 4:
for (int i = 1; i<4; i++)
decrement(date);
break;
case 5:
for (int i = 1; i<5; i++)
decrement(date);
break;
case 6:
for (int i = 1; i<6; i++)
decrement(date);
break;
default:
break;
}
}// end setFirstWeekDay Function
// Decrement Function to decrement days by one day
void decrement(Date &date)
{
date.day= date.day - 1;
switch (date.month) {
case 12: case 5: case 7: case 8: case 10:
if (date.day == 0)
{
date.month--;
date.day= 30;
}
break;
case 2: case 4: case 6: case 9: case 11:
if (date.day == 0 )
{
date.month--;
date.day= 31;
}
break;
case 3:
if ((date.year % 4 ==0 and date.year%100 !=0) or date.year%400==0 ){
if (date.day == 0){
date.month--;
date.day = 29;
}
}else {
if (date.day == 0 ){
date.month--;
date.day = 28;
}
}
break;
case 1 :
if (date.day == 0 )
{
date.month = date.month + 11;;
date.year--;
date.day = 31;
}
break;
default:
cout<<"Program should not get into this error in increment Function!!!"<<endl;
break;
}
} // end decrement Function
void readFile(vector<string> &data){
string line;
ifstream readFile("events.dat", ios::in);
if (!readFile) {
cerr<<"File COuld not be opened"<<endl;
exit(EXIT_FAILURE);
}
while (readFile && !readFile.eof()) {
getline(readFile,line);
//if (line.length() == 0 or line[0] == '#' )
data.push_back(line);
}
for(int i=0; i < data.size(); i++){
cout<<data[i];
}
}
this is how i have done till now,after that i want put data to event vector myhappening. Before that u would see i use normal event struct to initialize an array, but now i want to use file processing.
The difficulty is that your event structure uses int, and your format accepts special chars. If you can accept that * to be translated into 0 and the $ into -1, you could use the following function:
Event string_to_event (string s) {
static vector<string> wd{"*","Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
stringstream sst(s);
Event e;
string sday,smonth,syear,sweekday;
getline(getline (getline (getline(getline(sst,sday,'.'), smonth,'.'), syear,':'), sweekday, ':'), e.event);
e.day = sday.compare("*")==0 ? 0: (sday.compare("$")==0 ? -1 : stoi(sday));
e.month = smonth.compare("*")==0 ? 0: (smonth.compare("$")==0 ? -1 : stoi(smonth));
e.year = syear.compare("*")==0 ? 0: (syear.compare("$")==0 ? -1 : stoi(syear));
e.weekday = find(wd.begin(), wd.end(), sweekday)-wd.begin();
return e;
}
As you see it makes extensive use of stringstreams and getline().
If you can get rid of your intermediary data vector, you coud rewrite readLine() as follows:
void readFile(vector<Event> &data){
string line;
ifstream readFile("events.dat", ios::in);
if (!readFile) {
cerr<<"File COuld not be opened"<<endl;
exit(EXIT_FAILURE);
}
while (getline(readFile,line)) {
if (line.length() != 0 && line[0] != '#' && line[0] != '/') {
data.push_back(string_to_event(line));
}
}
}
If you need to keep your intermediate structure, you should correct your original reading function, by looping on getline() and not on eof() and use continue instead of break.
You could then use tranform() to apply the converstion function on the vector of strings:
vector<string> vs;
vector<Event> evt;
readFile(vs);
transform (vs.begin(), vs.end(), back_inserter(evt), string_to_event );
copy (evt.begin(), evt.end(), ostream_iterator<Event>(cout,"\n"));
I write this C++ program, destinated to reproduce the echo command :
#include <iostream>
#include <queue>
#include <string>
#include <iterator>
#include <unistd.h>
using namespace std;
int main(int argc, char *argv[])
{
//Step 1: convert a silly char*[] to queue<string>
queue<string> args;
for(int i=1;i<=argc;i++)
{
args.push(string(argv[i]));
}
//Step 2: Use this queue<string> (because a non-used variable, that's useless)
string arg, var, tos;
bool showEndl = true;
for(int i=0;i<=argc;i++) //The implementation of for arg in args is so crazy
{
arg = args.front(); //I can do arg = args[i] but that's not for nothing I make a queue. The cashier, she takes the customer front, she does not count the number of customers.
args.pop(); //Pop the arg
if(arg[0] == '$') //If that's a variable
{
var = ""; //Reset the variable 'var' to ''
for(string::iterator it=arg.begin();it!=arg.end();it++) //Because C++ is so complicated. In Python, that's just var = arg[1:]
{
var += *it;
}
tos += string(getenv(var.c_str()));
tos += ' ';
}
else if(arg == "-n") //Elif... No, C++ do not contains elif... Else if this is the -n argument.
{
showEndl = false;
}
else
{
tos += arg;
tos += ' ';
}
}
//Step 3 : Show the TO Show string. So easy.
cout << tos;
//Step 4 : Never forget the endl
if(showEndl)
{
cout << endl;
}
string a;
}
It compiles fine, but when I run it, it tells me "Segmentation fault: 11" in the console.
I use LLVM. What that means? Why that makes that?
PS : I use LLVM.
The segmentation fault is due to memory access violation - dereferencing invalid pointer:
for( int i = 1; i <= argc; i++)
{
args.push( string( argv[ i]));
}
When there are argc arguments sent to a program the last one is indexed with argc - 1.
for( int i = 0; i < argc; i++) // includes also a name of a program, argv[ 0]
{
args.push( string( argv[ i]));
}
or:
for( int i = 1; i < argc; i++) // excludes a name of a program, argv[ 0]
{
args.push( string( argv[ i]));
}
I suggest a use of debuger. It will show you the line causing a fault so you can investigate invalid pointer.
Change also to:
for( int i=0; i < args.size(); ++i)
{
arg = args.front();
i have this line taken from a txt file (first line in the file):
#operation=1(create circle and add to picture) name X Y radius.
why does this code doesnt take the integer 1 and puts it into k?
Circle Circle::CreateCirc(Circle c){
int k;
ifstream myfile("cmd.txt");
if (!myfile.is_open())
cout<<"Unable to open the requested file "<<endl;
string line,line2="create circle";
for (int i=1;i<countrows();i++)
{
getline(myfile,line);
if (line.find(line2)!=string::npos)
{
istringstream ss(line);
ss>>k;
cout<<k<<endl;
}
}
return c;
}
instead im getting adress memory...help plz
Because the line doesn't start with a number. You'll need to skip over the #operation= part before extracting a number.
You should check the result of the extraction, and of getline, to help identify what's going wrong when these fail.
Also, if countrows() returns the expected number of rows in the file, then your loop would miss out the last one. Either loop from zero, or while i <= countrows(); or, if you want to process every line in the file, you could simply loop while (getline(myfile,line)).
If the actual text in the file you try to read starts with "#operation=1" and you want the number 1 from that, you can't use the simple input operator. It will read the character '#' first, which isn't a digit and so the parsing will fail and k will not be initialized. And if k is not initialized, it will be of indeterminate value, and reading that value will lead to undefined behavior and seemingly random output.
You need to check that the extraction worked:
if (ss >> k)
std::cout << k << '\n';
That won't solve your problem though, as like I said above, you can't use the simple input operator here. You need to parse the string using other methods. One way might be to find the equal character '=' and get a sub-string after that to try and extract the number.
try this:
Circle Circle::CreateCirc(Circle c){
const std::streamsize ALL = std::numeric_limits< std::streamsize >::max(); // #include <limits> needed
int k;
ifstream myfile("cmd.txt");
if (!myfile.is_open())
cout<<"Unable to open the requested file "<<endl;
for (int i=1;i<countrows(); ++i, myfile.ignore(ALL,'\n') ) // skip rest of the line
{
if( myfile.ignore(ALL,'=') >> k )
{
cout<<k<<endl;
}
else
break; // read error
}
return c;
}
EDIT: A way to do it not much bit a little closer to the way you were trying to do it using atoi() rather than streams.
#include <iostream>
#include <cstdlib> // for atoi()
int main(){
std::string str = "#operation=1(create circle and add to picture) name X Y radius.";
int k;
std::string line=str, line2="(create circle";
std::size_t fnd = line.find(line2);
if (fnd!=std::string::npos)
{
k = atoi(&str[fnd-1]); // int atoi(const char *str) == argument to integer
std::cout<< k << " " << str[fnd-1] << str[fnd] << " ";
}
}
There are a few ways to extract an integer from a string but i like to filter out the digit from the string;
#include <iostream>
int main(){
std::string str = "#operation=1(create circle and add to picture) name X Y radius.";
int k = 0;
// an array of our base10 digits to filter through and compare
const char digit[] = {'0','1','2','3','4','5','6','7','8','9'};
for(int s_filter = 0; s_filter<str.size(); ++s_filter){
for(int d_filter = 0; d_filter<10; ++d_filter){
// filter through each char in string and
// also filter through each digit before the next char
if(digit[d_filter] == str[s_filter]) {
// if so the char is equal to one of our digits
k = d_filter;// and d_filter is equal to our digit
break;
} else continue;
}
}
switch(k) {
case 1:
std::cout<< "k == 1";
// do stuff for operation 1..
return 0;
case 2:
std::cout<< "k != 1";
// do more stuff
break;
//case 3: ..etc.. etc..
default:
std::cout<< "not a digit";
return 1;
}
}
// find_num.cpp (cX) 2015 adolfo.dimare#gmail.com
// http://stackoverflow.com/questions/21115457/
#include <string> // std::string
#include <cctype> // isnum
/// Find the number in 'str' starting at position 'pos'.
/// Returns the position of the first digit of the number.
/// Returns std::string::npos when no further numbers appear within 'str'.
/// Returns std::string::npos when 'pos >= str.length()'.
size_t find_num( const std::string str, size_t pos ) {
size_t len = str.length();
bool isNegative = false;
while ( pos < len ) {
if ( isdigit(str[pos]) ) {
return ( isNegative ? pos-1 : pos );
}
else if ( str[pos]=='-' ) {
isNegative = true;
}
else {
isNegative = false;
}
++pos;
}
return std::string::npos;
}
#include <cassert> // assert()
#include <cstring> // strlen();
int main() {
std::string str;
str = "";
assert( std::string::npos == find_num( str, 0 ) );
assert( std::string::npos == find_num( str, 9 ) );
str = "#operation=1(create circle and add to picture) name X Y radius.";
assert( strlen("#operation=") == find_num( str, 0 ) );
str = "abcd 111 xyx 12.33 alpha 345.12e-23";
/// 0123456789.123456789.123456789.123456789.
assert( 5 == find_num( str, 0 ) );
assert( 13 == find_num( str, 5+3 ) );
assert( 25 == find_num( str, 20 ) );
str = "abcd-111 xyx-12.33 alpha-345.12e-23";
/// 0123456789.123456789.123456789.123456789.
assert( 4 == find_num( str, 0 ) );
assert( 12 == find_num( str, 5+3 ) );
assert( 24 == find_num( str, 20 ) );
str = "-1";
assert( 0 == find_num( str, 0 ) );
assert( 1 == find_num( str, 1 ) );
assert( std::string::npos == find_num( str, 2 ) );
assert( std::string::npos == find_num( str, strlen("-1") ) );
return 0;
}
I'm trying to create a subject pre-requisite checker using linked list. I know how to insert single data into a node.
My problem is how to insert multiple data into a node? I found a good example which fits my assignment perfectly. But the problem is I do not understand C very much. Can any one help to explain the void add() function below? I want to use that add function to my assignment.
#include <stdio.h>
#include <conio.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
struct node
{
char data [ 20 ];
char m [ 5 ] [ 20 ];
int mcount;
struct node * link;
};
struct node * dic [ 26 ];
void add ( char * );
int search ( char * );
void show( );
void deldic( );
void main( )
{
char word [ 20 ] , ch;
int i;
clrscr( );
while ( 1 )
{
clrscr( );
printf ( "\n\t\tDictionary\n" );
printf ( "\n\t\t1.Add Word.\n" );
printf ( "\t\t2.Search Word.\n" );
printf ( "\t\t3.Show Dictionary.\n" );
printf ( "\t\t0.Exit." );
printf ( "\n\n\t\tYour Choice ");
scanf ( "%d", &ch );
switch ( ch )
{
case 1 :
printf ( "\nEnter any word : " );
fflush ( stdin );
gets ( word );
add ( word );
break;
case 2 :
printf ( "\nEnter the word to search : " );
fflush ( stdin );
gets ( word );
i = search ( word );
if ( ! i )
printf ( "Word does not exists." );
getch( );
break;
case 3 :
show( );
getch( );
break;
case 0 :
deldic( );
exit ( 0 );
default :
printf ( "\nWrong Choice" );
}
}
}
void add ( char * str )
{
int i, j = toupper ( str [ 0 ] ) - 65;
struct node * r, * temp = dic [ j ], * q;
char mean [ 5 ] [ 20 ], ch = 'y';
i = search ( str );
if ( i )
{
printf ( "\nWord already exists." );
getch( );
return;
}
q = ( struct node * ) malloc ( sizeof ( struct node ) );
strcpy ( q -> data, str );
q -> link = NULL;
for ( i = 0; tolower ( ch ) == 'y' && i < 5; i++ )
{
fflush ( stdin );
printf ( "\n\nEnter the meaning(s) : " );
gets ( mean [ i ] );
strcpy ( q -> m [ i ] , mean [ i ] );
if ( i != 4 )
printf ( "\nAdd more meanings (y/n) " );
else
printf ( "You cannot enter more than 5 meanings." );
fflush ( stdin );
ch = getche( );
}
q -> mcount = i;
if ( dic [ j ] == NULL || strcmp ( dic [ j ] -> data, str ) > 0 )
{
r = dic [ j ];
dic [ j ] = q;
q -> link = r;
return;
}
else
{
while ( temp != NULL )
{
if ( ( strcmp ( temp -> data, str ) < 0 ) && ( ( strcmp ( temp -> link -> data, str ) > 0 ) ||
temp -> link == NULL ) )
{
q -> link = temp -> link;
temp -> link = q;
return;
}
temp = temp -> link;
}
}
}
Here is my assignment so far
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
struct subjectlist
{
string subject;
string prereq;
subjectlist *next;
};
subjectlist *start_prt=NULL;
subjectlist *current;
int option=0;
int main ()
{
int x;
string subject;
cout << "1. Add subject" << endl;
cout << "2. Search prerequisite" << endl;
cout << "3. Delete subject" << endl;
cout << "4.Show subjects" << endl;
cout << "5. Save to file" << endl;
cout << "6. Load from file" << endl;
cout << "0. Exit" << endl;
cin >> x;
switch (x)
{
case 1:
cout<<"Input subject"<<endl;
cin >> subject;
add(subject);
break;
case 2:
cout<<"Input subject to be checked"<<endl;
break;
case 3:
cout<<"Delete a subject"<<endl;
break;
case 4:
cout<<"Show Subjects"<<endl;
break;
case 5:
cout<<"Save to File"<<endl;
break;
case 6:
cout<<"Load from file"<<endl;
break;
case 0:
cout<<"exit"<<endl;
break;
default: cout <<"Invalid selection, please try again."<<endl;
}
}
void add ()
{
}
The add() function adds node to list. But before adding node to list, it checks whether the data in node is already present in list?
i = search ( str );
if ( i )
This checks for duplicate data.
If data is already present in list, node is not inserted in list.
If data is not present in list, it moves further.
for ( i = 0; tolower ( ch ) == 'y' && i < 5; i++ )
This for loop accepts meaning (string) in array and only 5 meanings can be added per node.
Also node is added to list in such a way that list will be in sorted form.
Since you are working with c++, a language, what supports object oriented programming, why not use this feature?
First you could create your data structure, what contains all the useful items, you want to store. You could also write an operator== what makes MUCH clearer to compare two Data objects:
struct Data
{
char data [20];
char m [5][20];
int mcount;
bool operator==(const Data& other)const
{
//probably you need more comparisons
return mcount==other.mcount;
}
};
Then you could create a Node class, what holds one of your Data objects, and a pointer to the next (maybe to the previous) item.
struct Node
{
Data data;
Node * next;
//Node * previous;
}
After you got this, you could just create your own linked list class:
class MyLinkedList
{
Node * head;
public:
MyLinkedList(){//initialization steps}
~MyLinkedList(){ //Delete the list}
void add(Data item)
{
if(!contains(item))
{
//append it
}
}
bool contains(Data item){ //... check if the list already contains item}
//create a string representation of the object.
//If you dont like this style, you could also provide
//an operator>> or operator<< for the class
std::string toString()
{
std::stringstream stream;
//iterate through the list, and add elements with
return stream.str();
}
};
If you got this, then in your main() it would look much clearer, what you want:
MyLinkedList list;
Data data; //somehow fill it
//adding items
list.add(data);
//printing the list
cout<<list.toString();
//after it goes out of scope the destructor will be called,
//so you dont need to bother with the deletion.