Related
I'm a beginner in c++ and I'm training on exercises.
I'm stuck on one part. I would like to insert the string "CH" in front of each vowel in a sentence.
I first tried using string::replace, but it was not the best idea.
I would like to use string::insert to do this.
However, I can't seem to use it properly in a loop to tell it that the [i] is the desired position
Do you have any advice for me?
string message = "you have a secret message to decrypt";
string newMessage = "";
string InsertMessage = "CH";
for (int i = 0; i < message.length(); i++) {
if (
message[i] == 'a' ||
message[i] == 'e' ||
message[i] == 'i' ||
message[i] == 'o' ||
message[i] == 'u' ||
message[i] == 'y')
{
//newMessage = message.replace(i, 1, InsertMessage);
newMessage = message.insert(i, InsertMessage);
}
}
cout << newMessage << endl;
return 0;
This statement
newMessage = message.insert(i, InsertMessage);
does not make a sense at least because it changes the original string message.
I can suggest the following approach shown in the demonstration program below.
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
int main()
{
std::string message = "you have a secret message to decrypt";
std::string newMessage;
std::string InsertMessage = "CH";
const char *vowels = "aeiouy";
auto n = std::count_if( std::begin( message ), std::end( message ),
[vowels]( const auto &c ) { return std::strchr( vowels, c ); } );
newMessage.resize( message.size() + n * InsertMessage.size() );
std::string::size_type pos = 0;
do
{
auto i = message.find_first_of( vowels, pos );
if (i == std::string::npos)
{
newMessage += message.substr( pos );
pos = i;
}
else
{
newMessage += message.substr( pos, i - pos );
newMessage += InsertMessage;
pos = i;
newMessage += message[pos++];
}
} while( pos != std::string::npos );
std::cout << newMessage << '\n';
}
The program output is
CHyCHoCHu hCHavCHe CHa sCHecrCHet mCHessCHagCHe tCHo dCHecrCHypt
Thanks for your answers, I'll work on it :)
I need to write a program that uses a stack to verify if a string expression is balanced, in regards to the parenthesis, brackets, and curly braces contained in it. The string's are to be inputted by the user, and all errors (i.e. mismatched parenthesis, brackets, and curly braces) need to be pointed out by a caret on the next line, directly under it, like this:
(a bit hard to show here...)
(()
^
In my "balanced" function, I am taking the current index of the loop, and assigning it to either "unmatchedRightPosition" or "unmatchedLeftPosition," whichever one is needed, at the time. I think that a lot of my program works already, but I'm having problems with placing the carets under the errors. My professor suggested that I may choose to use a stack class that holds structs, where each struct contains both a char and the char's position, but I am a bit puzzled by that.
Thanks for looking
#include <iostream>
#include <string>
#include <stdlib.h>
#include <sstream>
using namespace std;
struct Stack{
static const unsigned MAX_SIZE = 5;
char data[ MAX_SIZE ];
unsigned size;
};
struct Stack2{
unsigned unmatchedLeftPos, unmatchedRightPos;
};
void initialize( Stack & stack );
void show( const Stack & stack );
unsigned getSize( const Stack & stack );
void push( Stack & stack, char c );
char pop( Stack & stack );
char top( const Stack & stack );
bool die( const string & msg );
bool balanced (unsigned & unmatchedLeftPos, unsigned & unmatchedRightPos, const string & expr);
int main(){
Stack2 s2;
cout << "\nPlease enter your expression - enter a blank line to quit. \n";
for(;;){
string line;
getline(cin, line);
if( line.size() == 0 ) break;
if (balanced(s2.unmatchedLeftPos, s2.unmatchedRightPos, line) == 1){
cout << "OK\n";
}
else if (balanced(s2.unmatchedLeftPos, s2.unmatchedRightPos, line) == 0){
cout << string(s2.unmatchedLeftPos, ' ') << '^';
cout << string(s2.unmatchedRightPos, ' ') << '^';
}
}
return 0;
}
void initialize( Stack & stack ){
stack.size = 0;
}
void show( const Stack & stack ){
cout <<"[" << stack.size <<"]:";
for( unsigned i = 0; i < stack.size; i++ )
cout <<stack.data[i];
cout <<endl;
} // show
unsigned getSize( const Stack & stack ) {return stack.size;}
void push( Stack & stack, char c ){
if( stack.size == Stack::MAX_SIZE ) die( "push: overflow" );
stack.data[stack.size++] = c;
} // push
char pop( Stack & stack ){
if( stack.size == 0 ) die( "pop: underflow" );
return stack.data[--stack.size];
} // pop
char top( const Stack & stack ){
if( stack.size == 0 ) die( "top: underflow" );
return stack.data[stack.size-1];
} // pop
bool die( const string & msg ){
cerr <<endl <<"Fatal error: " << msg <<endl;
exit( EXIT_FAILURE );
}
bool balanced (unsigned & unmatchedLeftPos, unsigned & unmatchedRightPos, const string & expr){
Stack s;
initialize(s);
unsigned i;
for (i = 0; i < expr.size(); i++){
char c = expr[i];
if( expr.size() == Stack::MAX_SIZE) {
die( "push: overflow" );
}
if (c == '(')
{
push(s, c);
}
else if (c == '['){
push(s, c);
}
else if (c == '{'){
push(s, c);
}
if (s.size == 0 && (c == ')' || c == ']' || c == '}'))
{
unmatchedRightPos = i;
return false;
}
else if (c == ')' && top(s) == '('){
pop(s);
}
else if (c == ']' && top(s) == '['){
pop(s);
}
else if (c == '}' && top(s) == '{'){
pop(s);
}
}
if (s.size == 0){
return true;
}
else if (top(s) == '(' || top(s) == '[' || top(s) == '{'){
unmatchedLeftPos = i;
return false;
}
}
You are currently using stack, with an array of characters:
char data[ MAX_SIZE ];
Instead, you would go for a struct, that holds both character and position in the input string
struct info {
char data;
int pos;
};
info data[ MAX_SIZE ];
So at the end, you just check your stack, and in addition to invalid characters, you also have the position in the input string.
Hope that helps.
You can move your main to the bottom to avoid forward function declarations. You also don't need to use another stack for the errors (actually I think it's easier if you don't). You just need to hold both the bracket and its position on a single stack, i.e.
struct Item
{
char bracket;
size_t position;
}
std::stack<Item> st;
As well as either an array or, better a string initialized to the same length as the input string with all spaces which you change to '^' upon encountering an error, i.e.
std::string errorString(input.size(), ' ');
if ( /* brackets don't match */ )
{
errorString[st.top().position] = '^';
}
In case you cannot use STL stack, you need to modify your own to hold Item objects instead of char (i.e. Item data[ MAX_SIZE ];). Your code looks very much like C thought and it would be better if you made use of std::string and std::stack instead.
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;
}
My assignment is to read from a gradbook text file and average every students' program, midterm and final scores, as well as the student ID and the first and last name. So far, code is able to compile and calculates the scores appropriately, but it won't read the studentID and first and last name.
I'm pretty sure the reason why is that the currentStudent variable in main() doesn't have any parameters and makes the constructor use default values. But I'm not sure how to give currentStudent values from class Student while in main(). My best idea for a solution is to move everything from ReadData into main(), but from the description of ReadData from my assignment, I think I have everything I need in there:
"A method called ReadData(istream&) which reads the Student's data. It reads the ID number (integer), first and last names (strings) in that order, the 10 program scores (all integers) and the midterm and exam scores (also integers). It returns true if all data was read successfully, otherwise false"
I'm sorry for the long-winded description, I'm just seeing if I can effectively explain my situation. Any help or advice would be greatly appreciated.
I've only included the class definition, constructor, ReadData, and main below because everything else is just equations and get/sets that I'm pretty sure all work, and I'm trying to lessen what you lovely people would have to read through. If anyone would like to see the full code, I'll post the rest.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class Student
{
private:
int studentID;
string firstName,
lastName;
int score[ 10 ];
int midterm, final;
public:
Student ( int, string, string );
bool ReadData ( istream& );
//fstream WriteData ( ostream& ); // I need to clear up with professor first
void setStudentID ( int );
void setFirstName ( string );
void setLastName ( string );
void setMidterm ( int );
void setFinal (int );
const int getStudentID ( );
const string getFirstName ( );
const string getLastName ( );
const int getMidterm ( );
const int getFinal ( );
void setProgramScore ( int, int[ ] );
int getProgramScore ( int );
const double ProgramAvg( );
const double CourseAvg( );
~Student( );
};
Student::Student ( int id = 0, string f = "", string l = "" )
{
setStudentID ( id );
setFirstName ( f );
setLastName ( l );
};
bool Student::ReadData( istream &readStudent )
{
int id;
string first, last;
int x[ 10 ], mid, fin;
readStudent >> id >> first >> last;
for ( int i = 0; i <= 10 - 1; i++ )
{
readStudent >> x [ i ];
setProgramScore( i, x );
}
readStudent >> mid >> fin;
Student studentInfo ( id, first, last );
setMidterm( mid );
setFinal( fin );
if ( readStudent.good( ) )
return true;
else
return false;
};
// getters, setters and calculations in between
int main( )
{
ifstream readStudent;
int lineCount = 0;
double totalProgramAvg = 0
, totalFinalAvg = 0
, totalCourseAvg = 0;
Student currentStudent;
readStudent.open ( "gradebook.txt" );
if ( readStudent.is_open ( ) )
{
while ( currentStudent.ReadData ( readStudent ) == true )
{
totalProgramAvg += currentStudent.ProgramAvg();
totalFinalAvg += currentStudent.getFinal();
totalCourseAvg += currentStudent.CourseAvg();
cout << currentStudent.getStudentID() << " "
<< currentStudent.getFirstName() << " "
<< currentStudent.getLastName() << " ";
for ( int j = 0; j < 10; j++ )
cout << currentStudent.getProgramScore( j ) << " ";
cout << currentStudent.getMidterm() << " "
<< currentStudent.getFinal() << endl;
cout << totalProgramAvg << " " << totalCourseAvg << endl;
lineCount++;
};
readStudent.close( );
cout << lineCount << endl << totalProgramAvg / lineCount << "\n" << totalFinalAvg / lineCount << "\n" << totalCourseAvg / lineCount;
system ("pause");
};
};
bool Student::ReadData( istream &readStudent )
{
int id;
string first, last;
int x[ 10 ], mid, fin;
readStudent >> id >> first >> last;
for ( int i = 0; i <= 10 - 1; i++ )
{
readStudent >> x [ i ];
setProgramScore( i, x );
}
readStudent >> mid >> fin;
Student studentInfo ( id, first, last );
setMidterm( mid );
setFinal( fin );
if ( readStudent.good( ) )
return true;
else
return false;
}; //what?
I haven't checked the rest of your code, but this is certainly erroneous.
You shouldn't be declaring a new item Student studentInfo( id, first, last); You're creating a new item that just dies when the function returns. Instead, you should use id,first,last to modify a current object member you're in, this. You have declared items for this in your class header but then declare local scope variables, use them, create a new student with it, and then all are destroyed when the function returns and they go out of scope. Simply delete/add things where I mark appropriate from the function to get
bool Student::ReadData( istream &readStudent )
{
int x[ 10 ], mid, fin; //if it ain't broke, don't fix it
readStudent >> studentID >> firstName >> lastName; //use your class members that you want to hold that data.
for ( int i = 0; i <= 10 - 1; i++ )
{
readStudent >> x [ i ];
setProgramScore( i, x );
}
readStudent >> mid >> fin;
setMidterm( mid );
setFinal( fin );
if ( readStudent.good( ) )
return true;
else
return false;
}
You can directly access class members in the class function Student::ReadData( istream &readStudent) and you should just do it for all of them but you said the score system was working so I left that alone.
Finally, ; goes after } if it's like a struct, or a class, or a bunch of stuff I don't know, but not a function definition.
Okay, I see another bug /flaw in your project flow:
while ( currentStudent.ReadData ( readStudent ) == true ) { /*stuff*/ } is not going to work right. Your ReadData function is going to read in all the data for your current student, but the while loop is also going to try to do that. I can't fathom the result but it will be ugly no doubt. Your better to use it like this:
if(!(currentStudent.ReadData( readStudent)) {
//Ooops, I failed, what do I do?
}
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.