Let me start by saying this is my first post here at daniweb and I am pretty new at C++. With that said I will dive right in.

I have a program due next week and trying to get it hammered out. I have to create a line editor that will keep entire text on a linked list one line in a seperate node. ( I think I have that part). It starts with "Edit" and enter the file name to open. ( I think I have that as well). afte this line a prompt should appear with line number (i.e. 1>) if the letter 'I' is entered with a number 'n' following it , then insert the text followed before line 'n'. If 'd' is entered with two numbers 'n' and 'm', one 'n' or no number following it, then delete lines 'n' - 'm', line 'n', or current line. Do the same with command 'L' for listing line. If 'A' is entered then append to existing line, and finally if 'E' exit and save in text file.

I have most of the functions put together, just not real sure how to approach the prompts and such for the insert, delete, list, and append. (or exit for that matter). My code is below. I appreciate any help with this.

#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>


using namespace std;

struct node{
node *next;
string sentence;
//char sentence[80];
};

void append (struct node **, string);
//void append (struct node **, char);


node *add_node(node *list, string x){ //insert at front or in front of current line
//node *add_node(node *list, char x){
node *p = new node;
p->next = list;
p->sentence = x;
return p;
}


node *find_item(node *list, string x){
//node *find_item(node *list, char x){
node *p = list;
while (p != NULL){
if (p->sentence == x)
return p;
p = p->next;
}
return NULL;
}

node *find_item_before(node *list, string x){
//node *find_item_before (node *list, char x){
node *p = list, *q = list;
while (q != NULL){
if (q->sentence == x)
return p;
p = q;
q = q->next;
}
return NULL;
}

node *delete_node (node *list, string x){ //delete line
//node *delete_node (node *list, char x){
node *p = find_item_before(list, x);
if (p != NULL){
node *q;
if ((p == list) && (p->sentence == x)){
q = p->next;
delete p;
return q;
}else{
q = (p->next)->next;
delete p->next;
p->next = q;
}
}else
return list;
return list;
}

node *insert_after (node *list, string x, string y){
//node *insert_after (node *list, char x, char y){
node *p = find_item(list, x);
if (p !=NULL){
node *q = p->next;
p->next = new node;
(p->next)->next = q;
(p->next)->sentence = y;
return p->next;
}
return NULL;
}


void append (struct node **p, string x)
//void append (struct node **p, char x)
{
struct node *tmp, *r;

if (*p == NULL)
{

tmp = new node;
tmp->sentence = x;
tmp->next = NULL;
*p = tmp;
}else{
tmp = *p;
while (tmp->next !=NULL)
tmp = tmp->next;

r = new node;
r->sentence = x;
r->next = NULL;
tmp->next = r;
}
}

void print_list(node *list){ // print lines
node *p = list;
int l = 1;
//cout << l << ">";
while (p != NULL){
cout<< l << ">";
cout << p->sentence << endl; 
p=p->next;
++l;
}
//cout << "tail." << endl;
return;
}

int main(){
char fName[20];
cout << "Edit: ";
cin >> fName;

ofstream outfile;
outfile.open(fName,ios::out);
if (outfile.fail())
outfile.open(fName,ios::out);

string temp;
//char temp[80];

node *lst = new node;
cout << "1> ";
cin >> temp;
getline (cin, temp);
//cin >> temp;
lst->sentence = temp;
//lst->sentence = "The first sentence";
lst->next = NULL;

print_list(lst);

/*cout << "now i'll add a sentence to the front" << endl;
lst = add_node(lst, "try here");
print_list(lst);

cout << "try and add another sentence to the front" << endl;
lst = add_node(lst, "another sentence");
print_list(lst);

cout << "try and append sentence" << endl;
append(&lst, "to this sentence");
print_list(lst);

cout << "try and delete node" << endl;
lst = delete_node(lst, "try here");
print_list(lst);

cout << "try and delete another node" << endl;
lst = delete_node(lst, "try again");
print_list(lst);*/

delete lst;



cout << "done" << endl;
cin.ignore();
return 0;
}

