• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 645
  • Last Modified:

Delete and Insert a line into C++ buffer

Hi all, I am writing a program in c++ to try and learn the re-language and I have hit a road block.

I have the following code that asks me to input a filename, it then loads the contents of that file into a buffer. I can then preview the contents of the buffer and save it as a different filename if I want.

What I am after is a way to insert a new line into the buffer and also delete.

In the terms of inserting a new line. I will enter the line number I wish to overwrite. I will then type in the new line contents., and it will overwrite the version stored in the buffer, and if i am happy with the change - i can save it to the file.

Same thing with delete, but I think I would need to re-write the buffer's contents as follows:
   Delete line 5
   Write lines 1 - 4 into temp buffer ...
   exclude line 5
   write lines 5 -> EOF into temp buffer then copy the contents of the temp buffer into the actual buffer and delete temp buffers contents.

Any help would be greatly appreciated.

#include <iostream>
#include <string>
#include <iomanip>
#include <cstdlib>  
#include <fstream> 
#include <stdio.h>
#include <cctype>

using namespace std;


int main(void) {
	system("cls");  // Clear the terminal window prior to running the application in Linux
        
	// Variables
	  	char 	exit;
		char	buffer[5000];

		// File specific variables
		string filename, line, inputFile;
		
		// Initialize the buffer by filling it with zeros		
		fill_n(buffer, 5000, '\0');		
		

		system("cls");

			case '1': {
				system("cls");
						
				// Clear the buffer of any data
				fill_n(buffer, 5000, '\0');

				cout << endl;
				cout << " Please enter filename > ";
				cin >> filename;

				ifstream inputFile (filename.c_str());				
				if(inputFile.is_open()){						
				   while(!inputFile.eof()){
				     inputFile.read(buffer, 5000);
				     string g(buffer);
				   }
				   inputFile.close();
				} else { cout << endl << "Error opening file: " << filename << endl; }
			 
				break;
			}

			case '2': {
				system("cls");
				cout << endl;
				cout << buffer << endl;  // show buffer
				pause();
				break;
			}


			case '4': {
				system("cls");
				char line[74];					
				cout << endl;
				cout << "Option 4: Delete line" << endl << endl;
				cout << "Enter line number to delete: ";
				cin >> lineNum; 
					
				while(currLine < lineNum){
				   if(currLine == lineNum){
					fill_n(buffer, lineNum, '\0');
				   }
                                   currLine++;
			           cout << currLine << endl;
				}

				cout << endl << endl << "New buffer contents are: " << endl;
				cout << buffer;
				pause();
				break;
			}

			case '7': {
				system("cls");
				cout << endl;
				// Save buffer to file
				cout << " Please enter filename > ";
				cin >> filename;
					
				ofstream outputFile (filename.c_str());			
			
				if(outputFile.is_open()){						
				   //getline(buffer[], line);
				   outputFile << buffer << endl;
				   outputFile.close();
				} else { cout << endl << "Error opening file: " << filename << endl; }
			
				pause();
				break;
			}

			case '8': {
				system("cls");
				cout << endl << "Are you sure you want to exit?" << endl;
				cin >> exit;
				if(exit == 'Y' || exit == 'y'){				
				  exit(0);
				} else { break; }
			}
		}
	} // end while loop
}// end int main(void)

Open in new window

0
seraph_matrix_631
Asked:
seraph_matrix_631
  • 21
  • 19
  • 9
6 Solutions
 
evilrixSenior Software Engineer (Avast)Commented:
You can't shrink a file using standard streams so if you delete you'll either need to either overwrite the existing file (truncating it when you open it for write) or pad the end of the file with, for example nulls.

When inserting into the buffer, if you use a vector or string rather than a char array you can use the insert and erase methods to handle all the grunt work for you.
http://www.cplusplus.com/reference/stl/vector/
http://www.cplusplus.com/reference/string/string/

Personally, I'd use a string as it plays well with streams and is perfectly 8 bit safe. The string class has a data() method to access non-text data (it doesn't append a null unlike the c_str() accessor).
0
 
