GIDForums  

Go Back   GIDForums > Computer Programming Forums > C++ Forum
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 30-Nov-2005, 15:59
Elsydeon Elsydeon is offline
Junior Member
 
Join Date: Aug 2005
Posts: 45
Elsydeon is on a distinguished road

Strings tripping me up once more


It's been a while. The past month or two I've managed to get my programs done on my own fairly quickly. We stopped messing with unfamiliar code and went into logical issues. Binary trees and so on. Logic problems never bugged me.

But, once again for one of my programs I need to use Strings in a way that the current implementation from our previous labs do not seem to support.

Basically I have a structure of information, First name, last name, etc. And I want to use a string to take in a street address (program is an address book). C style strings work fine for everything else, but when attempting to input to a character array as I did with the others, the spaces in the address (i.e. "555 Fake Street") are cutting off later inputs. That or filling them in, detecting the spaces as Null and considering it a different string. No requirement on which type of string to you, but my browsing and tinkering has come up empty.

Strings always seem to be my weakness, I never got any grounding in them. I did a search, couldn't find one, but if there's a basic thread that will get me set could I get directed to it? Tried to find one, failed. And if not, any responses are appreciated.

Much appreciated.
  #2  
Old 30-Nov-2005, 17:58
Paramesh's Avatar
Paramesh Paramesh is offline
Regular Member
 
Join Date: Sep 2005
Location: The Milky Way
Posts: 927
Paramesh is a jewel in the roughParamesh is a jewel in the roughParamesh is a jewel in the rough

Re: Strings tripping me up once more


You can use cin.getline to read strings with spaces.
For example, consider this sample program:

Using character arrays:
CPP / C++ / C Code:
#include<iostream>
using namespace std;

int main()
{
    char s[30];            //initialize the string

    cout<<"Enter the first line of the address: "<<endl;
    cin.getline(s, 20);   //get 20 characters

    cout<<s;              //print the string.

    return 0;
}


But usage of character arrays is not recommended in C++, we can switch to string.
Here is a sample code:
CPP / C++ / C Code:
#include<iostream>
#include<string>
using namespace std;

int main()
{
    string s;            //C++ string

    cout<<"Enter the first line of the address: "<<endl;
    getline(cin, s);   // get the line until a line break

    cout<<s;      

    return 0;
}
Note the difference between the two getline statements.

Regards,
Paramesh.
__________________

Don't walk in front of me, I may not follow.
Don't walk behind me, I may not lead.
Just walk beside me and be my friend.
  #3  
Old 01-Dec-2005, 01:22
WaltP's Avatar
WaltP WaltP is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Midwest US
Posts: 3,243
WaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to all

Re: Strings tripping me up once more


Since you didn't post code, all we can assume.
You seem to be using C with scanf(), or C++ with cin.

Read this info. If you're using cin the information is the same.

While you're at it, read the Guidelines
too.
__________________

Age is unimportant -- except in cheese
  #4  
Old 01-Dec-2005, 08:36
Elsydeon Elsydeon is offline
Junior Member
 
Join Date: Aug 2005
Posts: 45
Elsydeon is on a distinguished road

Re: Strings tripping me up once more


I originally thought I just didn't understand the basics of strings, why I didn't post my code. But it finally came to me to copy the code taking in the string from my program into it's own small one and run it. Since it works there, but not in this one, something else must be going on. The problem is in my add and update options. Look to the runmenu method near the bottom of the program.

On a side note, I know I've been told before that the .h at the end of includes is archaic and to switch, but for the compiler I've been using I don't seem to have a choice. Says it can't find them otherwise. I did switch the void main we were given to int main.

Sorry if the spacing is off.
CPP / C++ / C Code:
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
#include <ctype.h>
#include <fstream.h>
#include <stdlib.h> // for exit(1)

//using namespace std;


const int
	keyLength = 20,
	NIL = 0;