when the program is run you should see something like the following:

EDIT: <enter file name here>
1> The first line
2>
3> And another line
4> I 3
3> The second line
4> One More Line
5> L
1>The first line
2>
3>The second line
4>One more line
5> and another line //this is now line 5, not 3
5>D 2 // line 5 since L was issued from line 5
4>L // line 4 since one line was deleted
1>The first line
2>the second line // this and the following lines now have
3>One more line // new numbers
4>and another line
4>E

First, you need to loop until the input = "E". The prompts would work like this:

int lineNumber = 1;
cout << lineNumber << "> ";
cin >> temp;

This will prompt with the current line number. You will need if statements to keep track of the line number according to what the user has entered.

I did try that, and the problem is this, the string only gets the first part of the string: i.e., if I put in at the prompt, "This is the first line", the

cin >> temp

only gets "This" it doesn't pull in the rest of the string. I am pretty sure that char would work, if I could figure out how to make it work. I am currently stuck at this point since unless I get the prompts to work, nothing else will work further down the line.

Thanks for the help and any help in the future.

if you want to retrieve an entire line from a stream (such as cin, or a file), then you need the getline function

string temp;
 getline( cin, temp );

Edit- by the way, if you use cin >> you need to be careful, because it comes with a few pitfalls, such as leaving newlines in the stream, and needing to be checked for errors.

A better way is to always read your input as a string using getline and convert from a string to a number using stringstream's

you may want to try something like this

//Retrieve an int from an input stream
int get_int( istream& is )
{
    string input;
    int output;
    while (true)
    {
        //Read a whole line of text from the input stream
        getline( is, input );
        stringstream ss(input);

        //If the input is an int, break out of the loop
        if( ss >> output )
            break;
        else
            cout << "Error\n";
    }
    return output;
}

int main() 
{
    cout << "enter a number: ";

    //Get an int from 'cin' - No need to worry about error flags or rogue newline's
    cout << get_int( cin );
}

As a starting point I also have written the following code, but it errors on me.