seraph_matrix_631Author Commented:
It has taken me a lot of reading to get this far. Would you be able to help me change my current code to reflect your recommended changes?

Not done C++ in 3 years and could really do with the help.
I will of course, increase the point allocation if you can provide any additional assistance,
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> Would you be able to help me change my current code
I'll help you do it... that way you'll learn from the experience.

>> Personally, I'd use a string as it plays well with streams
Actually, that's true but one thing I didn't say was that for reading binary data from a stream vector is actually a better choice (tsk!). So, let me rephrase/elaborate just to clear up ambiguity. Both vector and string can contain binary data. String works great with streams; however, this is very much geared towards reading lines of text and not blobs of binary data. For reading blobs of binary data you are better off using a vector.

I apologise for misleading you.

So, the question is -- is this data text or binary?
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
seraph_matrix_631Author Commented:
The data will be a series of .txt files, that is all really, thank you for your help!

Greatly appreciated!
Points increased by 75 (now 200 points) :)
0
 
evilrixSenior Software Engineer (Avast)Commented:
No worries. Ok, I'm at work right now so it'll be later I provide you some help. Meanwhile, take a look a reading in text from a file using the getline function.

http://www.cplusplus.com/reference/string/getline/
http://www.cplusplus.com/reference/iostream/ifstream/

This will allow you to read a line of a text at a time. You can use this to read the whole thing into memory if you wish, or just a specific line. You could read this into a vector of strings, so each line is kept discrete (useful if you want to manipulate a line at a time) or you can read a line at a time and then serialise it to a stringstream (a special stream that can represent an in memory string) .

Why don't you have a go at trying to code up something that just loads the file into memory in a form that suites your needs using this and we can review the other requirements after?

Here's a Q&D example...

// A vector of lines
ofstream fs("myfile.txt");
vector<string> lines;
string line;
while(getline(fs, s))
{
   lines.push_back(s);
}

// The whole file in one string
ofstream fs("myfile.txt");
stringstream sstext;
string line;
while(getline(fs, s))
{
   sstext << s << '\n';
}

string text = sstext.str();

0
 
seraph_matrix_631Author Commented:
I there another way to do this without using vectors?
I'm still a newbie and don't understand vectors enough to fully understand it all.

Thank you for your input so far :) Much appreciated.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> I there another way to do this without using vectors?
Did you see the other approach I suggested?

>> I'm still a newbie and don't understand vectors enough to fully understand it all.
A vector is one of the simplest C++ constructs. It's nothing more than a dynamic array. One of the powers of C++ is the STL and the containers, you really should take the time to get to grips with them and the simplest of them all is vector.
0
 
itsmeandnobodyelseCommented:
>>>> while(!inputFile.eof()){
>>>>       inputFile.read(buffer, 5000);
>>>>       string g(buffer);
>>>>  }

That is wrong code:

First flaw: you only have one buffer (of 5000). If the file is greater than the 5000 the second read would destroy the 5000 bytes retrieved with the first read..

Second flaw:  the string g(buffer);  has no effect. The string object was defined in the while block, so it was destroyed after any loop cycle and the buffer saved was gone.

Instead do:

         string g;
         // the following condition would check for eof and fail
         while(inputFile)
         {
             if (inputFile.read(buffer, 5000))
                 g += string(buffer, 5000);   // that constructor takes a char pointer and size
         }

After that the string g contains the whole file (text).

>>>> In the terms of inserting a new line. I will enter the line number I wish to overwrite. I will then type in the new line contents., and it will overwrite the version stored in the buffer, and if i am happy with the change - i can save it to the file.

The vector evilrix has suggested is much better suitable for doing line changes than it is with the above string. But it would work also: if for example you want to insert a new 10th line with "Hello world", you would do  (using the string g from above)

    int pos1 = 0;
    int pos2 = 0;
    // 'read' next 9 lines
    for (int n = 0; n < 9; n++)
    {
         // search for next linefeed
         if ((pos1 = (int)g.find('\n', pos2)) == string::npos)
              break;   // file has less than 9 lines
         pos2 = pos1 + 1;
    }
    if (pos1 == string::npos)
        return;      // show an error message that the the line 10 cannot be inserted
    // now insert new line
    g = g.substr(0, pos2)  + "Hello World\n" + g.substr(pos2);


