Issues with pointers!!

I am trying to write a function that concatenates a character to a string using the function below:

1
2
3
4
5
6
7
8
9
void concatenate(char*& str, char ch)
{
    int len;
        
    len = strlen(str);
    
    *(str+len) = ch;		//or str[len] = ch;
    *(str+len+1) = '\0';	//or str[len+1] = '\0';
}



The above function is called by another function, convertToPostfix(), that does infix to postfix expression conversion. The outline of this function is shown below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void postfixType::convertToPostfix()
{
    int i;
    int* intptr;     //added just to test a concept
    char* pfx;       //pointer to desired postfix expression

    cout<<"Pointer value intptr = "<<intptr<<endl;
    cout<<"Before memory allocation, pointer value pfx = "<<pfx<<endl;

    pfx = new char[infxLength];     		

    cout<<"After memory allocation, pointer value pfx = "<<pfx<<endl;
   
    pfx = "";
    while (infx[i] != '\0')	    
    {
        .
        .
	.

        concatenate(pfx, infx[i]);
    }
        
	.
	.
	.
}



Function convertPostfix belongs to class postfixType whose definition is roughly shown below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class postfixType
{
public:
	.
	.
	.

     void convertToPostfix();
        .
	.
	.

private:
     int infxLength;		//length of the infix expression
     char* infx;		//pointer to the char array that holds the infix expression
     char* postfixString; 	//pointer to the char array that stores the converted infix expresssion
}



Here are my questions:
Qn #1: Why is it that, in the code for function convertToPostfix, the cout statement in line 7 (for the integer pointer) outputs a real memory address in hex as one would expect of a pointer but the ones in lines 8 and 12 (for the char pointer) do not?? Each of the cout statements for char pointer produced some random strings of characters!!

Qn #2: Why is my concatenate function not working?? Program execution took place to the point where the function was invoked in function convertToPostfix.

Any insights please?
1) cout thinks char pointers are strings, so instead of outputting the memory address stored in the pointer, it tries to display it as if it were a null-terminated array of characters.
Since your pointers aren't initialized at that point yet, this gives you undefined behavior.

2)
10
11
12
13
14
15
pfx = new char[infxLength]; // Allocate some memory for 'pfx'

cout<<"After memory allocation, pointer value pfx = "<<pfx<<endl;

pfx = ""; // Now pfx is no longer pointing at the allocated buffer
          // but rather at the address of the (constant, non-modifiable) string "" 
To fix, use std::strcpy instead of the assignment operator, or just do pfx[0] = '\0';.
Last edited on
@long double main:
Thanks a lot! Your reply was insightful and of immense help! I have resolved the problem I had been dogged by for days.

Please, I have another nagging issue about dynamic memory allocation. From my studying of C++, the lesson I have learnt about d.m.a. is that any memory dynamically allocated has to be deallocated one way or another before exiting the environment/scope of the encompassing function. Let me furnish you with some background as it relates to the program here.

Another member function of my class (which I omitted in my first post) is

void showPostfix();

and its definition is simply

1
2
3
4
void postfixType::showPostfix()
{
   cout<<postfixString;
}

In member function convertToPostfix of my first post, one of the statements I omitted was

postfixString = pfx;


Now, let's say function main is as shown below:

1
2
3
4
5
6
7
8
int main()
{
     postfixType infxExpr(a+b);
     infxExpr.convertToPostfix();
     infxExpr.showPostfix();

     return 0;
}


What I observed is that if I deallocated the dynamic memory allocated in function convertToPostfix, that is by including statement

delete [] pfx;

the statement in line 5 of function main would not show anything; but if I do not include the above memory-deallocating statement, the statement in line 5 displays the correct postfix conversion! I understand why this is so but I do not know how else to deallocate the memory in function convertToPostfix without impairing the integrity of pointer data member postfixString of the class.

Any insights please? While almost sounding illogical, I guess my question is how can I deallocate pfx while still ensuring that the statement

postfixString = pfx;

in function convertToPostfix still works?
Last edited on
Oh well, I think I found a way around my so-called nagging issue with d.m.a.! I did a hard copy of pfx into postfixString and it worked even in the presence of the memory-deallocating statement. I wonder why a hard copy should be necessary here though since it's not like I'm copying/assigning class objects with pointer data members!!

If you still have any helpful tips/hints, they would be appreciated.
The easiest thing would be to use std::string instead of char * and your own memory management. After all, how long can these expressions get? 10 characters? 100? 4,000? Is there enough room to concatenate the string without overflowing the space allocated?

To answer your immediate question, when you're doing memory management on your own, it's always helpful to think about who will delete the memory right up front. Call this entity the "owner" and document in the comments. In your case, shouldn't pfx really be member postfixString?

The way you've written concatenate(), there's no reason to pass a reference. Just pass a char *.

Back to concatenate(). If you use postfixString, then be sure to delete the old value before you create the new one.
And be sure to initialize postfixString in the constructor,
and delete it in the destructor,
and what if someone does
1
2
3
 postfixType a, b;
...
a = b;

You don't want a.postfixString and b.postfixString to point to the same thing, so you'll need to write an assignment operator.
And you'll need a copy constructor for the same reason.

See why it's a good idea to use std::string instead? All of these problems would go away.
@ dhayden:

Thanks for your reply. I agree that it is much easier to use std::string instead of char* as I had already successfully implemented a working program using the former. But since I'm still learning C++, I decided to try the seemingly harder approach; besides, the textbook I'm using makes use of the char* approach a lot.

You wrote:
In your case, shouldn't pfx really be member postfixString?
You may have a point here; I thought about it too! However, the problem I'm solving requires me to use pfx as it is.

Thanks for the tip on just using char* instead of passing the pointer by reference. Regarding the other things you wrote, I had already taken care of the constructor, destructor, copy constructor and overloading the assignment operator.

One more thing; you wrote:
... when you're doing memory management on your own, it's always helpful to think about who will delete the memory right up front. Call this entity the "owner" and document in the comments.
Could you explain what you mean by this?
Could you explain what you mean by this?


Consider:
1
2
3
4
5
6
7
8
9
class A {
public:
    A() : p(NULL) {}
    ~A();
    void setp(B* param);
    const B* getp();
private:
    B *p;
};

A class like this should give you lots of questions. Does this work?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
A a;
B* pB = new B;
a.setp(pB);
delete pB;
pB = a.getp();    // gets deleted pB or a copy of *pB?
}

What about this?
[code]
A a; B *pB1, *pB2;
...
pB1 = a.getp();
// change *pB1;
pB2 = a.getp();   // Does pB1 == pB2? 


Without some comments the class definition doesn't tell you. All of these issues can be resolved by deciding who "owns" the pointers: who is responsible for deleting them. For example it might be:

1
2
3
4
5
6
7
8
9
class A {
public:
    A() : p(NULL) {}
    ~A();
    void setp(B* param); // takes ownership of param
    const B* getp();        // Get B. "this" still owns the pointer
private:
    B *p;  // owned by "this."
};


Now you know. A::setp() takes ownership of the pointer, so the pointer must be allocated on the stack and A will delete it. A::getp() returns a copy of the pointer that it owns. That means the When A is destroyed the pointer will be invalidated.
Topic archived. No new replies allowed.