while (true){
cout << lineNumber << "> ";
getline (cin, temp);
if (toupper(temp.at(0) == 'E') break;
}

for some reason when it goes through the first time it will not stop and take a prompt, it just plows right on through with and empty string. However, when it loops back through it will stop and take a prompt. That seems strange to me. Any ideas on that one?

As a starting point I also have written the following code, but it errors on me.

if (toupper(temp.at(0) == 'E') break;

You missed a bracket out ...

if (toupper(temp.at(0)[b])[/b] == 'E') break;

for some reason when it goes through the first time it will not stop and take a prompt, it just plows right on through with and empty string. However, when it loops back through it will stop and take a prompt. That seems strange to me. Any ideas on that one?

You probably have a newline character left in cin somewhere.
Read my (edited) post above on that subject.

Sorry, Got it. Still same problem. Going through the loop without stopping the first time to take in a line. Below is essentially what I am getting when I go through it.

1>1> <waiting this time>  // this is second time through. It doesn't 
                       // stop the first time through thus the 2 '1>'s.

of course as I have the stops in my debugger, it blows up at the 'if' statement in the above code, since it has nothing in the string to compare.

To Bench:
I see what you were saying with the 'cin>>' I changed that to

cin.getline(fName, 20);

and that cleared that up, so I am now trying to figure out how to pass the different portions of the string to the different functions and how to set up the case statements or if statements. Thanks for helping me get the prompts working. I am sure I will be back in a little bit as soon as I get cracking on the if statements/case statements.

To Hamrick:
What do you mean "without the linked list stuff"? Are you referencing the node *insert_after (for example?)

I have to say I appreciate all the help you guys have given, it is great to get prompt help from folks that don't mind helping out. I am new to the C++ world and my current Prof, has said this is an Advance Advance class, so I am trying to keep my stress down, so I can get these things worked out.

What do you mean "without the linked list stuff"?

One or two line snippets make it hard to know what you've changed and what you haven't. You need to post more code. But you shouldn't post all of it because it's long. :) You've already posted the implementation for the linked list and we don't need to see it again. I'm trying to get you to cut out the linked list code and post the rest so I can see your code as it is now.

Gotcha. Below is what I am working on. I need to get the statements to call the linked list functions (if statements, or case statements) so when someone enters the 'I', 'D', 'A', or 'L' they will do what I initially posted as the assignment.

int main(){

string temp;
char fName[20];
int lineNumber = 1;
cout << "Edit: ";
cin.getline(fName,20);

while (true)
{
cout << lineNumber << "> ";
getline (cin,temp);
if (toupper(temp.at(0)) == 'E') break;
}
ofstream outfile;
outfile.open(fName,ios::out);

if (outfile.fail())
outfile.open(fName,ios::out);

node *lst = new node;
lst->sentence = temp;
lst->next = NULL;

print_list(lst);


delete lst;



cout << "done" << endl;
cin.ignore();
return 0;
}

Ok I have started trying to code the portion that will actually carry out the Insert 'I', Append 'A', List 'L', and Delete 'D'. As earlier posted I have the different functions created and defined, but I need help specifically with the Insert, List, and Delete.

These require a numeric to determine where to insert or a range of lines to delete. (I.E., 'I 3' should insert the text before line 3, if no number give then insert at that point.) Delete may give one number 'n' or two numbers 'n' and 'm', where 'n' would be the specific line to delete and if 'n' and 'm' are both listed, then we would delete that range of lines. List would also work in the same fashion as delete, meaning it would list specific lines if given, or a range of lines, or all if not numeric given. The code I have as launching point is below.

if (toupper(temp.at(0)) == 'L'){
print_list(lst);
}

if (toupper(temp.at(0)) =='D'){
lst = delete_node(lst, temp);
print_list(lst);
}

if(toupper(temp.at(0) == 'I'){
lst = add_node(lst, temp);
print_list(lst);
}

they seem to work with no numeric past to them, but I need help figuring out how to pass the numeric values to them to delete the specific line or lines; List the specific line or lines; and Insert at that specific point.

As always thanks for any and all help.

your line number will be the position in the list, so you probably want to implement a function which will iterate through the list 'N' number of times to return a pointer to the element you want (or return a null pointer if the line at N doesn't exist)

Could you use the code below to do something like that? And how would I do that?

node *find_item(node *list, string x){
	node *p = list;
	while (p != NULL){
		if (p->sentence == x)
			return p;
		p = p->next;
	}
	return NULL;
}

Yes, it would be similar, except instead of looking for an element by checking its data, you'd be looking for an element based on its position. so you'll need a counter (A for-loop may be more appropriate)

I would probably do something like this

node* find_pos(node* list, int pos)
{
    for(int i=0; i<pos; ++i)
    {
        if( list == NULL )   //true if the list is shorter than 'pos'
            break;

        list = list->next;
    }
    return list;
}

Hey Bench,

I tried that, but now it is deleting any thing in the list. Below is the code I tried. First being the function you explained in the above post.

node* find_pos(node* list, int pos)
{
	for (int i=0; i<pos; ++i)
	{
		if (list == NULL)
			break;
		list = list->next;
	}
	return list;
}

then added the delete call.

if (toupper(temp.at(0)) == 'D'){
	n = temp.at(2);
	
	lst = find_pos(lst,n);
	lst = delete_node(lst, temp);
    print_list(lst);
	}

I think what you're seeing is a memory leak, the data isn't being deleted, its just being lost in the wilderness..

I assume that lst is the pointer to the head of your list (?), so don't modify that - the find_pos function is supposed to return a pointer to the element at position 'n'. Store the result in a temporary variable instead - something like this perhaps.

node* nth_node = find_pos(lst,n);
if( nth_node != NULL)
    lst = delete_node( nth_node, temp );
This article has been dead for over six months. Start a new discussion instead.