Another attempt, simplified my question

This another attempt at understanding memory allocation and pointers. So here goes. I've created this simple program. It creates a pointer to an array of pointers to ints. This code works so you should be able to copy it out to see my results.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;

int main (){       
    int x = 2;
    int y = 2;
    int a = 1;

    int** ptr3 = new int *[x];	
    for (int i = 0; i < x; i++) ptr3[i] = new int[y];

    for (int j = 0; j < y; j++) 
        for (int i = 0; i < x; i++)
        {			
            ptr3[i][j] = a;
            cout << "ptr3[" << i << "][" << j << "] = " << ptr3[i][j] << endl;
            a++;
	}
delete [] ptr3;
system ("pause");
return 0;
}


I would like to create another pointer (for example ptr4) that points to ptr3[x][y] and have the following statements be true:

ptr4[x][y] == ptr3[x][y];
Last edited on
You have a memory leak in that code. You don't ever call delete on that memory. Remember to call delete on whatever you new.

As for your question: I don't know what you mean by "create another pointer (for example ptr4) that points to ptr3[x][y]". Going by your other statement however, it seems you just want another pointer pointing to that array:

int** ptr4 = ptr3;
Yeah I'm aware that I didn't call delete. I wrote this simply to help formulate my question.

int** ptr4 = ptr3;

Your solution was exactly what I was looking for. I definitely over complicated it when I was looking for the solution.

Thanks!
Please don't encourage to run buggy code, especially when you're aware that it'll cause harmful things such as memory leaks.

You must, must, MUST delete -every- new. Anything less is not only bad practice, but dangerous.

I also noticed your using namespace. It's not exactly illegal, but it's also bad practice to pollute the standard namespace. Consider using the std:: prefix instead.

@Nexius
Sorry about not deleting. I went back to my first post and edited it to include the delete statement. Let me know if I did that incorrectly.

I put using namespace std; because I saw it used in the tutorials here at cplusplus.com. You say use the std:: prefix, can you explain or give an example.
Last edited on
can you explain or give an example.


Since the names are in the std namespace do things like this:

1
2
3
4
std::cout<<"Hello world!";
std::cin>>x;
std::vector<int> some_ints;
//etc... 
std::cout << "proper use of \"std::\" prefix" << std::endl;

The reason why it's bad practice is because when you're using a namespace, you're practically importing the entire standard namespace scope, which increases the likelyhood of same name conflict of functions or variables with your code.

A much more safe approach, if you're too lazy to use the std:: prefix, is to import only the functions you use in your code, like so:
1
2
3
using std::cout;
using std::cin;
using std::endl;


I also want to throw out that pointers to data aren't the only type of pointers out there. You may also want to look into pointers-to-functions. And, when using them, the usefulness of typedef.

Your use of delete does not satisfy every new in your code.
Line 10: for (int i = 0; i < x; i++) ptr3[i] = new int[y]; is a memory leak.
You must delete[] it before deleting ptr3.
Last edited on
Your use of delete does not satisfy every new in your code.
Line 10: for (int i = 0; i < x; i++) ptr3[i] = new int[y]; is a memory leak.
You must delete[] it before deleting ptr3.


At the risk of coming across as a complete idiot, how would I do that? Something like:
1
2
for (int i = 0; i < x; i++) delete [] ptr3[i];
delete [] ptr3;
Last edited on
I was also looking for a way to double check that there weren't any missed memory leaks. Through searching I came across this in another website's forum:
you can call this at the start of your program :-

_CrtSetDbgFlag(_crtDbgFlag | _CRTDBG_LEAK_CHECK_DF);
After including

#include <crtdbg.h>