struct recType {					// data about a stock
 char key[keyLength];				// First Name (ex: Dale)
 char lName[keyLength];				//Last Name
 char addString[40];
 char city[keyLength];				//City
 char state[2];						//Two letter state ID
 int zip;							//Zip Code
}; // recType

enum lastChange {ADD, DELETE, UPDATE};
	// what was the last change to the data?


//////////////////////
//    stack class   //
//////////////////////

struct operationType {
	recType lastInfo;						// the contents of the record that was changed
	lastChange lastChangeWas;		// the operation that was performed
}; // operationType

// Class to maintain a simple stack.
class stack {
	// Structure for one node of the stack.
	private:
		struct node {
			operationType item;
			node *next;         // Pointer to the next node of the stack
		};
		node *head;             // Pointer to the head node of the stack
	public:
		stack();                 // Constructor. Creates an empty stack
		~stack();                // Destructor.  Restores memory to the heap
		void push(operationType);  // Push one item to the stack
		bool pop(operationType &); // Pop one item from the stack
		bool empty();			 // Test whether the stack is empty
		void clearStack();		 // Removes all records from the stack
}; // class stack


//////////////////////
//    Tree Class    //
//////////////////////

class treeClass {
	// holds and manipulates a binary tree of records (recType)
	// recType must have a field named key which is type char*
	//		key must uniquely identify a record
	// conditions maintained in object:
	//	 record ordered by key
	//	 no repetitions
	public:
		treeClass();									// constructor
		~treeClass();								// destructor
		void addRec (recType rec);	// adds record if it does not exist
		void deleteRec (char code[keyLength]);
							// deletes record with code = key.
		void findRec (char code[keyLength], recType &rec);
							// returns record with key = code
		void updateRec (recType rec);
							// locates and replaces current entry with record
		bool allOK ();			// returns the value of ok, then resets it to true
		int howManyRec();			// returns the number of records
		void undo();					// undoes last insert/delete
		void storeToDisk (char name[]);	// stores records to the disk under name
		void fetchFromDisk (char name[]);
					// loads records from disk; appends to current records
					// makes no assumptions about the order of records in main memory
		void deleteAllRecords (); // deletes all records from the linked list
		void treeClass::inTraversal(); // prints out tree elements in order
		void treeClass::inLevels();//Prints out tree level data
		
private:
		struct node {
			recType item;     	// Data item. One record stored at each node
			node *left, *right;	// Pointer to the left and right branches of the tree
		}; // node
		node *root;           // Pointer to the root node of the tree
		bool ok;						// holds true until an operation fails
		int min;// Small tree level
		int max;// Large tree level
		int avg;//Avg tree level
		int levelcount;//Counter for average
		int rectotal; //Total # of records.  Used in How Many Records.
		void treeLevels(node *it);//Prints out largest and smallest tree levels
		stack changes;
		void inTraversalRecur(node *it); // used by inTraversal
		void recDeleteAllRecords(node *thisun);
}; // treeClass

/////////////////////////////////////
//    Tree Class Implementation    //
/////////////////////////////////////


void treeClass::storeToDisk (char name[]) {
// stores records in a textfile under name
	cout <<"In storeToDisk.  Not implemented." <<endl;
} // treeClass::storeToDisk


void treeClass::fetchFromDisk (char name[]) {
// loads records from disk; appends to current records
// makes no assumptions about the order of records in main memory
	recType record;
	ifstream inFile (name, ios::in);
	if (!inFile) 			// file failed to open?
		ok= false;
	else {
		ok= true;
		int size= sizeof (recType);
		while (!inFile.eof()) {
			inFile.read ((char *) &record, size);
			addRec (record);
		} // while
		inFile.close();
		ok= true;
	} // if
} // treeClass::fetchFromDisk

int treeClass::howManyRec() {	// returns the number of records in the tree
	return (rectotal);
} // portfolio::howManyRec();