Note, of course instead of constants (10) or literals "Hello world" you also could use variables.
       






 
0
 
seraph_matrix_631Author Commented:
Hey, thank you for getting back to me.

@itsmeandnobodyelse
I amended the while loop to your suggestions and I loaded the file and I used the code shown above to insert a new line.

When I came to insert the line I entered the line number (a variable), it returned the error cannot write line.

After doing some checking it turned out that g was not being populated with any data. When I changed the buffer size down to 100, then g contained only the first 100 bytes of the file.


I tried the string stuff from @evilrix and it said that 's was not defined', I tried setting it to a string s (didnt work), and then a char s (again didnt work and errored out lots of errors on the screen).


For the purpose of this little program I cant see it using any more that 5000 chars for a buffer, and seems as I have read, write and view of the buffer using the code i posted above I am inclined to keep that code as it is, although I am open to suggestions (that I can get to work).

 
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> I tried the string stuff from @evilrix and it said that 's was not defined',
Can you show the code please? Below is a working (but in complete for your full needs) example for you to play with.

>> For the purpose of this little program I cant see it using any more that 5000 chars for a buffer
Sooo many buffer overrun exploits have started from that simple premise. Scott Meyer (very famous C++ author) has a simple rule, if you want people to write code properly don't teach them how to do it wrong in the first place. In other words, forget using fixed size buffer and you'll never have to worry about all the issues that pertain to them.
#include <sstream>
#include <iostream>
#include <vector>
#include <string>

int main()
{
   // Some test daya -- this is your input stream
   std::stringstream ssTd;

   ssTd
      << "hello\n"
      << "world\n";

   // Define a line and a vector of lines
   std::string line;
   std::vector<std::string> lines;

   // Read each line and push to the back of the vector of lines
   while(std::getline(ssTd, line))
   {
      lines.push_back(line);
   }

   // Insert a line at position 1 (that's after the first line, which is at position 0)
   lines.insert(lines.begin() + 1, std::string("cruel"));

   // Write each line back to file (in this case I'm just outputting it to stdout
   for(std::vector<std::string>::const_iterator itr = lines.begin() ; itr != lines.end() ; ++itr)
   {
      std::cout << *itr << std::endl;
   }
}

Open in new window

0
 
seraph_matrix_631Author Commented:
Just so you are aware, I am using Ubuntu Linux 9.10 if that makes any major difference.

I used the code above and got the following error:
error 'constant_iterator' is not a member of 'std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std:allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >'

expected ';' before 'itr'
error: 'itr' was not declared in this scope.

