As was foretold, we've added advertisements to the forums! If you have questions, or if you encounter any bugs, please visit this thread: https://forums.penny-arcade.com/discussion/240191/forum-advertisement-faq-and-reports-thread/

C++ prototyping help

clsCorwinclsCorwin Registered User regular
edited March 2007 in Help / Advice Forum
Alright, so my teacher really hasn't explained how prototyping and header files work really, he just showed up how to do it before. We used this before to make array based stacks and queues.

Heres the array based stack:
Stack.cpp
#include "Stack.h"
#include <iostream>
using namespace std;

STACKDATA sd;
int top;

Stack::Stack()
{
}

Stack::~Stack()
{
}
	
void Stack::create()
{
	top = 0;
}

void Stack::destroy()
{
	top = 0;
}

bool Stack::full()
{
	return top >= STACKMAX;
}

bool Stack::empty()
{
	return top == 0;
}

void Stack::push(char ch)
{
	sd[top++] = ch;
}
void Stack::pop(char &ch)
{
	ch = sd[--top];
}

int Stack::getTop()				//useful if position of top needs to be accessed
{
	return top;
}
Stach.h
#pragma once
const int STACKMAX = 100;
typedef char STACKDATA[STACKMAX];

class Stack
{
	STACKDATA sd;
	int top;

public:
	Stack();
	~Stack();
	void create();
	void destroy();
	bool full();
	bool empty();
	void push(char ch);
	void pop(char &ch);
	int getTop();
};

So now, we're writing dynamic versions, you know, linked-lists. Right now, this is what my current Stack.cpp looks like, since I don't know how I would prototype my added Node struct in with this. Should I make a Node.h with just the struct? Put it in the Queue.h and Stack.h files? Enlighten me please. =)

Dynamic Stack.cpp
struct NODE
{
	int data;
	NODE *next;
	NODE *last;
};

class STACK
{
	NODE *top;

	void create()
	{
		top = 0;
	}

	void destroy(NODE *n)
	{
		if( n->next == 0 )
			delete n;
		else
			destroy(n->next);
	}

	bool full()
	{
		NODE *temp;
		return temp == 0;
	}

	bool empty()
	{
		return top->next == 0 && top == 0;
	}

	void push(char ch)
	{
		NODE *temp;
		temp = new NODE;
		temp->data = ch;
		temp->next = top;
		top = temp;
		delete temp;
	}

	void pop(char &ch)
	{
		NODE *temp;
		temp = top;
		top = top->next;
		ch = temp->data;
		delete temp;
	}
};

clsCorwin on