treeClass::treeClass() {
	ok= true;
	root= NIL; // indicates an empty list
	rectotal=0;
} // treeClass::treeClass()

treeClass::~treeClass() {			// destructor
 	deleteAllRecords ();
} // treeClass::~treeClass


void treeClass::deleteAllRecords () {
// deletes all records from the linked list
	node *thisun=root;
	recDeleteAllRecords(thisun);
	rectotal=0;
	changes.clearStack();			// removes previous changes from stack
} // treeClass::deleteAllRecords

void treeClass::recDeleteAllRecords(node *thisun){//Most likely not most efficient method, but it works.  Deletes all records by leaf
if (thisun != NIL) {//If value is found
	if(thisun->right==NIL && thisun->left==NIL){//if leaf, delete
		deleteRec(thisun->item.key);
	}
	else{//continue down tree
		recDeleteAllRecords (thisun->right);
		recDeleteAllRecords (thisun->left);
	}
	if(thisun->right==NIL && thisun->left==NIL){//after traversal, checks again to delete
		deleteRec(thisun->item.key);
	}
	} 
}



void treeClass::addRec (recType rec) {	// adds record if it does not exist
	node *newnode,          // Pointer to the new node to be added to the list
		 *current= root,    // Pointer to the current node during search
		 *previous;			// Pointer to parent of current

	newnode = new node;     // Allocate heap memory for one new node
	if (newnode==NIL) 			// Test whether memory allocation was successful
		ok= false;
	else {
		newnode->item = rec;            // Copy new name to the new node
		newnode->left= NIL;
		newnode->right= NIL;

		if (root==NIL)
			root= newnode;
		else {
			previous = NIL;                       // There is no node before the root

			// Loop until insertion spot located, or duplicate is found
			while (current!=NIL && strcmp(current->item.key, rec.key) != 0) {
				previous= current;
				if (strcmp(current->item.key, rec.key) > 0) {
					current = current->left;
				} else {
					current = current->right;
				}
			} // while

			// If a matching name is found, cancel the insertion, delete new node
			if (current!=NIL && strcmp(current->item.key, rec.key)==0) {
				delete newnode;
				ok= false;
			} else {
				if (strcmp(previous->item.key, rec.key) > 0)
					previous->left= newnode;
				else
					previous->right= newnode;
			} // inner if
		} // middle if
	} // outer if
	if (ok==true) {
		operationType operation;
		operation.lastInfo= rec;
		operation.lastChangeWas= ADD;
		changes.push(operation);
	} // if
} // treeClass::addRec

void treeClass::deleteRec (char code[keyLength]) {
// deletes record with code = key if it exists

	node *current,           // Pointer to the current node
			 *previous;         // Pointer to the previous node
	current = root;          // Set current node to the head of the list
	bool wentRight;
	recType r;

	findRec (code, r);
	if (!allOK()) {
		ok= false;
		return;
	}
	ok= true;

	// Search the tree for the code to be deleted
	previous = NIL;                       // There is no node before the root

	// Loop until record is found
	while (current!=NIL && strcmp(current->item.key, code) != 0) {
		previous= current;
		if (strcmp(current->item.key, code) > 0) {
			current = current->left;
			wentRight= false;
		} else {
			current = current->right;
			wentRight= true;
		}
	} // while

	if (current->right == NIL) {//deletion conditions
		if (previous == NIL)
			root= current->left;
		else if (wentRight)
			previous->right= current->left;
		else
			previous->left= current->left;
	} else if (current->left == NIL) {
		if (previous == NIL)
			root= current->right;
		else if (wentRight)
			previous->right= current->right;
		else
			previous->left= current->right;
	} else {
	// has 2 children
		node *tempCurr, *tempPrev;
		tempPrev= NIL;

		// move to left sub-tree
		tempCurr= current->left;

		// find largest node in left sub-tree
		while (tempCurr->right != NIL) {
			tempPrev= tempCurr;
			tempCurr= tempCurr->right;
		}

		if (previous == NIL)
			root= tempCurr;
		else if (wentRight)
			previous->right= tempCurr;
		else
			previous->left= tempCurr;
		tempCurr->right= current->right;
		if (tempPrev != NIL) {
			tempPrev->right= tempCurr->left;
			tempCurr->left= tempPrev;
		}
	} // else if

	// update for undo
	operationType operation;
	operation.lastInfo= current->item;
	operation.lastChangeWas= DELETE;
	changes.push(operation);
	
	delete current;
} // treeClass::deleteRec