Sorry to be a pain and all. I have tried to debug this but with being so new to the language I am not really sure how to go about fixing this :-(

I fail ... :(
0
 
evilrixSenior Software Engineer (Avast)Commented:
>>  I am using Ubuntu Linux 9.10 if that makes any major difference.
Shouldn't do the code is 100% cross-platform. In fact, I tested it using both Windows and Linux ans it builds without warning or error.

>> error 'constant_iterator' is not a member of 'std::vector
I'm guessing you didn't copy/paste it but retyped it? It's const_iterator, not constant_iterator :)

Line 29: for(std::vector::const_iterator itr = lines.begin() ; itr != lines.end() ; ++itr)

0
 
itsmeandnobodyelseCommented:
>>>> When I came to insert the line I entered the line number (a variable), it returned the error cannot write line

If you used the

    outputFile << buffer << endl;

for output, it is wrong.

Remind, that the text was stored in the string g and not in the buffer. The buffer only was a temporary for reading in.

Define the g (or some string variable with a better name)  at begin of main function so that you can use it both for read and write. And then write like

    outputFile.write(g.c_str(), g.length());

0
 
seraph_matrix_631Author Commented:
I am getting really confused with 2 different approaches from the both of you at the moment.
EvilRix is using vector of lines, and itsmeandnobodyelse are using 'g' and string lengths.


After re-coding the code from EvilRix to load a file into a vector of lines using a CONST_ITERATOR (not constant! hehe) it seems to work. I don't know how i would output the contents of the file (and new line) using the code supplied.


I tried
while(getline(ssTd, line){
  cout << line << endl;
}


My main focus at the moment it to read a text file, store it in a buffer and be able to delete or insert a line, and having two different people doing this is confusing the hell outta me.


@itsmeandnobodyelse, I will give you a cut of the points for your assistance but I would like EvilRix to help assist with the solution if that is ok, nothing personal.
0
 
seraph_matrix_631Author Commented:
Increased the points to 315 to cover getting the desired functionality working :)
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> I am getting really confused with 2 different approaches from the both of you at the moment.
Heh. Sorry. Tell us which approach you'd prefer and we can focus on that.

>>  I don't know how i would output the contents of the file (and new line) using the code supplied.

Just change

 cout << line << endl;


to

  << line << endl;

there filestream is an ofstream object to your output file

>>  I would like EvilRix to help assist with the solution if that is ok
I'm here if you need help. I won't post back until I'm sure you'r happy... I don't want to confuse the issue with too many cooks :)
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> Increased the points to 315 to cover getting the desired functionality working :)
BTW: Many thanks, but just so you know, I'd still be happy to help if it was just 20 pts :D
0
 
itsmeandnobodyelseCommented:
>>>> I am getting really confused with 2 different approaches from the both of you at the moment
Sorry, that wasn't my intention. I made the string approach because it was nearest to the code you posted and because you said you don't want vectors.

>>>> but I would like EvilRix to help assist with the solution if that is ok, nothing personal.
No probs ;-)

I already told that using a vector of lines is the best approach. Using streamed text in a string variable is MUCH more complex (for example it is the way MS Word stores documents internally what probably was expecting too much from their developers) though surely you could learn from it.
0
 
evilrixSenior Software Engineer (Avast)Commented:
Thanks Alex... by all means do stick around though... it's a team effort :)
0
 
seraph_matrix_631Author Commented:
Thank you for understanding. To be honest I think the Vector approach would be beneficial and I'm happy to go down that route now that I have read up (briefly) on what vectors are etc.

To be honest I just want to get this working now, so I can fiddle around with it and make it do different things :D


Basically what I have is a loop in the int main like:
loop = 1;
while(loop){
   cout << "press 1 to do this... ";
   cout << "pres 2 to do this... ";
   cin >> selection;

   switch(selection){
       case '1': {
          cout << "load file";
          break;
       }

      case '2': { break; }
   }
}

I have a dummy text file that i open -> this is stored into a buffer.
I make the changes (like insert a new line and delete line) on the buffer version, then when happy write the buffer to the file.

Any help would be great as I have gone from my original version (where i had it working) to this thread and im now so confused its unreal.
0
 
evilrixSenior Software Engineer (Avast)Commented:
I shall look at this when I get home from work and take it from there... I'm a little tied up atm. Meanwhile, Alex, if you wanna assist please do.
0
 
seraph_matrix_631Author Commented:
Thank you for all the help an support you two. It really is appreciated!
0
 
itsmeandnobodyelseCommented:
>>>> I have a dummy text file that i open -> this is stored into a buffer.

It isn't stored into a buffer but in a vector<string> see http:#28672706

You make an insert of a new line by calling vector::insert

The first argument is an iterator to the slot of the vector you want to insert. For a vector v you can get such an iterator for slot n  (n = 0; n < vector size - 1) by calling  v.begin() + n, cause v.begin() points to slot 0, v.begin()+1 points to slot 1, and so on.

Note, the insert would shift existing entries to the right, beginning with slot n. So, if you had

 0:  This is
 1:  a text
 2:  with
 3:  five
 4:  lines

in vector v, a call

    v.insert(v.begin()+3, "more than");

would produce

 0:  This is
 1:  a text
 2:  with
 3:  more than
 4:  five
 5:  lines

   
0
 