So I tried it out. To test what it does I removed all the deletes and ran it through the debugger. As expected it warned me of memory leaks. Then I put back the delete delete [] ptr3; and as Nexius pointed out I still had memory leaks. Then I put it back to
1
2
for (int i = 0; i < x; i++) delete [] ptr3[i];
delete [] ptr3;
and no warnings were thrown back. So my guess is that I removed all memory leaks.
woah, that's cool, I didn't know you could check for memory leaks like that, I'll be sure to use it in the future.
I have another question based on deleting the "new's". In order to ask the question I would need to post my code. In the code I've commented my explanation of what I think is going on and added questions as well.

Are there any objections to me asking my question this way?
lol @ LittleStudios
If you're going to ask about asking questions, you're never going to get anywhere.

Yeah, your use of delete @post ( Jul 28, 2012 at 12:57pm ) should satisfy your all of your news.

Mind you, this is why pointers are so dangerous. Generally, if you're going to be tossing pointers around, you should ensure that your data is managed properly. I recommend, using the standard template library containers, such as the vector or linked list.

1
2
std::list<int> intpool;
int *ptr= &*intpool.insert(intpool.begin(), 30);

This way, you can use pointers without having to throw new and delete everywhere, the container will handle all of the tedious management for you.
lol @ LittleStudios
If you're going to ask about asking questions, you're never going to get anywhere.

I understand, but at the VST developer's forum that I read, people tend to get annoyed by rookie questions and long and tedious posts.
------------------------------------------------------------------------------------------------------------------------------------

So I'm working on developing a VST plugin to be used in a Digital Audio Workstation. I didn't want to upload the code for that because it's long and full of other information that doesn't pertain to my question. So instead I've written the following code to simplify and get to the point of my question.

So when the host software creates an instance of the VST plugin the plugin's constructor is called and this is where parameters are set, audio files are loaded, etc. This math example is very similar to the tasks I'm going to need to do. I mention this because it may seem that I've over complicated things.

Also I do not recommend running this code. It may be full of mistakes, which is precisely why I'm asking for help. If you run it, it is at your own risk.

Below is the code with comments and questions through out.

Thank you to those who have taken the time to try and help me wrap my mind around C++ programming.

Math.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Define a data type to return from GetData().
typedef struct DATA
	{
		int rows;
		int columns;
		int** ptr4;
	};

class Math{	
	
	int** ptr3;
	int rows, columns, valueOfCell;
	DATA data;
public:
	DATA GetData();
	
	Math();
	~Math();
};


Math.cpp
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
#include <iostream>
#include "Math.h"

/*///////////////////////////////////////////////////////////////////
The following function takes two inputs, rows and columns. Then fills
the corresponding cell with a value. For example ptr3[0][0] has a value
of 1 stored and ptr3[1][0] has a value of 2 stored. It then stores 
the number of rows, number of columns and a pointer to the value stored
at each location (ex. ptr3[0][0]) in a structure and returns said stucture.
///////////////////////////////////////////////////////////////////*/
DATA Math::GetData()
{
	// Get the number of rows.
	std::cout << "How many rows: " << std::endl;
	std::cin >> rows;

	// Get the number of columns.
	std::cout << "How many columns: " << std::endl;
	std::cin >> columns;

	// Initialize the value of the cell.
    valueOfCell = 1;

	// Allocate memory for a certain number of arrays of pointers to integers.
    int** ptr3 = new int *[rows];

	// For each array of pointers to integers that has been allocated,  
	// allocate memory for a certain number of pointers that point to integers.
    for (int i = 0; i < rows; i++) ptr3[i] = new int[columns];

	// Create data of type DATA. The type DATA is a structure.
	// Refer to the header file to get a list of DATA's members.
	DATA data;

	// Assign the members of data.
	data.rows = rows;
	data.columns = columns;

	// This member is declared as int** ptr4;
	// I guess this assignment means ptr4 points to the same place as ptr3???
	data.ptr4 = ptr3;

	// Here we cycle between cell locations and assign the incremented value 
	// of valueOfCell.
    for (int j = 0; j < columns; j++) 
        for (int i = 0; i < rows; i++)
        {			
            ptr3[i][j] = valueOfCell;
            valueOfCell++;
		}

	// Return the structure data.
	return data;
}

