Ending multi-line user input?

Cannot safely end multi-line user input from stdio.

Page 1 of 1

6 Replies - 4806 Views - Last Post: 24 September 2010 - 03:06 AM Rate Topic: -----

#1 Tracekill  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 15
  • Joined: 17-January 09

Ending multi-line user input?

Posted 24 September 2010 - 12:12 AM

Hey all, having a bit of a problem with a recent project. The goal here is to be able to input several lines of text containing a date in mm/dd/yyyy format followed by a whitespace and then a description of the event. I've accomplished actually allowing for multiple lines of text input (I think), but now I'm not exactly sure how to stop it. Is there a way to simply assume after a set amount of time, perhaps, that the user is done inputting? This problem is stressing me a lot as they never really addressed how to end user input, only how to accomplish multiple lines. We have to use the standard user input, not from text files which would be so much easier. Code below, please feel free to also tell me if I've made an unnoticed mistake elsewhere. I just need to be able to let the user finish the input so the program can re-order the events[] and output them.

calendar.cpp

#include <string>
#include <sstream>
#include <iostream>
#include <vector>

using namespace std;
#include "event.h"


int main(){
 // Maximum number of input lines
 const int MAX = 100; 

 // Array of pointers to events 
 Event *events[MAX];

 // Number of currently used pointers in events
 int size = 0;
 int i = 0;

 // Vector containing each input line as a string
 vector<string> vec (100);
 char temps[100];
 while(i < MAX){
  cin.getline(temps, 100);
  vec[i] = temps; 
  i++;
 }


 for(int i = 0; i < vec.size(); i ++){
   int found = vec[i].find("/");
   int tmo = atoi(vec[i].substr(0, found).c_str());
   int sfound = vec[i].find("/", found + 1, 6);
   int tda = atoi(vec[i].substr(found + 1, sfound - (found + 1)).c_str());
   int tye = atoi(vec[i].substr(sfound + 1, 4).c_str());
   string tdes = vec[i].substr(sfound + 6, vec[i].length() - (sfound + 6));
   events[size] = new Event(tmo, tda, tye, tdes);
   size++;
 }

 return 0;
}



event.cpp

#include <iostream>
#include <string>

using namespace std;
#include "event.h"

Event::Event(int mo, int da, int ye, string des){
 month = mo;
 day = da;
 year = ye;
 desc = des;
}

Event::~Event(){

}

void Event::print(){
 cout << month << "/" << day << "/" << year << " " << desc << endl;
}


event.h

#ifndef EVENT_H
#define EVENT_H

#include <iostream>
#include <string>
using namespace std;

class Event{
 public:
  Event(int mo, int da, int ye, string des);
  ~Event();
  void print();
 private:
  int month;
  int day;
  int year;
  string desc;
};

#endif


Thank you in advance for your help, gentlemen.

Is This A Good Question/Topic? 0
  • +

Replies To: Ending multi-line user input?

#2 janotte  Icon User is offline

  • code > sword
  • member icon

Reputation: 990
  • View blog
  • Posts: 5,141
  • Joined: 28-September 06

Re: Ending multi-line user input?

Posted 24 September 2010 - 12:34 AM

Your question is a bit fuzzy to me so maybe I am missing the point?
Could you have the user give you a sentinel value to tell you they have completed data entry?

As I say I don't really know what you are trying to ask us.
Was This Post Helpful? 0
  • +
  • -

#3 Guest_Tracekill*


Reputation:

Re: Ending multi-line user input?

Posted 24 September 2010 - 12:44 AM

View Postjanotte, on 23 September 2010 - 11:34 PM, said:

Your question is a bit fuzzy to me so maybe I am missing the point?
Could you have the user give you a sentinel value to tell you they have completed data entry?

As I say I don't really know what you are trying to ask us.


I apologize for the vagueness. Basically, the user must be allowed to enter multiple lines of text in the format:

mm/dd/yyyy event description
mm/dd/yyyy event description
mm/dd/yyyy event description

My issue is that, though I have allowed the user to enter multiple lines of input, I cannot figure out how to terminate that input without a delimiting character. I cannot use a delimiting character because the program will be tested using the Linux "diff" function and a test file containing parameters of exactly that aforementioned format. I've since tried to remedy the problem by changing my while loop to:

while((i < MAX) && (!cin.eof())){
		cin.getline(temps, 100, '\n');
		vec[i] = temps; 
		i++;
	}

and then typing Ctrl + D in the command line to insert an EOF marker but it still fails to terminate the input.
Was This Post Helpful? 0

#4 janotte  Icon User is offline

  • code > sword
  • member icon

