0

I'm trying to solve the exercise 22 (chapter 4) from Thinking in C++ but there's something that I'm missing because also after a few days of work, my solution doesn't do it's job. I don't like so much to ask for help in solving exercises, but in this moment I'm feeling overwhelmed.

Create a Stack that holds Stashes. Each Stash will hold five lines from an input file. Create the Stashes using new. Read a file into your Stack, then reprint it in its original form by extracting it from the Stack.

#include "CppLib.h"
#include "Stack.h"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

using namespace std;

//typedef unsigned int uint;

int main() {
    ifstream in("main.cpp");

    Stack stackStashes;
    stackStashes.initialize();

    Stash linesStash;
    linesStash.initialize(sizeof(char) * 80);

    string line;
    bool flag = true;
    while (flag) {
        for (int i = 1; flag && (i <= 5); i++) 
            if ((flag = (bool)getline(in, line)))
                linesStash.add(line.c_str());

        if (flag) {
            stackStashes.push(new Stash(linesStash));
            linesStash.cleanup();
            linesStash.initialize(sizeof(char) * 80);
        }
    }

    Stash* s;
    char* cp;
    int z = 0;
    while ((s = (Stash*)stackStashes.pop()) != 0) {
        while ((cp = (char*)s->fetch(z++)) != 0) 
            cout << "s->fetch(" << z << ") = "
                 << cp << endl;

        delete s;
    }

    s->cleanup();
    stackStashes.cleanup();
    return 0;
}

I tried to solve it with vector, without using of flag, all of my solutions returned an error. Moreover, in all my experiment, this is oneo f the worse, but is the only one left.
Here are the libraries provided by the book. All the code below is written by Bruce Eckel.
CppLib.cpp, CppLib.h, Stack.cpp, Stack.h, require.h.

john
  • 7,897
  • 29
  • 27
Overflowh
  • 1,103
  • 6
  • 18
  • 40
  • 4
    And the error is? I think this is the 4th or 5th time I've said this today and it's only 10:49am. – Joseph Mansfield Apr 15 '13 at 09:49
  • That it doesn't work? When you try to run the console retun some lines and then windows kill the thread. – Overflowh Apr 15 '13 at 09:55
  • 2
    @sftrabbit That means you've got up too early :) – jrok Apr 15 '13 at 09:55
  • Your test will lose the last few lines of the file because flag will be false unless the file ends on a 5 line multiple. Check for empty instead. Otherwise, code looks good – stark Mar 20 '20 at 11:56

3 Answers3

1

Wow, that is pretty bad. I'm afraid there is nothing wrong with your code, only Bruce Eckel's. The problem is that the Stash object cannot be copied, but you make a copy here

 stackStashes.push(new Stash(linesStash));

which crashes the program.

No way you were to know. You'll have to rewrite your program something like this