Posts

  • ThornMartinThornMartin Registered User regular
    edited March 2007
    Think about it this way: a header file is where you say what the class is; the .cpp file is where you define how its methods work.

    For example, look at the Stack.h that you posted: it says what the class is, all of its attributes, and all of its methods. However, it does not provide definitions to those methods; that is, you only know how they work by looking at the .cpp.

    So, all of the class Stack{ ... } declaration stuff goes in the header file and the function definitions (such as void Stack::create() {...}) go into the .cpp. When creating your new class, I would model it after the Stack.h and Stack.cpp that you posted.

    Finally, to answer your question, I would put struct NODE { ... } in the header file. If you foresee using it in multiple distinct classes (such as in a queue class, which would have no other reason to include stack.h), then it may be beneficial to put it in one location (it's own Node.h, like you mentioned, or some other common header file), so that you won't have to redefine it in multiple places.

    EDIT: Also, I just took note of this:
            void destroy(NODE *n)
            {
                    if( n->next == 0 )
                            delete n;
                    else
                            destroy(n->next);
            }
    

    This isn't doing the same thing as the original Stack::destroy, unless the caller passes in the top of the stack (which they won't be able to access unless they are part of the class, since top is private [as it should be] ). You may want to think about what this method is supposed to do and keep the prototype the same as in the original (that is, keep it as void destroy() (note the lack of parameters)).

    ThornMartin on
  • JHunzJHunz Registered User regular
    edited March 2007
    Well, it depends on how anal you want to be about separating your code.
    I'd go with either sticking the Node definition either at the top of the Stack.h, or making a Node.h with it and including it. The former is probably quite sufficient for this kind of project.

    Unsolicited advice below:

    You don't seem to understand the purpose of constructors and destructors. Why do you have a create() function? Anything you would bother putting in a create() function should be straight in the constructor. You should also be allocating the memory for your first Node here.
    Your destroy function seems as though you intend to just call it with the parameter top - you should really make a proper destructor that iterates through and deletes each node.

    Your full() function makes no sense, but I assume that's because you haven't finished writing it.
    if( n->next == 0 )
    
    You should never write that unless you've already tested whether n is a valid pointer, otherwise you're going to have a hell of a time figuring out why your program is crashing.

    JHunz on
    bunny.gif Gamertag: JHunz. R.I.P. Mygamercard.net bunny.gif
  • PhilodoxPhilodox Registered User regular
    edited March 2007
    I'm not going to tell you what it is, but there's a pretty bad bug in your empty function. I guarantee it will crash every time if the stack is actually empty.

    Philodox on
    That's a Freudian mansex if I ever cocked one.
    twinsbanneroq0.jpg
  • clsCorwinclsCorwin Registered User regular
    edited March 2007
    Well, I know everything is buggy right now. This is the first time I've played with pointers, so, yea. As I said, I just needed help with the prototyping, how I would actually package everything better. Once I know how its structured, then I can actually run my program, and see what my code is doing.

    The code I have right now is just top of the head thoughts as to how it might work.

    clsCorwin on
  • clsCorwinclsCorwin Registered User regular
    edited March 2007
    Oh, and I changed my empty function anyways. I figure, knowing how many nodes I have would be good, so I made a counter that will increment with each push and decrement with the pops. Thus empty would be

    return count == 0;

    But I still need to figure out everything else.

    clsCorwin on
  • BamaBama Registered User regular
    edited March 2007
    You can actually place the definition of Node inside the specification of Stack if you want. Doing that lets you use a relatively common class name like "Node" without fear of naming conflicts, but that's not really a concern with this project anyway. However, be aware that (unless you put it in the "public" part of your class) the Node class will be inaccessible outside of the Stack class. This shouldn't be much of a problem, since the using code doesn't need to know how you're storing things internally and just cares about the data it gives Stack to store.

    As others have mentioned, there's some bad stuff going on in the functions you have there. If things don't become more clear before that assignment is due, I'm sure there are a lot of people here (myself included) willing to help you out. Pointers and linked-lists are one of the classic hurdles presented to beginning programmers, so don't be discouraged if it seems difficult and unintuitive.

    Bama on
  • clsCorwinclsCorwin Registered User regular
    edited March 2007
    I know. I'm well ahead of the class, I'm just trying to knock it out early, you know? So far my teacher's only given one lecture on pointers, which basically covered how a pointer to some value can be used to change that value as well, among some of the other basics.

    But if I need help, you know I'll ask.

    clsCorwin on
  • BamaBama Registered User regular
    edited March 2007
    Yea, you actually replied twice in the time it took me to write that post (curse you, ADD!). I figured it was just scratchwork and that you had more pointer-related lectures ahead. Good job keeping ahead of things; I wish I could do that more.

    Bama on
  • clsCorwinclsCorwin Registered User regular
    edited March 2007
    Yea, just playing around with things trying to figure them out before the teacher really gets around to it.

    But yea, I could have Node within stack and queue, but wouldn't it having its own header that is #included in both be more effecient?

    clsCorwin on
  • BamaBama Registered User regular
    edited March 2007
    If you're using the same node structure in both of those classes it makes sense to put it in its own file and have the using classes' headers include it. This is particularly true for complex classes that do more than just aggregate some primitives for you.

    Bama on
  • clsCorwinclsCorwin Registered User regular
    edited March 2007
    Word.

    Ok, quick help, wtf does:

    Dynamic Palindrome.obj : error LNK2019: unresolved external symbol "public: __thiscall STACK::STACK(void)" (??0STACK@@QAE@XZ) referenced in function "void __cdecl `dynamic initializer for 's''(void)" (??__Es@@YAXXZ)

    mean?

    clsCorwin on
  • clsCorwinclsCorwin Registered User regular
    edited March 2007
    Oh, and as for my full function, really the only way I can see a dynamic structure being full, is if there is no memory left to allocate to it. I was told that if there is no memory left and you try to create pointer, it will automatically set it to 0. Am I mistaken in this reasoning then?

    clsCorwin on
  • BamaBama Registered User regular
    edited March 2007
    It looks like that error is complaining that it can't find the definition of your stack's constructor. Usually you can get away without defining a constructor, but if you prototyped one and never defined it I guess you'd get a link error like that. If you did something like move the definition to a .cpp file, make sure to #include the header in the cpp.

    You're right that full() doesn't really make much sense for something that it just limited by heap size, and you've got the right idea with how to check for an allocation failure. That temporary pointer will always be created, and there's no guarantee what's going to be in it (it's unlikely that it's zero). Also, you're de-referencing that pointer and checking if the value at that address is zero. If you try to de-reference address 0, bad things will happen. Where you're going to get your zero pointer is when you try to allocate like in
    temp = new Node;
    
    because new will return zero address when it fails to allocate memory. Now if you do that and verify that the Node was allocated, then you're going to have to delete it since you aren't going to be putting it in your stack. This would just look like
    delete temp;
    

    Dynamically allocating memory and then losing all the pointers to it (such as when full() ends without deleting the node it created) is called "orphaning" and is how you get memory leaks. Therefore you should always think very carefully about how you're manipulating your pointers and the objects they point to. For example, what's in your create() should be in your constructor for a few reasons and one of them is that if create() gets called while there is stuff in the stack, you'll lose your pointer to the head and be unable to access all the nodes you created. You'll probably never do that, and you'll probably never give this code to someone else to use, but it's good to get in the habit of "idiot-proofing" your code as much as is reasonably possible.

    Ok, that was longer than I planned. I hope it wasn't too confusing.

    Bama on
  • clsCorwinclsCorwin Registered User regular
    edited March 2007
    Nope, makes perfect sense to me.

    clsCorwin on
Sign In or Register to comment.