Change Pointer via function call

Jan 13, 2010 at 9:58pm
Pretty sure this is just some silly syntax that Im having trouble grasping. Im pretty familiar with C style pointers but have never used them this way and honestly im getting a little bit wacky trying to wrap my brain around it. What im trying to do is: (im working with C++, in MCVS 2009)
- First off: I have a class A that holds a pointer of type Class B;
- Second: I create an object of class A and initialize(dynamically) the pointer of type class B to point to an array (new B[size]) of class B of specified size;
- In my main function I create another pointer of Class B and point it to an array of class B of specified size;
- Then I pass it to Class A via a member function and within that function it is changed to point to the pointer inside Class A;

I mean this is simple all im doing is creating a new pointer in main that points to the pointer inside class A; This seems really simple not sure why C pointers act so silly when your passing them around. Seems really inconsistent when you start passing them in functions when you start considers pass-by-value and pass-by-reference and all.

Any help is greatly appreciated. Thank you.
Jan 13, 2010 at 10:12pm
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41

const int SIZE = 5;
const int SIZE2 = 10;

class B
{
  // does something
}

class A
{
public:
   A() : 
       m_b(NULL)
   {
       m_b = new B [SIZE];
   }
   
   ~A()
   {
      if (NULL != m_b)
         delete [] m_b;
   }

   B* m_b;
}

int main()
{
   A* a = NULL;
   B* b = NULL;
   a = new A();

   if (NULL != a)
   {
      b = new B[SIZE2];
      if (NULL != b)
          a->m_b = b;  // Note there is bug here.  I'll let you figure out what it is
   }
   return 0;
}


Note this doesn't answer all your questions. But it should get you started.
Last edited on Jan 13, 2010 at 10:14pm
Jan 13, 2010 at 10:48pm
Thank you very much for your reply.

So im seeing something here and from what ive been messing around with my code while waiting on replies.

the B class pointer in main is assigned space in memory via:
b = new B[SIZE2];

Also the same applies to the B class pointer in A:
m_b = new B [SIZE];

So when we reference the pointer in class A via:
a->m_b we are grabbing a reference to it? I believe.
Then assigning the class B pointer in main to it via:
a->m_b = b;

So im guessing from what ive seen that we are really only pointing pointer m_b's first address to pointer b's first address?

All m_b's other address's will remain unchanged?

So do you have to loop through using a-m_b[i] = b[i] or something?

Jan 13, 2010 at 10:56pm
Here is my code if you want to actually see what im doing.

Programs intent:
-Create an array of Key objects that each contain an ASCII int value and string value;

Do this by:
-Create keyGenerator Class (Class A from discussion above) that contains a pointer of type Class key (Class B from discussion above) that points to an array of Key[Size];
-Call keyGenerator Class's genKeys() member function to actually do file i/o operations and read in the information from the .txt file to the array of Keys;
-Assign the Class Key pointer created in the main function to point to this array;


Code
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
//------------------------------------
//  main.cpp
//------------------------------------
#include <iostream>
#include "keysGenerator.h"
using namespace std;

int main()
{
	Key *ppK = new Key[255];
	cout << "Welcome" << endl;
	KeysGenerator generator;
	generator.genKeys();
	if(generator.keyCopy(ppK)){
	for(int i = 0; i < 255; i++)
		cout << ppK[i].getIntValue() << ", " << ppK[i].getStringValue() << endl;
	}
	else
		cout << "Keys were not copied to mains pointer ppK" << endl;

	while(true){}
	delete[] ppK;
	
	
	return 0;
}



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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#ifndef KEYSGENERATOR_H
#define KEYSGENERATOR_H
//------------------------------------
//  keysGenerator.h
//------------------------------------
#include <string>
using namespace std;

//#####CLASS Key#####
class Key
{
private:
	string aciiString;
	int    aciiInt;
public:
			 Key();
	explicit Key(string theAciiChar, int theAciiInt);
			 ~Key(void);
			 Key(Key &key);
	string	 getStringValue();
	int		 getIntValue();
	void	 setStringValue(string newAciiString);
	void	 setIntValue(int newAciiInt);
};

//#####CLASS KeysGenerator#####
class KeysGenerator
{
private:
	static const int ArraySize = 255;	// Size of array
	Key *pK;							// Pointer to dynamically allocated array of Key objects

public:
	explicit KeysGenerator();
			 ~KeysGenerator(void);
	void	 Print() const;
	void	 genKeys();			 // Geneartes an array of Key objects with all ASCII decimal and string/char values
	bool     keyCopy(Key *ppk);  // Copy values from pK pointer into passed ppK object
};


#endif


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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//------------------------------------
//  keysGenerator.cpp
//------------------------------------
#include <iostream>
#include <fstream>
#include <string>
#include "keysGenerator.h"
using namespace std;

//#####CLASS KeysGenerator#####
KeysGenerator::KeysGenerator()						// Constructor No paramaters			
{
	pK = new Key[ArraySize];
	for(int i=0; i < ArraySize; i++)
	{
		pK[i].setStringValue(" ");
		pK[i].setIntValue(0);		
	}
}

