Hey y'all. First post here in the C++ section.
I'm working on a commission for a client, and I'll be doggone if I can't figure this out. The code showing my issue is below. Here's a description of the setup - I'll keep it as short as I can.
I have 2 classes - Sentences and Sentence. Sentences houses each Sentence in a vector of pointers to each dynamically allocated Sentence.
Each Sentence has a "level", like 1, 5, 10, 15, etc. This is akin to COBOL if you are familiar with that. The level defines a hierarchy and groupings. In this example, these are my Sentence[s]:
The above would show length of 19 is simply added up.Code:name=FIELDA level=1, repeat=4 length=0 name=FIELDB level=5, repeat=1 length=5 name=FIELDC level=5, repeat=1 length=2 name=FIELDD level=1, repeat=1 length=12
What I am trying to do is apply the repeat factor and expand my vector to look like this:
The correct total length is 40.Code:name=FIELDA level=1, repeat=4 length=0 name=FIELDB level=5, repeat=1 length=5 name=FIELDC level=5, repeat=1 length=2 name=FIELDB#1 level=5, repeat=1 length=5 name=FIELDC#1 level=5, repeat=1 length=2 name=FIELDB#2 level=5, repeat=1 length=5 name=FIELDB#2 level=5, repeat=1 length=2 name=FIELDB#3 level=5, repeat=1 length=5 name=FIELDC#3 level=5, repeat=1 length=2 name=FIELDD level=1, repeat=1 length=12
FIELDB and FIELDC get repeated the number of times specified by FIELDA. FIELDD is ignored because it's level is not higher than FIELDA.
Although my test case does not show it, FIELDB or FIELDC could also have a repeat level, and there could be fields under it which would also have to be expanded.
So, my issue!! (finally).
In Sentence::replicate, I'm using 4 iterators to keep track of my position with the vector of Sentence pointers and iterator elem_start is changing (somehow) after the first loop. When variable j becomes 2, variable tmp gets corrupted due to elem_start being corrupt. I've put a lot of cout statements in the code and stepped through the code in the debugger, but I still cannot figure it out. (I'm using Xcode on Tiger 10.4.11).
Here's my current output:
And here's the code. The clause in RED causes the issue. I stepped through the code in the debugger and when j==2, that clause causes elem_start to become corrupt (0x1 is the corrupted value). What's going on????!!!Code:[Session started at 2007-12-24 07:44:35 -0600.] Sentence address = 0x3003e0 Sentence address = 0x300420 Sentence address = 0x300410 Sentence address = 0x300450 REPEAT level start=1, and there are 4 elements to add. Field with REPEAT is FIELDA last known good end field is FIELDB inspecting name=FIELDC, level=5, current repeat level=1... last known good end field is FIELDC inspecting name=FIELDD, level=1, current repeat level=1... starting field name = FIELDB ending field name = FIELDC Replicating FIELDB thru FIELDC 3 times. J = 1, tmp = 0x300420 Index name = FIELDB Index=0x300420, Last=0x300410 Top of DO loop... j = 1 Replicate Sentence address = 0x3004b0 temp name = FIELDB#1 temp length = 5 temp repeat = 1 temp level = 5 Index=0x300410, Last=0x300410 Top of DO loop... j = 1 Replicate Sentence address = 0x300480 temp name = FIELDC#1 temp length = 2 temp repeat = 1 temp level = 5 J = 2, tmp = 0x1
Any help is appreciated very much.Code:#include <iostream> #include <string> #include <vector> #include <iomanip> #include <sstream> using namespace std ; ////////////////////////////////////////////////////////////////////////////////////////////////////////// class Sentence { int level ; int repeat ; int length ; string name ; public: // Member Method Declarations (setters / getters) Sentence() ; void set_level(int) ; int get_level() ; void set_repeat(int) ; int get_repeat() ; void set_length(int) ; int get_length() ; void set_name(string) ; string get_name() ; } ; // Member Method definitions Sentence::Sentence() { // class Constructor repeat = 1 ; // assume field does not repeat } void Sentence::set_level(int n) { level = n ; } int Sentence::get_level() { return level ; } void Sentence::set_name(string s) { name = s ; } string Sentence::get_name() { return name ; } void Sentence::set_repeat(int n) { repeat = n ; } int Sentence::get_repeat() { return repeat ; } void Sentence::set_length(int n) { length = n ; } int Sentence::get_length() { return length ; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// class Sentences { vector<Sentence *> sentences ; vector<Sentence *>::iterator elem , elem2, elem_start , elem_end ; int i ; // index public: Sentences::Sentences() ; // Constructor declaration void add_sentence(Sentence *) ; int sentence_count() ; void reset() ; void set_range_start() ; void set_range_end() ; Sentence * next() ; Sentence * next2() ; void replicate(int) ; } ; Sentences::Sentences() { i = 0 ; } void Sentences::add_sentence(Sentence * s) { sentences.push_back(s) ; } int Sentences::sentence_count() { return sentences.size() ; } void Sentences::reset() { i = 0 ; elem = sentences.begin() ; elem2 = sentences.begin() ; } void Sentences::set_range_start() { elem_start = elem2 ; } void Sentences::set_range_end() { elem_end = elem2 ; } Sentence * Sentences::next() { elem2 = elem ; return *elem++ ; } Sentence * Sentences::next2() { elem2++ ; return *elem2 ; } void Sentences::replicate(int times) { Sentence * temp, * index , * last ; // we're adding new sentences. stringstream ss ; vector<Sentence *>::iterator tmp_start, tmp ; cout << "Replicating " << (*elem_start)->get_name() << " thru " << (*elem_end)->get_name() << " " << times << " times." << endl << endl ; tmp_start = elem_start ; last = *elem_end ; for (int j = 1 ; j <= times ; j++ ) { // Add "times" elements tmp = tmp_start ; index = *tmp ; cout << "J = " << j << ", tmp = " << *tmp << endl ; cout << "Index name = " << index->get_name() << endl ; cout << "Index="<< index << ", Last=" << last << endl ; do { cout << "Top of DO loop... j = "<< j << endl ; temp = new Sentence() ; // Allocate a new sentence cout << "Replicate Sentence address = " << temp << endl ; ss.str("") ; // reset to empty. ss << index->get_name() << "#" << j ; temp->set_name( ss.str() ) ; // Add a suffix to the field name cout << "temp name = " << temp->get_name() << endl ; temp->set_length(index->get_length()) ; cout << "temp length = " << temp->get_length() << endl ; temp->set_repeat(index->get_repeat()) ; cout << "temp repeat = " << temp->get_repeat() << endl ; temp->set_level(index->get_level()) ; cout << "temp level = " << temp->get_level() << endl ; sentences.insert(elem+1, temp) ; if ( index->get_name() == last->get_name() ) break ; // exit if the field name just added matches the last name. tmp++ ; index = *tmp ; cout << "Index="<< index << ", Last=" << last << endl ; } while (1) ; } } ////////////////////////////////////////////////////////////////////////////////////////////////////////// int main (int argc, char * const argv[]) { Sentences * sentences ; // A pointer to "Sentences" class sentences = new Sentences() ; // We only get one of these. Sentence * sen ; // A pointer to a Sentence sen = new Sentence() ; cout << "Sentence address = " << sen << endl ; sen->set_level(1); sen->set_name("FIELDA") ; sen->set_length(0) ; sen->set_repeat(4) ; sentences->add_sentence(sen) ; sen = new Sentence() ; cout << "Sentence address = " << sen << endl ; sen->set_level(5) ; sen->set_name("FIELDB") ; sen->set_length(5) ; sentences->add_sentence(sen) ; sen = new Sentence() ; cout << "Sentence address = " << sen << endl ; sen->set_level(5) ; sen->set_name("FIELDC") ; sen->set_length(2) ; sentences->add_sentence(sen) ; sen = new Sentence() ; cout << "Sentence address = " << sen << endl ; sen->set_level(1) ; sen->set_name("FIELDD") ; sen->set_length(12) ; sentences->add_sentence(sen) ; sentences->reset() ; // Loop through all sentences, and expand all repeating clauses. // First, find a clause that contains a REPEAT clause and note it's level number. Note's it's index. // Get the range of all immediately following sentences with a lower level number. // Reinsert that range "repeat-1" times, altering the name to suffix a "#n", where "n" is the repeat number. // Continue with next clause following "start" until done. int current_repeat_level ; int current_repeat ; Sentence * s_start, * s_end ; // first and last to insert sentences->reset() ; for ( int i = 0 ; i < sentences->sentence_count() ; i++ ) { sen = sentences->next() ; if (sen->get_repeat() > 1) { current_repeat = sen->get_repeat() ; current_repeat_level = sen->get_level() ; cout << "\nREPEAT level start=" << current_repeat_level << ", and there are " << current_repeat << " elements to add." << endl ; cout << "Field with REPEAT is " << sen->get_name() << endl ; sen = sentences->next2() ; // set second iterator sentences->set_range_start() ; // set 2nd iterator up s_start = sen ; // starting element do { s_end = sen ; // assume this is the last one sentences->set_range_end() ; cout << "\tlast known good end field is " << sen->get_name() << endl ; sen = sentences->next2() ; // get next sentence cout << "\tinspecting name=" << sen->get_name() << ", level=" << sen->get_level() << ", current repeat level=" << current_repeat_level << "..." << endl; } while (sen->get_level() > current_repeat_level) ; // see if it's the last one // Now, add new elements cout << "starting field name = " << s_start->get_name() << endl ; cout << "ending field name = " << s_end->get_name() << endl ; sentences->replicate(current_repeat-1 ) ; } } //****************************************************************** // Now, loop through all statements, and accumulate the total length // Should be 40 sentences->reset() ; int total_length = 0 ; for ( int i = 0 ; i < sentences->sentence_count() ; i++ ) { sen = sentences->next() ; total_length += sen->get_length() ; cout << "Level=" ; cout << right << setw(2) << setfill('0') << sen->get_level() ; cout << left << ", " << setw(30) << setfill(' ') << ("'" + sen->get_name() + "'") ; // left justify, pad to 30 bytes if (!sen->get_length() == 0) { cout << endl ; continue ; } cout << ", len=" << right << setw(2) << setfill('0') << sen->get_length() ; } cout << "Done." << endl ; return 0; }
Thanks, Todd



LinkBack URL
About LinkBacks