seraph_matrix_631Author Commented:
Yes, that is the type of thing I am planning on doing.
When I talk about a 'buffer' I mean that the file is read from the hard disk and temporarily stored within the program for modifications without overwriting the actual physical file on disk, until the user selects a menu option to write the 'buffer' to the file.

Your explanation seems a bit easier to comprehend now. I'm just slow at picking things up :(
0
 
evilrixSenior Software Engineer (Avast)Commented:
Hi,

I can see you and Alex are working on this so I won't interfere. I'll continue to monitor just in case I can be of assistance but I leave you in Alex's more than capable hands.

Good luck.

-Rx.
0
 
seraph_matrix_631Author Commented:
What I have done is taken my program back to basics.

How would I go about opening a text file, and then loading this into a vector of lines, and then outputting the result?


The output would be something like ?
while (n = 0; n < sizeof(vector) - 1; n++){
   cout << vector[n] << endl;
}
0
 
evilrixSenior Software Engineer (Avast)Commented:
Ok, it's a little quite here so, let's see if we can get this moving...

>>How would I go about opening a text file, and then loading this into a vector of lines, and then outputting the result?
Let's go back to me original example, with added comments.

You need to use ifstream to read your file and ofstream to write your file. I've commented in the original code what you need to change. I'm not going to do it for you though, as it will deprive you of a learning experience.

Use these links to help you. If you get stuck post back here with what you've written so far. Try and get it working by just modifying the template I've given you below. It's a very simple couple of changes.

http://www.cplusplus.com/reference/iostream/ofstream/
http://www.cplusplus.com/reference/iostream/ifstream/
#include <sstream>
#include <iostream>
#include <vector>
#include <string>

int main()
{
	// For the sake of an example I used a stringstream, all you need do is
	// replace this with an ifstream, which has been opened to read your
	// input file as a text file
	std::stringstream ssTd;

	ssTd
		<< "hello\n"
		<< "world\n";

	std::string line;
	std::vector<std::string> lines;

	while(std::getline(ssTd, line))
	{
		lines.push_back(line);
	}

	lines.insert(lines.begin() + 1, std::string("cruel"));

	for(std::vector<std::string>::const_iterator itr = lines.begin() ; itr != lines.end() ; ++itr)
	{
		// I am just writing to stdout, all you need do is open a file using ofstream
		// and change std::cout for the name of your ofstream, which will then write
		// this data to file rather than to stdout
		std::cout << *itr << std::endl;
	}
}

Open in new window

0
 
seraph_matrix_631Author Commented:
Well so far so good.

I have got the system to show the ssTd and insert a new line.
I noticed that when I used:

    cout << 'enter line';
    cin >> lineNo;

    cout << 'enter text';
    cin >> linetext;

    lines.insert(lines.begin() + lineNo, std::string(lineText));

   It reported 'segmentation fault'


When I used: lines.insert(lines.begin(), std::string("Some new text here ..."));
It added that text as the very first line in the text file.

Not sure what I am doing wrong because I would like to be able to enter a line number and a line text and for it to insert that in the appropriate position.



In regards reading a file into the stringstream variable I used:
   ifstream FileIn;
   FileIn.open(file.c_str(), FileIn::in);
   while(FileIn.good()){
       ssTd << FileIn.get() << endl;
   }

This just outputs lines of numbers on the screen and no actual text from the file.
When I do a cout << FileIn.get() << endl; I get the same.

I have checked the file and there is only text in the file, again, I'm not sure where I am going wrong.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>>  It reported 'segmentation fault'
You need to make sure that lines.begin() + lineNo < lines.size() as you can't insert beyond the end of the iterator.If it's greater just append it to the end. If you want it inserted to an exact position after the last line you'll need to pad it by appending empty strings. The simplest way is to resize the vector first, which would be the smartest way --->  v.resize(LineNo)) to ensure it's always big enough. A resize is a no-op if you try to resize smaller than the vector currently is so you could do this, safely, every time if you don't want to code up the logic to only do it when necessary.

