-2

Ok so i am writing a program for class and I am not very familure with the ways of c++. I have looked into char arrays and can not figure out the issue. It seems like when allocating the space the null terminator is not assigned in the desired location.

My issue is this. I am allocating an array see below:

char* St ="";

if(P.GetSize() > 0)
{
    int StLen = P.GetSize() + 1;
    St= new char[StLen];

    int i;
    for( i = 0;!P.isEmpty() && i < (int)strlen(St); i++)//StLen
    {
        *(St+i)= P.getTop();

        P.Pop();
    }
    *(St+i) = 0;
    std::reverse( St, &St[ strlen( St ) ] ); //flip string to display bottom to top
}

if P.GetSize() is 1 and I add one for the null terminator the line (int)strlen(St) is still returning 16 for the length which is the original length of my array read in. I have posted My working Program Below for reference for other people that have the same issue

Below Is my working solution Header File:

 //Created By : Timothy Newport
//Created on : 4/26/2012
//===========================================
// NewportStack.h
//============================================
#pragma once

#include <iostream>
#include <iomanip>
#include <fstream>
#include <crtdbg.h>
#include <stack>
#include <string>
using namespace std;

const int MAX_POSTFIX = 30;
void infixToPostfix(const char *infix, char* postfix,ostream& os);
void WriteHeader(ostream& os);
void WriteResults(ostream& os,const char *postfix);

template<class T>
struct Node
{
    T data;
    Node<T> *prev;
};

template<class T>
class NewportStack
{
    private:        
        Node<T> *top; 
        int size;
    public:
        NewportStack();
        NewportStack(const NewportStack <T> & displayStack);
        ~NewportStack();
        void Push(T ch);
        void Pop();
        T getTop() const;
        bool isEmpty() const;
        const int GetSize() const;
        int SetSize(const int prvSize);
        bool checkPresidence(T data,char infix);
        void printStack() const;

        virtual ostream& Output (ostream& os, const NewportStack & S,
                                    const char infix,const char *postfix
                                    ,const int size) const;
};

//------------
//Constructor
//------------
template<class T>
NewportStack<T>::NewportStack()
{
    top = NULL;
    size = 0;
}
template<class T>
void NewportStack<T>::printStack() const
{
    Node<T>* w;
    w = top;
    while( w != NULL )
    {
        cout << w->data;
        w = w->prev;
    }
}
//------------
//Copy Constructor
//------------
template<class T>
NewportStack<T>::NewportStack(const NewportStack<T> &Orig)
{
    if (Orig.top == NULL) // check whether original is empty
    {
        top = NULL;
    }
    else
    {
        Node<T>* newPrev=new Node<T> ;

        Node<T>* cur = Orig.top;
        newPrev->data = cur->data;
        top = newPrev;
// Now, loop through the rest of the stack
        cur = cur->prev;        
        while(cur != NULL )
        {
            newPrev->prev = new Node<T>;
            newPrev = newPrev->prev;            
            newPrev->data = cur->data;  
            cur = cur->prev;
        } // end for        
        newPrev->prev = 0;
        cur = 0;

    } // end else
    size = Orig.size;
} // end copy constructortor

//------------
//DeConstructor
//------------
template<class T>
NewportStack<T>::~NewportStack()
{
    Node <T>* w = top;

    while(top!=NULL)
    {
        delete w;
        top=top->prev;
    }
    size =0;
}
//------------
//getsize
//------------
template<class T>
const int NewportStack<T>::GetSize() const
{
    return size;
}
//------------
//SetSize
//------------
template<class T>
int NewportStack<T>::SetSize(const int prvSize)
{
    return size = prvSize;
}
//------------
//Push
//------------
template<class T>
void NewportStack<T>::Push(T d)
{
    Node <T>* w= new (std::nothrow) Node<T>;

    if ( !w ) 
    {
       cerr << "Error out of memory in Push\n";
       exit (1);
    }
    w->data =d;

    if( top == NULL )
    {
        w->prev = NULL;
    }
    else
    {   
        w->prev = top;
    }
    top = w;
    w = NULL;
    size++; 
}

//------------
//Pop
//------------
template<class T>
void NewportStack<T>::Pop()
{   
    if( top == NULL )
        return;
    Node<T>* w = top;
    top = top->prev;
    delete w;
    w = NULL;
    size--;
}
//------------
//getTop
//------------

template<class T>
T NewportStack<T>::getTop() const
{
    if (isEmpty ()) 
        exit(0);
    return top->data;
}

//------------
//isEmpty
//------------
template<class T>
bool NewportStack<T>::isEmpty() const
{
    if(top == NULL)
    {
        return true;
    }
    return false;
}

//------------
//checkPresidence
//------------
template<class T>
bool NewportStack<T>::checkPresidence(T data,char infix)
{
    switch(infix)
    {
        case '+': case '-':
            switch(data)
            {
                case '+': case '-': case '*': case '/': case '%':
                         return true;
                default: return false;
            }           
        case '*': case '/': case '%': 
            switch(data)
            {
                case '*': case '/': case '%':
                       return true;
                default: return false;
            } 
        default: return false;
    }
}

//------------
//OutPut
//------------
template<class T>
ostream& NewportStack<T>::Output(ostream& os, const NewportStack<T>& S,
                                    const char infix,const char *postfix
                                    ,const int size) const
{
    NewportStack<T> P ( S );//***INVOKED COPY CONSTRUCTOR*****

    char* St = new char[21];

    int i;
    if(P.GetSize() > 0)
    {
        int StLen = P.GetSize();

        for( i = 0;!P.isEmpty();i++)
        {
            *(St+i)= P.getTop();

            P.Pop();
        }
        *(St+i) = 0;
        std::reverse( St, &St[ strlen( St ) ] ); //flip string to display bottom to top
    }
    else
        *(St+0) = 0;

    os <<left<<setw(20) << infix ;

    for(i = 0;i < (int)strlen(St);i++)
    {
        os << St[i];        
    }
    os << right<< setw(21-i);

    for(i = 0;i <size;i++)
    {
        os << postfix[i];       
    }
    os << endl;

    if(St != NULL)
    {
        delete[] St;
    }

    return os;                                      
}