// This is the constructor of the Math class.
Math::Math(){
	std::cout<< "Made a math object!" << std::endl;
}

/*///////////////////////////////////////////////////////////////////
Here in the destructor of the Math class I attempt to use what I've
learned previously about deleting a "new's" created by my program.
When I run my program through the debugger I get this error:
"Unhandled exception at 0x013725d8 in DoMath.exe: 
0xC0000005: Access violation reading location 0xcccccccc."
///////////////////////////////////////////////////////////////////*/
Math::~Math(){

/*The error stops the program here */
for (int i = 0; i < rows; i++) delete[] ptr3[i];
delete[] ptr3;	
}


DoMath.cpp
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
#include <iostream>
#include <crtdbg.h>
#include "Math.h"

int main ()
{
	// This lets me know if I have any memory leaks.
	_CrtSetDbgFlag(_crtDbgFlag | _CRTDBG_LEAK_CHECK_DF);

	// I create an instance of my Math class.
	Math mathObj;

	// I declare "data" of type DATA, which is a structure.
	// I assign the structure returned by GetData() to 
	// my new data structure "data".
	DATA data = mathObj.GetData();
	
	// I declare "rows" and assign it to "data.rows"
	int rows = data.rows;

	// I declare "columns" and assign it to "data.columns"
	int columns = data.columns;
	
	// I cycle through the cells pointed to by data.ptr4 and
	// print out the values to the screen.
	for (int j = 0; j < columns; j++) 
        for (int i = 0; i < rows; i++)
        {           
            std::cout << "ptr4[" << i << "][" << j << "] = " << data.ptr4[i][j] << std::endl;
	}
	
system ("pause");
return 0;
}
Last edited on
For the time being, I'm a bit busy. I've skimmed through your code though, and might come back to look at it more in-depth.

Here's a few things I noticed.

Your use of typedef is improper. You may want to look into typedef, which C++ inherited from C. When you declare a struct or class, struct mystruct{};, the symbol followed by struct/class is not a typename but a tagname. So when someone writes:
1
2
3
4
typedef struct
{
 ///data
} custom_t;

They declare an anonymous struct of type custom_t. This way, the tediousness of declaring structs as types using the struct keyword like the following can be omitted:
1
2
3
4
5
6
7
struct mystruct
{
 /*data*/
}; 
int main(){
    struct mystruct object; /*use a typedef to omit 'struct'*/
}


Luckily, in C++, (for better or for worse) you -can- use tagnames as typenames and omit the struct keyword in type declaration either way.

Another thing I noticed is that you're using new in your code. This is very error-prone, and should be avoided when possible.
Instead, try using a standard template library container to manage dynamic memory for you.

Another thing you may want to look at is encapsulation to organize code a little better.

Here's a prototype.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <list>
struct math_t /*using tagname as typename because in c++, I can*/
{
private:
	//types
	struct data_t
	{
		//data goes here

		//data_t methods here
	};

	//data
	std::list<data_t> data_pool;

	//private methods here
	void changeData(std::list<data_t>::iterator it);
public:
	//public methods here
};

@Nexius
Thanks for taking the time to help me understand and offer advice. Looks like I've got some reading to do.

About the Standard Template Library (STL) containers, for instance vector, can it handle the thousands of audio samples of a .wav file. I don't want to have stack overflow.

Thanks.
Last edited on
I found the error!! In Math.h I declared int** ptr3;. Then in Math.cpp I had written int** ptr3 = new int *[rows]; when in fact I should have written ptr3 = new int *[rows];.

When I was reading through my code, trying to find the problem, I was in Math.cpp and noticed int** ptr3 = new int *[rows]; and read it out loud and realized that this was declaring int** ptr3, which I had already done in Math.h.

In other words, if you've already declared it, don't do it again. I wonder why I wasn't thrown an error by MSVC++ warning me that I had already declared it.
Topic archived. No new replies allowed.