>> In regards reading a file into the stringstream variable I used:
You don't need to read into the stringstream -- your file stream REPLACES the stringstream. Don't forget the interface of a stream, regardless of file or string is the same so they are interchangeable. The strignstream was only used for example purposes. So, in my example code above, just get rid of stringstream completed and replace it with a file stream... it's that simple.
0
 
itsmeandnobodyelseCommented:
>>> In regards reading a file into the stringstream variable I used:

When using a vector as a buffer you should read with getline as shown in http:#28440788.

When adopting that sample to your variables the resulting code would be like

   // A vector of lines
   ifstream FileIn(file.c_str());   // opens in constructor, ios_base::in is default
   vector<string> lines;
   string line;
   while(getline(FileIn, line))    // would check both on eof and fail
   {
        lines.push_back(line);
   }
   FileIn.Close();

You could put that piece of code to a function  'readFile' and pass the vector by reference

     bool readFile(const std::string & file, std::vector<std::string> & lines);  

And call the function in your main after


    cout >> "Filename: ";
    cin >> file;
    vector<string> lines;
    if (!readFile(file, lines))
    {
         cout << "wrong inputfile " << file << endl;
         return -1;
    }
   
When passing the vector by reference, the readFile actually would use the vector from main.




0
 
seraph_matrix_631Author Commented:
Both of those errors are fixed, and as far as I can tell the program is working as required, and boy have I learn't a lot from this!

Now to try and get the delete line working :)
0
 
itsmeandnobodyelseCommented:
>>>> and get the delete line working :)

You delete line n from a vector v by calling

   v.erase(v.begin() + n);

Don't forget to check that n is less than v.size().
0
 
seraph_matrix_631Author Commented:
I have noticed an issue.
When I load the file it stores the contents into the vector of lines and when I go and preview the vector of lines it shows the contents of the file.

If I press option 1 to load the file, it appends the same text to the vector of lines so I get n+1 copies of the text. I only noticed this behavior when inserting a line.

When I go to insert the line (and the new line has spaces between words), only the first word is written to the new line. if I enter "This is the new line 14" it will go through the process of writing the file, show the menu, but try and load menu option 4 (in this particular example).
0
 
itsmeandnobodyelseCommented:
>>>> it appends the same text to the vector of lines so I get n+1 copies of the text.

I don't know whether I understand correctly but if you mean that the vector wasn't empty before reading a second inputfile (or reading the same file again), then you easily could solve the issue by making

   lines.clear();

before reading from file.

>>>> When I go to insert the line (and the new line has spaces between words), only the first word is written to the new line

That is if you were using

    cin >> line;

which breaks at any whitespace character. Use

   getline(cin, line);

instead and you can input phrases of multiple words (terminated by <ENTER>).
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> as I can tell the program is working as required, and boy have I learn't a lot from this!
w00t --> that was the plan so I'm very pleased :)

0
 
seraph_matrix_631Author Commented:
This is very very bizarre ....

I have added a switch case for menu options 4, 5 and 6.
I have re-compiled the C++ source into an executable and run it.

When I press the menu option nothing is shown from the switch case (I added a cout to show the case number to test).

I copied the code into a new file and named it something different and to be sure i removed the error message from the menu if a numeric entry was not entered. I recompiled and entered 'T' into the menu but it showed the error message that I removed, and the newly added switch statements or amended code suggested by itsmeandnobodyelse seems to be running.

Any suggestions cos this is just plain weird.
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> Any suggestions cos this is just plain weird.
Just one, can you show the code please? :)
0
 
seraph_matrix_631Author Commented:
Here is the code I am using
#include <iostream>
#include <iomanip>
#include <cstdlib>   // use 'system' function calls
#include <fstream>   // required for file handling
#include <stdio.h>
#include <cctype>
#include <vector>
#include <sstream>
#include <string>

using namespace std;

int showMenu(void){
	char Opt;
	cout << "  1. " << " Load File" << endl;
	cout << "  2. " << " Show Contents of file" << endl;
	cout << "  3. " << " Insert line" << endl;
	cout << "  4. " << " Delete line" << endl;
	cout << "  5. " << " Save File" << endl;
	cout << "  6. " << " Exit" << endl;
	cout << endl << "Option: ";
	cin >> Opt;

	return Opt;
}