CPP File Here:

//Created By : Timothy Newport
//Created on : 4/26/2012
//===========================================
// NewportStackTester.cpp
//============================================
#include "NewportStack.h"
//------------
//Main
//------------
int main()
{
    //////////////////////////////////////////
    ///  Tester Part Two Test The class ///
    //////////////////////////////////////////

    char arr[] = "a+b-c*d/e+(f/g/h-a-b)/(x-y)*(p-r)+d";
    //char arr[] = "a+b-c*d/e+(f/g)";

    int len = (int) strlen(arr);
    char *postfix = new char[len+1];

    ofstream outputFile;
    outputFile.open("PostFix.txt");

    outputFile << "Infix is : " << arr<<endl<<endl;
    WriteHeader(outputFile);

    _strupr( arr); ///**** convert the string to uppercase ****

    infixToPostfix(arr,postfix,outputFile); 

    outputFile.close();



    system("notepad.exe PostFix.txt");

    return 0;
}
//------------
//infixToPostfix
//------------
void infixToPostfix(const char *infix, char* postfix, ostream & os) 
{   
    NewportStack <char> P;
    int len=strlen(infix);
    len += 1;
//  cout << "infix in infixToPostfix: " << infix << endl; 
    int pi = 0;
    int i=0;
    char ch;

   while( i < len && *(infix+i) !='\0')
   {
       ch = *(infix+i);

      if(ch >='A' && ch <='Z' )
      {
            postfix[pi++]= ch;
      }
      else if(ch =='+' ||ch =='-'||ch =='*'||ch =='/'||ch =='%')
      {       
            while(!P.isEmpty() && P.getTop() != '(' 
                && P.checkPresidence(P.getTop(), ch ) )
            {               
                postfix[pi++]= P.getTop();
                postfix[pi] = 0;                
                P.Pop();
            }

            P.Push(ch);         
       }
      else if(infix[i] == '(')
      {
            P.Push(infix[i]);
      }
      else// if(infix[i]==')')
      {
        while(!P.isEmpty() && P.getTop() != '(')
        {
            postfix[pi++] = P.getTop();
            P.Pop();
        }
        P.Pop(); //****remove the '(' from the stack top.
      }

     P.Output(os, P, ch, postfix, pi); // display after each read

     i++;    
   }
   // end of infix empty stack
   while(!P.isEmpty() )
   {
        postfix[pi++]= P.getTop();
        P.Pop();
   }
   postfix[pi] = 0; //add null terminator at the end of the string.
   //cout << "postfix 104: " << postfix << endl;
 P.Output(os,P,*infix,postfix,pi);// display final line
 WriteResults(os,postfix);
}
//------------
//WriteHeader
//------------
void WriteHeader(ostream& os)
{
    os <<left<< setw(20)<< "Input Characters" << setw(20)<< "Stack Item" << setw(20)
                << "PostFix" <<endl <<setw(20)<< "----------------"<< setw(20) 
                << "----------" << setw(20)<< "-------" <<endl;
}
//------------
//WriteResults
//------------
void WriteResults(ostream& os,const char *postfix)
{
    os << endl<< "The Final postfix is: " << postfix <<endl;
}

You folks help me so much! I just kept messing around with it until I found the issue in the main.

tim.newport
  • 97
  • 3
  • 12

2 Answers2

3

new char[StLen]; does not initialize the memory. You should use std::string instead of manually handling character arrays like this.

If you're forced to use character arrays by hand, you can write your own automatic memory management wrapper to handle deallocation, and you can initialize the memory to be a null-terminated string by writing a '\0' character at the first index.

Community
  • 1
  • 1
R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
0

The first thing that pops out to me is that you can't use strlen() on a char array unless you are absolutely sure it is a zero-terminated string. In your loop condition, you should check (i < (StLen - 1)) instead of calling strlen(). strlen() doesn't know anything about array lengths; it just reports the number of bytes before it hits a char of '\0' value. Check "man strlen" on your platform or, if that's not available web search "man strlen." I'm actually a bit surprised this isn't crashing outright due to an access violation.

[EDIT: Listen to R. Martinho Fernandes. You are handling strings using C conventions and the C standard library. There are better and safer ways to do it in C++, unless your instructor has told you to do otherwise.]

[EDIT]: If for some reason you know you'll be passing an otherwise uninitialized char array to strlen() then setting the first byte to '\0' as the other poster suggested will keep strlen() happy. But taking a second look at your code, I really doubt strlen() is what you want to do here. I think it's going to give you a logic error. See my above suggestion for a loop condition.

As far as the proper way to initialize a C-style zero-terminated string goes, you'd want to use memset() with a value of '\0', as in

memset(St, '\0', StLen);

I believe the prototype is in string.h. This will reduce the number of ways you can mess up the integrity of your string later on, at least for the first time you write to it. It's a good general practice to always initialize your memory, but it's especially important with zero-terminated strings.

If you're going to do more work with zero-terminated strings, a good rule of thumb is that the "str" functions are generally unsafe and the "strn" functions are preferred when available and feasible. Of course, the "strn" functions are generally more work to use, since you have to keep track of your buffer sizes. See the manual entries for strcpy() and strncpy() or strcat() and strncat() for the differences. But again, I don't think strlen() is even what you want in this scenario.

coydog
  • 111
  • 4