void treeClass::findRec (char code[keyLength], recType &rec) {
// returns record with key = code
	node *current;
	current=root;

	// Loop until record located, or is not found
	while (current!=NIL && strcmp(current->item.key, code) != 0)
		if (strcmp(current->item.key, code) > 0)
			current = current->left;
		else
			current = current->right;

	if (current == NIL)
		ok= false;
	else {
		ok= true;
		rec= current->item;
	}
} // treeClass::findRec

void treeClass::updateRec (recType rec) {
// locates and replaces current entry with rec
	recType temp;
	operationType operation;
	findRec (rec.key, temp);
	if (ok) {
		deleteRec(rec.key);
		changes.pop(operation);
		if (ok) {
			addRec(rec);
			changes.pop(operation);
			operation.lastInfo= temp;
			operation.lastChangeWas= UPDATE;
			changes.push(operation);
		} // if
	} // outer if
} // treeClass::updateRec

void treeClass::undo() {
// undoes the most recent operation
	operationType operation;
	if (changes.pop(operation)) {
		switch (operation.lastChangeWas) {
			case ADD: deleteRec(operation.lastInfo.key); break;
			case DELETE: addRec (operation.lastInfo); break;
			case UPDATE: updateRec (operation.lastInfo); break;
			default: {
				cerr <<"Program error.  Failure in undo." <<endl;
				exit(1);
			} // default
		} // switch
		changes.pop(operation);	// remove the record on stack from undo operation
	} else
		ok= false;
} // treeClass::undo



bool treeClass::allOK () {	// returns value of ok, then resets it to true
	bool temp= ok;
	ok= true;
	return temp;
} // treeClass::allOK


void treeClass::inTraversal () {
// outputs the binary tree in 'sideways' tree form
	rectotal=0;
	inTraversalRecur (root);
	cout <<endl;
} // treeClass::inTraversal


void treeClass::inTraversalRecur(node *it) {
// private- used by inTraversal
	static int level= 0;
	int ctr;
	if (it != NIL) {
		rectotal++;
		level++;
		inTraversalRecur (it->right);
		for (ctr=1; ctr<level; ctr++)
			cout <<"\t";
		cout <<it->item.key <<endl;
		inTraversalRecur (it->left);
		level--;
	}
} // gtreeClass::inTraversalRecur

void treeClass::inLevels(){//Initializes values to track tree levels & prints them
	double averaged;
	max=0;
	min=-1;
	avg=0;
	levelcount=0;
	treeLevels(root);//calls level tracker
	averaged=((double)avg/(double)levelcount);//finds average
	if(root!=NIL){
	cout<<endl<<"Min level: "<<min<<"  Avg level: "<<averaged<<"  Max level: "<<max<<endl;//prints
	}
	else{
		cout<<endl<<"Min level: 0"<<"  Avg level: 0"<<"  Max level: 0"<<endl;
	}

}

void treeClass::treeLevels(node *it){//Prints out largest and smallest tree levels
		static int level= 0;
		
		
	int ctr;
	if (it != NIL) {
		level++;
		if(level>max){//Keeps track of max level
			max=level;
			if(it->left==NIL && it->right==NIL && min==-1){//If min isn't set yet, and at end of a branch, sets it
				min=level;
			}
		}
		else if(level<min && it->left==NIL && it->right == NIL){//If min is set and lower value is found, sets it
			min=level;
		}
		if(it->right==NIL && it->left==NIL){//Gets average
			avg+=level;
			levelcount++;
		}
		//Continue on down the tree, and decrement level to backtrack when done.
		treeLevels (it->right);
		treeLevels (it->left);
		level--;
		
}
	
}

