动态堆栈分配(来自Thinking in C ++)

时间:2013-04-15 09:47:40

标签: c++ stack

我正在尝试解决 Thinking in C ++ 中的练习22(第4章),但有些东西我不见了,因为经过几天的工作,我的解决方案不做这是工作。我不太喜欢在解决练习方面寻求帮助,但在这一刻我感到不知所措。

  

创建一个包含Stashes的堆栈。每个Stash将保持五行   来自输入文件。使用new创建Stashes。将文件读入   你的堆栈,然后通过从中提取它以原始形式重新打印它   堆栈。

#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;
}

我试图用vector解决它,而不使用flag,我的所有解决方案都返回了一个错误。而且,在我的所有实验中,这是更糟糕的,但是唯一剩下的 这是本书提供的图书馆。以下所有代码均由Bruce Eckel撰写 CppLib.cppCppLib.hStack.cppStack.hrequire.h

3 个答案:

答案 0 :(得分:1)

哇,这很糟糕。我担心你的代码没有任何问题,只有Bruce Eckel的代码。问题是Stash对象无法复制,但您在此处复制

 stackStashes.push(new Stash(linesStash));

会导致程序崩溃。

你根本不知道。你必须像这样重写你的程序

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);
    }

无论如何,我还没有测试过。关键是它不会复制任何Stash对象,一切都是通过Stash指针完成的。

建议你尝试一本更好的书吗?尽管对Bruce Eckel公平,但他可能还没有引入对象复制的概念,并且没有预料到有人会编写试图复制Stash的代码。

答案 1 :(得分:0)

我也在这个练习中苦苦挣扎,但终于解决了。我希望这就是你要找的东西。

请检查一下这个main.cpp:它与原始资源(你在问题中已经链接)一样工作,而不对其进行任何修改。

我希望这会有所帮助。如果有什么不清楚,请随时询问。

//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;
}

答案 2 :(得分:0)

我也有练习23的解决方案。

修改练习22,以便您创建一个结构来封装堆栈。用户只能通过成员函数来添加和获取行,但是在隐蔽的情况下,该结构恰巧使用了堆栈堆栈。

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");
}