int main(void) {
	// Initialize Variables
	char  Opt;
	int   loop = 1;

	stringstream ssTd;
	string line;
	vector<string> lines;
	string filename, inputFile, outputFile;

	// insert line
	int lineNum = 0;
	string newLine;  

	system("clear");

	while(loop){
		system("clear");
		menuOpt = showMenu();

		switch(menuOpt){
			case '1': {
				system("clear");
				filename = "quotes.txt";        
				lines.clear();
				ifstream inputFile(filename.c_str());
				if(inputFile.is_open()){
					while(getline(inputFile, line)){
						lines.push_back(line);
					}
					inputFile.close();
				}
				pause();
				break;
			}


			case '2': {
				for(vector<string>::const_iterator itr = lines.begin(); itr != lines.end(); itr++){
					cout << *itr << endl;
				} 
				cout << endl;
				pause();
				break;
			}


			case '3': {
				system("clear");
				cout << endl;
				cout << "Option 3: Insert new line" << endl << endl;

				cout << "Enter line number > ";
				cin >> lineNum;

				cout << "Enter Line Contents > ";
				getline(cin, newLine);
				
				lines.insert(lines.begin() + lineNum, newLine);
				pause();
				break;
			}       


			case '4': {
				system("clear");
				cout << endl;
				cout << "Option 4: Delete line" << endl << endl;
				cin >> lineNum;
				pause();
				break;
			}

			case '5': {
				cout << "Hey im save file" << endl;
				pause();
				break;
			}


			case '6': {
				system("clear");		
				exit(0);
				break;
			}
		}
	}
}

Open in new window

0
 
evilrixSenior Software Engineer (Avast)Commented:
Cool, looking.
0
 
evilrixSenior Software Engineer (Avast)Commented:
Well, I just run the code below through my debugger and it definately goes through the switch cases you are expecting. I noticed the code you gave me had a compile error (fixed) are you sure it was actually building?
#include <iostream>
#include <iomanip>
#include <cstdlib>   // use 'system' function calls
#include <fstream>   // required for file handling
#include <stdio.h>
#include <cctype>
#include <vector>
#include <sstream>
#include <string>

using namespace std;

int showMenu(void){
	char Opt;
	cout << "  1. " << " Load File" << endl;
	cout << "  2. " << " Show Contents of file" << endl;
	cout << "  3. " << " Insert line" << endl;
	cout << "  4. " << " Delete line" << endl;
	cout << "  5. " << " Save File" << endl;
	cout << "  6. " << " Exit" << endl;
	cout << endl << "Option: ";
	cin >> Opt;

	return Opt;
}

void pause()
{
	system("pause");
}


int main(void) {
	// Initialize Variables
	char  menuOpt;
	int   loop = 1;

	stringstream ssTd;
	string line;
	vector<string> lines;
	string filename, inputFile, outputFile;

	// insert line
	int lineNum = 0;
	string newLine;  

	system("clear");

	while(loop){
		system("clear");
		menuOpt = showMenu();

		switch(menuOpt){
			case '1': {
				system("clear");
				filename = "quotes.txt";        
				lines.clear();
				ifstream inputFile(filename.c_str());
				if(inputFile.is_open()){
					while(getline(inputFile, line)){
						lines.push_back(line);
					}
					inputFile.close();
				}
				pause();
				break;
					  }


			case '2': {
				for(vector<string>::const_iterator itr = lines.begin(); itr != lines.end(); itr++){
					cout << *itr << endl;
				} 
				cout << endl;
				pause();
				break;
					  }


			case '3': {
				system("clear");
				cout << endl;
				cout << "Option 3: Insert new line" << endl << endl;

				cout << "Enter line number > ";
				cin >> lineNum;

				cout << "Enter Line Contents > ";
				getline(cin, newLine);

				lines.insert(lines.begin() + lineNum, newLine);
				pause();
				break;
					  }       


			case '4': {
				system("clear");
				cout << endl;
				cout << "Option 4: Delete line" << endl << endl;
				cin >> lineNum;
				pause();
				break;
					  }

			case '5': {
				cout << "Hey im save file" << endl;
				pause();
				break;
					  }


			case '6': {
				system("clear");		
				exit(0);
				break;
					  }
		}
	}
}