/////////////////////////////////////
//    stack class implementation   //
/////////////////////////////////////

stack::stack() {
		head = NIL;
} // stack::stack

stack::~stack() {
	clearStack();
} // stack::~stack

void stack::clearStack() {
	node *previous;
	while (head!=NIL) {
		previous = head;
		head = head->next;
		delete previous;
	} // while
} // stack::clearStack

void stack::push(operationType value) {
    node *newnode;
    newnode = new node;
		if (newnode==NIL) {
				cerr << "out of memory in stack::push!" << endl;
        exit (1);
		}
    newnode->item = value;
    newnode->next = head;
		head = newnode;
} // stack::push

bool stack::pop(operationType &olditem) {
		node *oldnode= head;
		if (empty())
			return false;
		olditem = head->item;
		head = head->next;
    delete oldnode;
		return true;
} // stack::pop

bool stack::empty() {
	if (head==NIL)
		return true;
	else
		return false;
} // stack::empty

	 ///////////////////////////
	//  Test Driver Program //
 //////////////////////////

// prototypes
void menuResponse(char &ch);
void runMenu (treeClass &p);

int main () {
	treeClass portfolio; // a portfolio of stocks
	recType s;	// one record; holds information about 1 stock

	portfolio.inTraversal();
	portfolio.inLevels();
	runMenu (portfolio);
	
	cin.get();

	return(0);
} // main


void runMenu (treeClass &p) {
// operates a menu for the stock portfolio
	char recName[keyLength];
	char ch;
	recType s;	// one record; holds information about 1 stock
	do {
		menuResponse (ch);
		switch (ch) {
			case 'A': // add a record
				cout <<"First Name: ";
				cin >>s.key;
				cout <<"Last Name: ";
				cin >>s.lName;
				cout<<"Street Address: ";
				cin.getline(s.addString, 39);//Just picks up trash, no input even allowed.
				p.addRec (s);
				break;
			case 'D': // delete a record
				cout <<"Stock key to delete: ";
				cin >>recName;
				p.deleteRec(recName);
				break;
			case 'F': // find a record
				cout <<"Stock to find: ";
				cin >>recName;
				p.findRec (recName, s);
				cout <<s.key <<' ' <<s.lName <<endl <<s.addString<<endl;
				cout <<endl;
				break;
			case 'H': // how many record
				cout <<"There are "<<p.howManyRec() <<" stocks." <<endl;
				break;
			case 'L':	// load records from disk
				p.fetchFromDisk ("c:/temp/trash.dat");
				break;
			case 'N': // undo last add, delete, update
				p.undo();
				break;
			case 'P': // update record
				cout <<"First Name: ";
				cin >>s.key;
				cout <<"Last Name: ";
				cin >>s.lName;
				cout<<"Street Address: ";
				cin.getline(s.addString, 39);//Same problem, garbage, no input opportunity
				p.updateRec (s);
				break;
			case 'R': // removes all records
				p.deleteAllRecords ();
				break;
			case 'S':	// store all records to disk
				p.storeToDisk ("c:/temp/trash.dat");
				break;
		} // switch
		if (!p.allOK())
			cout <<"Process failed." <<endl;
		p.inTraversal();
		p.inLevels();

	} while (ch != 'Q');
} // runMenu

void menuResponse (char &ch) {
	cout
		<<endl
		<<"Choose a letter:\n"
		<<"   (A)dd a record         u(N)do last add/delete/update\n"
		<<"   (D)elete a record      u(P)date a record\n"
		<<"   (F)ind a record         (Q)uit\n"
		<<"   (H)ow many records?     (R)emove all records\n"
		<<"   (L)oad from disk        (S)tore to disk"
		<<endl;
	cin >>ch;
	ch= toupper(ch);
	//error trapping goes here
} // menuResponse

  #5  