void KeysGenerator::genKeys()				// Generate array of Key objects
{

	char buffer[25];
	int value;
	int i = 0;
	string str = "";

	fstream filestr("ASCII_CODES.txt", fstream::in | fstream::out);	// Create a fileStream for i/o using given .txt file
																	// Format inside text file is int then delimeter then string value
																	// Example: 1|One
	if(filestr.is_open()){											// Make sure fileStream is open/ready for use
		cout << "File opened: Operating" << endl;

	while (filestr.good())							// Loop while extraction from file is possible
	{
		filestr.get(buffer, 25, '|');				// Read first value and stop at | delimeter
		value = atoi(buffer);						// Convert string to int
		pK[i].setIntValue(value);					// Set the Key objects int value to value
		filestr.ignore(4,'|');						// Throw away the | delimeter
		filestr.get(buffer, 25);					// Read until '\n' char and store in buffer
		str = buffer;								// Assign buffer contents to str
		pK[i].setStringValue(str);					// Set the Key objects string value to str
		filestr.ignore(2,'\n');						// Throw away the '\n' char
		i++;										// Increment i for next index in Key array
	}												// End loop

	filestr.close();								// Close the file
	}	
	else											// FileStream was not successfully opened
		cout << "File Not Opened: Returning" << endl;
}

bool KeysGenerator::keyCopy(Key *ppK)
{
    if ((NULL == ppK) || (NULL == pK))
       return false;

    for (int i = 0; i < ArraySize; i++)
    {
        ppK[i] = pK[i]; 
    }

    return true;
}

void KeysGenerator::Print() const					// Print member array method 
{
	cout << "Printing List" << endl;
	for(int i = 0; i < ArraySize; i++)
	{
		cout << pK[i].getIntValue() << ", " << pK[i].getStringValue() << endl;
	}
	cout << "End of List" << endl;
}

KeysGenerator::~KeysGenerator()						// Destructor	
{delete[] pK;}

//#####CLASS Key#####
Key::Key():aciiString("NULL"), aciiInt(0){}			// Constructor No paramaters, using initialize list

Key::Key(string theAciiString, int theAciiInt):aciiString(theAciiString),
	aciiInt(theAciiInt){}							// Constructor Two paramaters, using initialize list

string Key::getStringValue()						// Get String method
{return aciiString;}

int Key::getIntValue()								// Get Int method
{return aciiInt;}

void Key::setStringValue(string newAciiString)		// Set String method
{aciiString = newAciiString;}

void Key::setIntValue(int newAciiInt)				// Set Int method
{aciiInt = newAciiInt;}

Key::Key(Key &key)									// Copy constructor
{
	aciiString = key.aciiString;
	aciiInt = key.aciiInt;
}

Key::~Key(){}										// Destructor




Limited .txt contents to conserve post space:
1
2
3
4
5
6
7
8
9
10
11
12
13

1|EMPTY		
2|EMPTY
...		
65|A
66|B
...
155|›
156|œ
...
254|þ
255|ÿ


If you want the full .txt file you can get it here

http://www.mathaino.com/Download/ASCII_CODES.txt








Last edited on Jan 13, 2010 at 11:58pm
Jan 13, 2010 at 11:00pm
In the example provided above after line 38.

The size of a->m_b is SIZE2 (10) allocated units and b points the exact same memory.

However there is still a bug associated with the reassignment of a->m_b pointer to point to different memory. I.e. a memory leak. Because the reference to the memory allocated for a->m_b in the "A" constructor is lost by the pointer reassignment.

However, you'll need to create functions to for the assignment per your statement in the first post. And in there you can handle the bug.

Edit: Saw that you posted.

Line 10 of main.cpp is meaningless since you are attempting to reassign inside KeysGenerator. So should be:
Key *ppK = NULL

Line 49 of KeyGenerator.cpp is trying to assign a pointer to a dereferrenced point (i.e. what is pointed at) so shoudl be:
ppK = pK;

However to get the generated keys back you need to pass in ppK by reference. The function prototype should be:
void genKeys(Key*& ppK);

Another way to do it (and perhaps that was your intention) was copy from array into another array then return the results in the original array (inwhich case the pass by reference is not needed). But you would need a copy function similar to this. Also Key will need a copy constructor... http://www.cplusplus.com/forum/general/16960/

1
2
3
4
5
6
7
8
9
10
11
12
bool KeysGenerator::keycopy(Key *ppk)
{
    if ((NULL == ppK) || (NULL = pk))
       return false;

    for (int i = 0; i < ArraySize; i++)
    {
        ppk[i] = pk[i]; 
    }

    return true;
}
Last edited on Jan 13, 2010 at 11:21pm
Jan 13, 2010 at 11:06pm
Edited code in my second post to use the items discussed in your post just above this.

I went with this way:

Another way to do it (and perhaps that was your intention) was copy from array into another array then return the results in the original array (inwhich case the pass by reference is not needed). But you would need a copy function similar to this. Also Key will need a copy constructor... http://www.cplusplus.com/forum/general/16960/