Reputation: 990
  • View blog
  • Posts: 5,141
  • Joined: 28-September 06

Re: Ending multi-line user input?

Posted 24 September 2010 - 12:53 AM

Why a C character array here?
char temps[100]

You are writing in C++.
Why not make use of the string class?
Why expose yourself to buffer overruns and all the headaches of nasty fixed length arrays when you have 'real' strings available?

----
Could you simply keep looping until the input string is either blank or is not in the right format?
That would mean a press of the return key should end the collection.
Again I am not 100% sure I am getting your question right - could well be me, not you.

EDIT - Note to self USE CODE TAGS CORRECTLY!!
Just to be clear for those with sense of humour bypasses - this is me talking to me

This post has been edited by janotte: 24 September 2010 - 12:55 AM

Was This Post Helpful? 0
  • +
  • -

#5 Tracekill  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 15
  • Joined: 17-January 09

Re: Ending multi-line user input?

Posted 24 September 2010 - 01:09 AM

View Postjanotte, on 23 September 2010 - 11:53 PM, said:

Why a C character array here?
char temps[100]

You are writing in C++.
Why not make use of the string class?
Why expose yourself to buffer overruns and all the headaches of nasty fixed length arrays when you have 'real' strings available?

----
Could you simply keep looping until the input string is either blank or is not in the right format?
That would mean a press of the return key should end the collection.
Again I am not 100% sure I am getting your question right - could well be me, not you.

EDIT - Note to self USE CODE TAGS CORRECTLY!!
Just to be clear for those with sense of humour bypasses - this is me talking to me


Normally I would, lord knows I'd prefer a nice clean string over a messy char[], but for some reason the VCC compiler gave me issues about using a string as a parameter for cin.getline().

However, the issue seems to have fixed itself, while creating a whole new issue. Using a step-through debugger (most useful technology ever), I see that it actually is recognizing the EOF character of Ctrl + Z (^Z) and terminating the multi-line input. And proceeds to the beginning of my for loop:

for(int i = 0; i < vec.size(); i ++){
			int found = vec[i].find("/");
			int tmo = atoi(vec[i].substr(0, found).c_str());
			int sfound = vec[i].find("/", found + 1, 6);
			int tda = atoi(vec[i].substr(found + 1, sfound - (found + 1)).c_str());
			int tye = atoi(vec[i].substr(sfound + 1, 4).c_str());
			string tdes = vec[i].substr(sfound + 6, vec[i].length() - (sfound + 6));
			events[size] = new Event(tmo, tda, tye, tdes);
			size++;
	}


but then promptly fails with an error of:

-		_Message	0x0086ed9c "invalid string position"	const char *


I have a feeling, I've made a mistake in that messy jumble that is the body of the loop. Do you notice any problems that might arise at runtime? To clarify, the purpose of this for loop is to iterate through each string in the vector "vec" and extract the data relevant to the creation of an Event object (int month, int day, int year, string desc). Is there an easier way to accomplish this than the one I have found? If you would like me to more carefully document the code and explain the logic, I'd be happy to. I'm sorry for getting off topic and really do appreciate all of your help, especially at this late hour (assuming you're from the states).
Was This Post Helpful? 0
  • +
  • -

#6 janotte  Icon User is offline

  • code > sword
  • member icon

Reputation: 990
  • View blog
  • Posts: 5,141
  • Joined: 28-September 06

Re: Ending multi-line user input?

Posted 24 September 2010 - 01:23 AM

View PostTracekill, on 24 September 2010 - 05:09 PM, said:

Normally I would, lord knows I'd prefer a nice clean string over a messy char[], but for some reason the VCC compiler gave me issues about using a string as a parameter for cin.getline().

Try making temps a C++ string and use this line in place your problematic cin.getline() call.
  getline(cin, temps);


Try that before we debug too much further.
Doubt it will fix your problem but it might and it's definitely better than the nasty C-string.

EDIT- Sorry may have skipped the obvious that you may need to rewrite your string manipulations to C++ in that messy loop. Not sure, haven't looked at that too closely.

This post has been edited by janotte: 24 September 2010 - 01:28 AM

Was This Post Helpful? 0
  • +
  • -

#7 janotte  Icon User is offline

  • code > sword
  • member icon

Reputation: 990
  • View blog
  • Posts: 5,141
  • Joined: 28-September 06

Re: Ending multi-line user input?

Posted 24 September 2010 - 03:06 AM

I got bored so knocked out a little bit of rough code to give you the idea of another way to go about handling the parsing if the strings in the vector into arguments for your class constructor.