Old 01-Dec-2005, 10:14
WaltP's Avatar
WaltP WaltP is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Midwest US
Posts: 3,243
WaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to allWaltP is a name known to all

Re: Strings tripping me up once more


Quote:
Originally Posted by Elsydeon
I originally thought I just didn't understand the basics of strings, why I didn't post my code. But it finally came to me to copy the code taking in the string from my program into it's own small one and run it. Since it works there, but not in this one, something else must be going on. The problem is in my add and update options. Look to the runmenu method near the bottom of the program.
cin.getline() should have fixed the problem you claimed you were having.
I see you're also using cin to read a single character. Use cin.getline() here too. When you read one character the ENTER is left in the buffer for the next cin. You should probably use cin.getline() for all inputs.

If this isn't the problem, be specific. Details are important.

Also, looking at the function you mention:
CPP / C++ / C Code:
void menuResponse (char &ch) {
	cout
		<<endl
		<<"Choose a letter:\n"
		<<"   (A)dd a record         u(N)do last add/delete/update\n"
		<<"   (D)elete a record      u(P)date a record\n"
		<<"   (F)ind a record         (Q)uit\n"
		<<"   (H)ow many records?     (R)emove all records\n"
		<<"   (L)oad from disk        (S)tore to disk"
		<<endl;
	cin >>ch;
	ch= toupper(ch);
	//error trapping goes here
} // menuResponse
the problem I see is is a style problem. The entire concept of the function is to return a character. There is nothing needed as a parameter. Therefore the function should be defined as
CPP / C++ / C Code:
char menuResponse()
instead.


Quote:
Originally Posted by Elsydeon
On a side note, I know I've been told before that the .h at the end of includes is archaic and to switch, but for the compiler I've been using I don't seem to have a choice. Says it can't find them otherwise. I did switch the void main we were given to int main.
You should upgrade then. There are compilers available that are good and free.
Check out Borland as one possibility, a lot of people here use Bloodshed DevC. Technically, as long as you are programming in Standard C/C++ any compiler should work. If yours is too old, it should be replaces so you can use Standard C/C++.


Quote:
Originally Posted by Elsydeon
Sorry if the spacing is off.
If you're worried about your spacing (and that's a good thing to be concerned with), this will help.
__________________

Age is unimportant -- except in cheese
  #6  
Old 04-Dec-2005, 17:41
Elsydeon Elsydeon is offline
Junior Member
 
Join Date: Aug 2005
Posts: 45
Elsydeon is on a distinguished road

Re: Strings tripping me up once more


Yeah, I had the same thoughts about that method. But we're given basic frameworks to use for a lot of his programs, sort of the "In the real world you have to work with other people's usually flawed code" deal. So the basic structure, method arguments, etc are to be left alone according to our instructions.

But yes, converting all my cins to getlines did the trick. It just took a little tinkering to get it going right. Unfamiliar code for me. Have one odd bug where my menu repeats an extra time using certain options, but I can get that. Just a logic problem.
 
 

Recent GIDBlogMeeting the local Iraqis by crystalattice

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Declaring an array of strings dynamically (C Language) Hyuga C Programming Language 5 03-Aug-2005 09:18
need help - questions about strings Benayoun C Programming Language 6 24-Jan-2005 02:15
array of pointers to strings mirizar C++ Forum 5 21-Jan-2005 10:24
C++ style strings and STL dexter C++ Forum 14 04-Jan-2005 07:46
I am reviewing Arrays and need help converting some strings to arrays jenmaz C Programming Language 22 22-Nov-2004 23:26

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 05:51.


vBulletin, Copyright © 2000 - 2008, Jelsoft Enterprises Ltd.