Added copy constructor to Class Key:

1
2
3
4
5
Key::Key(Key &key)									// Copy constructor
{
	aciiString = key.aciiString;
	aciiInt = key.aciiInt;
}


Added your keycopy function:
1
2
3
4
5
6
7
8
9
10
11
12
bool KeysGenerator::keyCopy(Key *ppK)
{
    if ((NULL == ppK) || (NULL == pK))
       return false;

    for (int i = 0; i < ArraySize; i++)
    {
        ppK[i] = pK[i]; 
    }

    return true;
}


Main now looks like this:
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
28
//------------------------------------
//  main.cpp
//------------------------------------
#include <iostream>
#include "keysGenerator.h"
using namespace std;

int main()
{
	Key *ppK = new Key[255];
	cout << "Welcome" << endl;
	KeysGenerator generator;
	generator.genKeys();
	if(generator.keyCopy(ppK)){
	for(int i = 0; i < 255; i++)
		cout << ppK[i].getIntValue() << ", " << ppK[i].getStringValue() << endl;
	}
	else
		cout << "Keys were not copied to mains pointer ppK" << endl;

	while(true){}
	delete[] ppK;
	
	
	return 0;
}



Removed all code reassigning pointers.






Last edited on Jan 14, 2010 at 12:02am
Jan 14, 2010 at 12:06am
I have a bunch of questions though maybe you can enlighten me or point me into the right direction for reading.
I feel pretty confident with pointers but using them inside function calls like:
void genKeys(Key*& ppK);
or
Key::Key(Key &key)
Baffles me, Can you describe what actually is going on here?
More especially what is going on with
void genKeys(Key*& ppK);

Also how do I know if the copy constructor of Key class is actually being used when say this happens:
ppK[i] = pK[i];

Is the copy constructor used or am I supposed to overload the = operator?

Also, in say main when you do
char *p;
char *z =3;
p=&z; p now points to z
or
p=*z; p now holds value of z
Why are these operations handled differently inside functions?

Thanks again for all your help.
Last edited on Jan 14, 2010 at 12:12am
Jan 14, 2010 at 2:55pm
The & symbol means to pass by reference
http://www.tech-recipes.com/rx/1232/c-pointers-pass-by-value-pass-by-reference/

What it allows is the values to be returned back to the caller. In this case you need to return the head pointer to the member array. The array information (which changed) has to be pointed at and we need that pointer. Passing by reference changes where the pointer points and returns the new location. Without it, you would not receive the new array.

For Key::Key(Key &key), really is doing the same as above. Except not as an array, its a singular object of Key type. But if the object is changed, the changes will be seen by the caller of the method aswell. Also, this saves the need of copying from the original to the function variable (i.e. less memory usage and time usage which is important on big arrays). I.e. arrays should best be implemented using the STL library for vectors/lists. So a list example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <list>

void myfunct(std::list<int> myList)
{
  // Do something
}

int main()
{
   std::list<int> daList;

   for (int i = 0; i < 255; i++)
      daList.push_back(i);

   myfunct(daList);
}


What happens above daList is copied into myList via the List copy constructor (which in tern uses the int copy constructor). http://cplusplus.com/reference/stl/list/list/ If myfunct() changed any values in myList, daList would not see any changes.

Now if I change it to.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <list>

void myfunct(std::list<int>& myList)
{
  // Do something
}

int main()
{
   std::list<int> daList;

   for (int i = 0; i < 255; i++)
      daList.push_back(i);

   myfunct(daList);
}


I am for the ease of clarity (but reality is not as simple) passing the pointer of daList to myList and only copying the pointer of daList to myList so they both point to the same location of data and then automatically dereferencing the pointer i.e. a normal list. So any changes to myList will affect daList.

You could overload the = operator(), but if copying type to same type the copy constructor will do the task. If however going class A = class B then you would need to overload the = operator().

1
2
3
4
5
char *p;
char *z =3;  // you don't want to do this, you just assigned z = memory address 0x03 since z is a pointer
p=&z; //p now points to z // P now points to the address that pointer z is allocated in
or
p=*z; //p now holds value of z  //p now points to memory address of what ever value was at address 0x03.  i.e. if Mem loc 0x03 has the value 0x0824, then p now points to memory location 0x0824 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
char * p;  // p points to unknown location
char * z  = new char('3');  //p points to an allocated memory location of size char containing the value of 3

p = z;  // p points to the same location as z

std::cout<<*p<<std::endl;  //prints 3
std::cout<<*z<<std::endl;  //prints 3

*p = '5';
std::cout<<*p<<std::endl;  //prints 5
std::cout<<*z<<std::endl;  //prints 5

z = new char('8');
std::cout<<*p<<std::endl;  //prints 5
std::cout<<*z<<std::endl;  //prints 8 
Last edited on Jan 14, 2010 at 3:05pm
Jan 14, 2010 at 8:43pm
You have been more than helpful iharrold. Thank you for all your help. This has helped my understanding of pointer use greatly.
Topic archived. No new replies allowed.