Open in new window

0
 
seraph_matrix_631Author Commented:
This is so annoying.
I completely re-made the manu and the switch and made it in a completely different file name and location in ubuntu.

When I do the switch and get it to show just a cout statement it does it for all switch options.
I then copied / pasted the variables into the new C++ file and re-compiled and ran. No problems.

The minute I include the code for menu option 2 the program refuses to output any cout statement for the case '2' switch case.
0
 
evilrixSenior Software Engineer (Avast)Commented:
Ok, can you attach the EXACT code, verbatim, including any includes, test fiiles or make files and all related source files. I'll make it on Linux and test it.

Probably a bit OTT but, let's not assume anything :)
0
 
seraph_matrix_631Author Commented:
Now, without changing the code, it now wants to work!
BLOODY C++ !!!! GRRRRR!
0
 
seraph_matrix_631Author Commented:
I have learn an awful lot from this thread and it has actually made me want to continue my study in c++

Thanks to these two experts I have gained a better fundamental understanding of stringstream, input/output files, debugging and vectors.

Thank you both, for investing so much time to assisting me in my n00bish errors, it really is appreciated as I understand you both live busy lives.

Once again, EE has not let me down and has proven to be a great resource where friendly developers can help each other out and better from the experience.

Once again - thank you!
0
 
evilrixSenior Software Engineer (Avast)Commented:
>> BLOODY C++ !!!! GRRRRR!
Muhahhahah muhahahahahah :)

Welcome to the club dude!

Thank you seraph_matrix_631 and Alex, thank you for great team work.
0
 
seraph_matrix_631Author Commented:
If I may ...
There is but one thing that is puzzling me.

When I insert a new line I could not use cin >> line; as it would not allow me to use spaces for the line text.

When I use:  cout << "Enter Line Contents > ";
                 getline(cin, newLine);

I find that the program asks me to input the line number, and then dies (not asking me to enter line contents) and just inserts a blank new line.

Any thoughts?
0
 
itsmeandnobodyelseCommented:
>>>> I find that the program asks me to input the line number

The code you posted asks for Line Contents and not for Line Number. Is it nevertheless the code which "dies" or ist it different code.

Note, when using getline you should not mix it up with cin>>  . The problem is that getline checks for the <Enter> key as terminating input while cin>> does not. So combinations of both normally don't work (though I don't know whether the above is true for all platforms).

So if you must use the getline for text input you also should use the getline for number input. You could use stringstream to convert it to a number after that.

     getline(cin, line);
     istringstream iss(line);
     if (!(iss >> lineNum))
          return -2;    // invalid number

The above has the additional benefit that user input can't spoil the cin stream (at least not so easily). If you do

    cin >> lineNum;

and the user inputs O and not 0, cin goes into fail state and would not accept any more inputs before you made a reset by calling cin.clear() - what clears all failure bits - *and* make a valid input operation to 'eat' the wrong character that caused the failure. You see it is a good decision to avoid cin>> and move that issue to a istringstream where it doesn't matter if it goes to fail state or not as it was used only once.
0
 
seraph_matrix_631Author Commented:
Ah I see.
Following a similar logic I used a char for the menu input and then used if(isnumeric($variable)){ ... }

Thanks for the 'input'
0
 
itsmeandnobodyelseCommented:
>>>> I used a char for the menu input

Use getline(cin, string_input) for all inputs, e. g. for the menu in ShowMenu

    ...

    Opt = -1;   // init with an invalid option
    string input;
    getline(cin, input);
    if (input.length() == 1)
        Opt = input[0]-'0';   // converts string input to number
    return Opt;
0

Featured Post

The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

  • 21
  • 19
  • 9
Tackle projects and never again get stuck behind a technical roadblock.
Join Now