while (flag) {
    Stash * stash_ptr = new Stash();
    for (int i = 1; flag && (i <= 5); i++) 
        if ((flag = (bool)getline(in, line)))
            stash_ptr->add(line.c_str());

    if (flag) {
        stackStashes.push(stash_ptr);
    }

Something like that anyway, I haven't tested it. The point is that it does not copy any Stash object, everything is done via a Stash pointer.

Suggest you try a better book? Although to be fair to Bruce Eckel it's possible that he hasn't introduced the concept of object copying yet and didn't anticipate that anyone would write code that attempted to copy a Stash.

john
  • 7,897
  • 29
  • 27
  • Ehm but.. when I wrote that like I was pretty sure that its task should be to "take the Stack -> add another element with push -> this element should be a brand NEW linesStash casted to a Stash". Why this become a copy? However you are right, the book still not introduced the concept of object copying. – Overflowh Apr 15 '13 at 11:32
  • (However, could you suggest me a better book aynway? Thanks.) – Overflowh Apr 15 '13 at 11:33
  • @unNaturhal `stackStashes.push(new Stash(linesStash))` creates a new Stash object but initalizes it by *copying* the existing `linesStash` object. In C++ terms you are calling the *copy constructor*. My version uses `new Stash()` instead of `new Stash(linesStash)` so it calls the *default constructor*. – john Apr 15 '13 at 12:08
  • @unNaturhal There's a list of books here http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – john Apr 15 '13 at 12:09
  • So.. you are saying that it's enough to "push" a new GENERIC Stash object, instead of a more specific linesStash each time? I thought that was necessary to create a new pointer to an object with the characteristcs of linesStash, so to contain new values.. – Overflowh Apr 16 '13 at 14:48
  • Ok, I tried the modifications just right now: it crashes without printing nothing.. – Overflowh Apr 16 '13 at 15:01
  • My code does not push a generic Stash object. It creates a specific Stash object in pretty much the same way as your code did. Sorry I can't help you with the crash you are currently seeing. I'd need to see the code you are actually using (and the input as well) – john Apr 16 '13 at 15:38
0

I also struggled a lot with this excercise, but finally solved. I hope this is what you were looking for.

Please check this main.cpp: it works as it should with the original sources (which have you linked in the question) without any modifications made on them.

I hope this helps. Feel free to ask if anything remained unclear.

//Create a Stack that holds Stashes. Each Stash will hold
//five lines from an input file. Create the Stashes using
//new. Read a file into your Stack, then reprint it in its
//original form by extracting it from the Stack.

#include <iostream>
#include <fstream>
#include "cpplib.h"
#include "stack.h"
#include <stdexcept>
#include <string>
#include <cstdlib>

const std::string FILENAME = "file.txt";
const unsigned int LINES_PER_STASH = 5;
const unsigned int MAX_LINE_LENGTH = 80;

int main(){

  std::ifstream in;

  try
  {
    in.open(FILENAME.c_str(),std::ios_base::in);
    if(!in.is_open())
    {
      throw new std::exception();
    }
  }
  catch(...)
  {
    std::cout << "Error should be handled" << std::endl;
    exit(-1);
  }



  unsigned int lineCount = 0;

  Stack stack;
  stack.initialize();

  Stash* pStash = 0;
  std::string line;

  while(std::getline(in, line) )
  {
    if(! (lineCount % LINES_PER_STASH))
    {
      if(lineCount)
      {
        stack.push(pStash);
      }
      pStash = new Stash();
      pStash->initialize(MAX_LINE_LENGTH);
    }
    pStash->add(line.c_str());

    lineCount++;
  }
  if(0 < pStash->count()) {
        stack.push(pStash);
  }

  in.close();


  Stash* tempStash;
  Stack* pTempStack = new Stack();
  pTempStack->initialize();


  //revert the order of stashes in a new stack
  while((tempStash = static_cast<Stash*>(stack.pop())) != 0)
  {
    pTempStack->push(tempStash);
  }

  stack.cleanup();



  while(0 != (tempStash = static_cast<Stash*>(pTempStack->pop()) ) )
  {
    //a more elegant and consistent way should be to solve this loop with 'while', still 'for' and worked fine at first try, so I left it as it is:
    for(int i = 0; i < LINES_PER_STASH; i++){
      std::cout << (char*)tempStash->fetch(i) << std::endl;
    }
    delete tempStash;
  }

  pTempStack->cleanup();
  delete pTempStack;  

  return 0;
}
Janos
  • 650
  • 8
  • 13
0

I got a solution for Exercise 23 also.

Modify Exercise 22 so that you create a struct that encapsulates the Stack of Stashes. The user should only add and get lines via member functions, but under the covers the struct happens to use a Stack of Stashes.

The source code of Stack.cpp

#include "CppLib.h"
#include "Stack.h"
#include "require.h"
using namespace::std;

const int bufsize = 80;

void Stack::Link::initialize(Stash* dat, Link* nxt) {
    data = dat;
    next = nxt;
}

void Stack::initialize() {
    head = 0;

    Stash* stash = new Stash;
    stash->initialize(sizeof(char) * bufsize);
    Link* newLink = new Link;
    newLink->initialize(stash, head);
    head = newLink;
}

void Stack::push(const void * element) {
    // each stash stores 5 lines
    if (head->data->count() < 5) {
        head->data->add(element);
    } else {
        // Push old stash
        Link* newLink = new Link;
        newLink->initialize(head->data, head);
        head = newLink;
        // Create new stash
        Stash* newStash = new Stash;
        newStash->initialize(sizeof(char) * bufsize);
        head->data = newStash;
        // Add element to new stash
        head->data->add(element);
    }
}

void* Stack::peek() {
    require(head != 0, "Stack empty");
    return head->data->fetch(head->data->next);
}

void* Stack::pop() {
    if (head == 0) return 0;

    void* result;
    Stash* stash = head->data;
    int index = stash->next;
    // retrieve next stash
    if (index < 1) {
        stash->cleanup();
        head = head->next;
        if (head == 0) return 0; // Check if next stash exists
        stash = head->data;
        index = stash->next;
    }
    // pop 5 lines within stash
    result = stash->fetch(index - 1);
    stash->next = index - 1;

    return result;
}

void Stack::cleanup() {
    require(head == 0, "Stack not empty");
}
Epping_
  • 29
  • 2
  • 6