This compiles but has not been tested so beware of horrible bugs with big gnashing teeth.

I hope it give you an idea of how parsing through the string can give you lots of opportunities for handling bad input errors. Not my best work by a long shot but hope it might give you an idea of a very different way of going about the challenge you have. Not necessarily better. I am of the 'defensive code is good code school' so I think providing more error handling is better but not all would agree with me.
Anyway - for whatever it is worth

#include <string>
#include <sstream>
#include <iostream>
#include <vector>

using namespace std;
// #include "event.h"


int main(){
	 // Maximum number of input lines
	 const int MAX = 100; 

	 // Array of pointers to events 
	 // Event *events[MAX];

	 // Number of currently used pointers in events
	 int size = 0;
	 int i = 0;

	 // Vector containing each input line as a string
	 vector<string> vec (MAX);
	 string temps;
	 while(i < MAX){
	  getline(cin, temps);
	  vec[i] = temps; 
	  i++;
	 }

	// process the vector we just built
	 for(size_t vecCount = 0; vecCount < vec.size(); vecCount++){
		int  	slashFoundCount = 0;
		bool 	spaceSeparatorFound = false;
		string 	eventDescription,
		       	strMonth,
			   	strDay,
				strYear;
		// grab the current vector element as a working variable
		string strTemp = vec[vecCount];
		
		for(size_t strPos=0; strPos<strTemp.length(); strPos++){
			if(slashFoundCount > 1 && spaceSeparatorFound){
				// all the special characters have been found.
				// you are now in the description so grab everything until
				//    the end of the string and jam it in the description
				// let the substr() function handle the fact the requested 
				//    sub string is too long - make it work for it's living
				eventDescription = strTemp.substr(strPos, strTemp.length());
				break;
			}
			
			// handle date slashes
			if(strTemp[strPos] == '/'){
				if(slashFoundCount < 2){
					slashFoundCount++;
					continue;
				}else{
					// you seem to have too many slashes
					//   do you want to throw an error?
				}
			}
		
			// handle spaces 
			if(strTemp[strPos] != ' '){
				// if before second date slash ignore it
				//   this assumes you want to ignore space in dates
				//   if you don't then you have found an error
				//     what will you about the error?
				if(slashFoundCount < 2){
					continue;
				// if found both slashes and not yet found space separator mark
				//   the fact you found the separator
				}else if(!spaceSeparatorFound){
					spaceSeparatorFound = true;
					continue;
				}
			}
		
			if(slashFoundCount == 0){
				// digits before the first slash are months (damn yankee date system)
				if(isdigit(strTemp[strPos])){
					strMonth.push_back(strTemp[strPos]);
					continue;
				}else{
					// you have founf a char which is not a slash, not a space and
					//   not a digit before the first slash
					//   Should you throw an error?
					// Because I don't know I what you want to do I am just ignoring it
					continue;
				}
			}else if(slashFoundCount == 1){
				// digits after the first slash and before the second slash are
				//    days (damn yankee date system)
				if(isdigit(strTemp[strPos])){
					strDay.push_back(strTemp[strPos]);
					continue;
				}else{
					// you have found a char which is not a slash, not a space and
					//   not a digit between the two slashes
					//   Should you throw an error?
					// Because I don't know I what you want to do I am just ignoring it
					continue;
				}
			}else if(slashFoundCount == 2 && !spaceSeparatorFound){
				// digits after the second slash and before the space separator are
				//    years
				if(isdigit(strTemp[strPos])){
					strYear.push_back(strTemp[strPos]);
					continue;
				}else{
					// you have found a char which is not a slash, not a space and
					//   not a digit between the second slash and the space separator
					//   Should you throw an error?
					// Because I don't know I what you want to do I am just ignoring it
					continue;
				}	
			}
		}// end string loop
		
		// test the strings you have built
		if(strMonth.length() < 1 || strMonth.length() > 2){
			// got a bad month
			// what will you do?
		}
		if(strDay.length() < 1 || strDay.length() > 2){
			// got a bad day
			// what will you do?
		}
		if(strYear.length() != 4){
			// got a bad year
			// what will you do?
		}
	
	
		// TODO
		// USE A STRINGSTREAM TO CONVERT THE STRING VALUES OF NUMBERS INTO INTS
		// TEST THAT THEY ARE GOOD VALUES (e.g. Month is 1 to 12)
		// ASSIGN TO A NEW INSTANTIATION OF EVENT
		size++;

	 }// end vector loop

 return 0;
}


Was This Post Helpful? 0
  • +
  • -

Page 1 of 1