Trouble Expanding an Array of pointers in C++

In summary: NamesEntered; int numEntered (0); int index; int CurrSize (20); int compareResult; pNamesEntered = new char * [20];You need to allocate for 21 pointers to store 21 names. The problem is, you have no way of knowing how many names will be entered, so you have to dynamically allocate the array of pointers as well.In summary, the conversation is about a program that reads in names, sorts them, and makes them searchable. The problem is that when the 21st element is entered, the program crashes due to a heap corruption error. The problem lies in the dynamic expansion of the
  • #1
punx
7
0

Homework Statement



I am working on a program that reads in names (strings), sorts them, and then later is searchable. The problem I am having is this. When I enter the first 20 elements of the array, everything works fine. When I enter the 21 element (when it goes into the if loop) I get an error that says:

Debug Error!
Program: ...

HEAP CORRUPTION DETECTED: After Normal block (#118) at 0x00355930.

CRT detected that the application wrote to memory after end of heap buffer.

Abort Retry Ignore

To make it easier to read, arrayExpansion is a const int defined in the header file as 10.
CurrSize is defined at the beginning at 20.

Homework Equations





The Attempt at a Solution



Code:
char	**	pNamesEntered;
	char	*	pNameToSearch;
	int			numEntered (0);
	int			index;
	int			CurrSize (20);
	int			compareResult;

	pNamesEntered = new char * [20];

	do	{
		cout << "Enter a name to be sorted and then searched: ";
		pNamesEntered [numEntered] = ReadString ();
		if (numEntered >= CurrSize)
				{
				CurrSize += arrayExpansion;
				char **	pNew;
				pNew = new char * [CurrSize];
				for (index = 0; index < numEntered; index++)
					pNew [index] = pNamesEntered [index];
				//memcpy (pNew, pNamesEntered, numEntered * sizeof (char *));
				for (int index = 0; index < numEntered; index++)
					delete [] pNamesEntered [index];
				
				delete [] pNamesEntered;
			
				pNamesEntered = pNew;
				}
		} while (strlen (pNamesEntered [numEntered++]) > 0);

The commented out memcpy line was my original attempt to copy the existing array to the new array. I get the same error when I use that line.

The rest of my program works great, its this one particular section that I can't get.

I suppose the question is, when you have dynamically created an array of pointers, and you have reached the limit of what you have created, how do you expand the array of pointers? I know how to make a single array bigger. This is my ReadString Function

Code:
char * ReadString ()
	{
	char *		pChar;
	char		c;
	int			charCounter (0);
	int			CurrSize (arrayExpansion);

	pChar = new char [CurrSize + 1];
	while ((c = cin.get ()) != '\n')	
		{
		pChar [charCounter++] = c;
		if (charCounter >= CurrSize)
				{
				char *	pTemp;
				CurrSize += arrayExpansion;
				pTemp = new char [CurrSize + 1];
				memcpy (pTemp, pChar, charCounter);
				delete [] pChar;
				pChar = pTemp;
				}
			else;
		}
	pChar [charCounter] = '\0';
	return pChar;
	}

Any help with understanding this would be outstanding. Thanks.
 
Last edited:
Physics news on Phys.org
  • #2
two ways...
[1] the first involves data structures, have you learned this before?
[2] you want to go from "new char * [20];" new char * [20+k ];" for some k size (you can't actually do this in C/C++)...but what are you tring to achieve...

(a) first think what is the difference between new char[n] and new char*[n];
(b) next think of the statement you wrote

"how do you expand the array of pointers? I know how to make a single array bigger." What exactly is it that you do to make a single array bigger?

or call the first statement B, and the second one A...now treat B as statement A...

That is you can say:
i know how to make a single array bigger.
I know how to make a array(pointer) of arrays bigger
(...and then a new related question would be the next statement to follow that line of thinking)

NOTE: the second method is only reasonable for small data sets like the problme you have...where you would need to copy the entire set.
 
  • #3
punx said:
Code:
for (index = 0; index < numEntered; index++)
					pNew [index] = pNamesEntered [index];
				//memcpy (pNew, pNamesEntered, numEntered * sizeof (char *));
				for (int index = 0; index < numEntered; index++)
					delete [] pNamesEntered [index];
Is there any particular reason you bothered to copy the pointers if you were just planning on deleting the memory to which the pointers are pointing?
 
  • #4
Hurkyl said:
Is there any particular reason you bothered to copy the pointers if you were just planning on deleting the memory to which the pointers are pointing?

I thought what I was doing there was to create a new temporary array of pointers, copy the old array to the new array, delete the old array, then assign the new temp array info to a newly established pNamesEntered array.

Honestly, I think a lot of my trouble is I am not quite grasping the array of pointers thing. Is that not a necessary step?

What exactly is it that you do to make a single array bigger?

Code:
if (charCounter >= CurrSize)
				{
				char *	pTemp;
				CurrSize += arrayExpansion;
				pTemp = new char [CurrSize + 1];
				memcpy (pTemp, pChar, charCounter);
				delete [] pChar;
				pChar = pTemp;
				}
That is how I was able to expand a single array.

But as I said, I can't wrap my head around how to do this same thing for the array of pointers. Will memcpy handle this type of function? I tried that, but I am not sure I used it correctly.
 
  • #5
punx said:
I thought what I was doing there was to create a new temporary array of pointers, copy the old array to the new array, delete the old array, then assign the new temp array info to a newly established pNamesEntered array.
You did all of that. It's just that you also deleted everything that was being pointed to by the elements of the original array.

The key piece of understanding that you're missing, I think, is that copying the pointer does not duplicate the memory to which the pointer points. It simply copies the pointer, so that you now have two pointers pointing to the same piece of memory.


For a real world analogy -- you ran out of space in your address book. So, you buy a bigger address book and copy all of the addresses over from the old one into the new one, and destroy the old book. Would you want to destroy your friends' houses in this process?
 
Last edited:
  • #6
... Would you want to destroy your friends' houses in this process?

I would never do that. Unless they pissed me off.

Seriously though, I went through and commented out the sections that were deleting the pNamesEntered elements.

Now when I run the program, and enter the 21st element, it crashes and the Just in Time debugger (using Visual Studio 2005) says:

An Unhandled Win32 exception error occurred in Program10.exe [1984]
 
  • #7
its because you can't you did not allocate for 21 pointers, you statically allocated for 20...do you know what data structures are?

if not then you will need to allocate for that 21st...but you can't because you statically allocated for 20. Now you need to dynamically allocated the array of pointers.
Now seeing your code you seem to know howt o allocate for an array of char now apply that to an array of pointers.
 
  • #8
neurocomp2003 said:
its because you can't you did not allocate for 21 pointers, you statically allocated for 20...do you know what data structures are?

if not then you will need to allocate for that 21st...but you can't because you statically allocated for 20. Now you need to dynamically allocated the array of pointers.
Now seeing your code you seem to know howt o allocate for an array of char now apply that to an array of pointers.

I do know what a data structure is, but that is for next project. This project is supposed to be using pointers for everything.

As far as dynamically allocating the array of pointers, that is what I thought I was doing with:

Code:
 CurrSize += arrayExpansion;
				char **	pNew;
				pNew = new char * [CurrSize];
				for (index = 0; index < numEntered; index++)
					pNew [index] = pNamesEntered [index];
				
				
				pNamesEntered = pNew;

pNew = new char * [CurrSize];

That should be creating a new array of pointers. Then the for loop should be copying the pNamesEntered array to the pNew array.
I thought that should be creating a new array with more space allocated.

Am I on the right track here? Should I scrap it and start over?
 
  • #9
ah my bad it would help if i actually looked at the middle:
ok here's the problem...you can't input the 21st right...

now on pen and paper simulate how the logic of the code should work by
removing everything in the if statement except { currSize+=...}.

Jump straight to say the 19th iteration...and proceed from there.
You should find your error by doing this...

as for the middle portion of the code (the if statement ...it looks correct)

Try to use less tabbing in an open forum like this...gets a little hard to read.
CurrSize += arrayExpansion;
char ** pNew;
pNew = new char * [CurrSize];
for (index = 0; index < numEntered; index++) pNew [index] = pNamesEntered [index];

//and hurkyl was right you dont' need the 2nd portion
//because from his analogy you keep the houses and destroy the
//address in the book. Sort of like selling between people.

delete [] pNamesEntered; //delete only the addressed

pNamesEntered = pNew;
 
  • #10
Thanks for the help with this program. All of the different parts work now. I have one last issue with it. What is the code to delete the pNamesEntered array?

I was trying:

delete [] pNamesEntered;

but that gives me an error.

I tried:

delete [] * pNamesEntered;

on a whim...and the program works all around now..but does that free up the memory? That is the only thing I need to resolve in the program.
My book has very limited information about the delete command.
 
  • #11
if u allocated teh array the syntax should be "delete [] arrayname;"
copy and paste the error to the forum..and check if you have deleted it before hand...

if you have a double pointer then you delete each element first...then delete the array of pointers.

Funnything one of my HPC profs says ...ah in the end the computer does it for you so why bother...but its good practice to delete them on your own.
 
  • #12
neurocomp2003 said:
Funnything one of my HPC profs says ...ah in the end the computer does it for you so why bother...
Because eventually, somebody (possibly you) is going to have the bright idea of taking the code you wrote and wrapping it up into a function call so that another program can call it a bunch of times.

Which means that person is going to have to waste a lot of his time tracking down all of the stuff you didn't bother freeing.

If, for some peculiar reason, it really does make a relevant1 performance difference, at the very least you should make a flag that controls whether or not cleanup code is executed.


1: relevant being the key word: in almost every practical situation, you should first write the code correctly and simply. Optimization comes later in the software development process, and should not be done until you do actual performance analysis that suggests where optimization will make a relevant difference in runtimes.
 
  • #13
Code:
#include <iostream>
#include <string.h>
#include "Sort.h"

using namespace std;

void main ()
	{
	char	**	pNamesEntered;
	char	*	pNameToSearch;
	int			numEntered (0);
	int			index;
	int			CurrSize (20);
	int			compareResult;

	pNamesEntered = new char * [20];

	do	{
		cout << "Enter a name to be sorted and then searched: ";
		pNamesEntered [numEntered] = ReadString ();
		if (numEntered >= CurrSize)
				{
				CurrSize += arrayExpansion;
				char **	pNew;
				pNew = new char * [CurrSize];
				for (index = 0; index < numEntered; index++)
					pNew [index] = pNamesEntered [index];
				
				}
		} while (strlen (pNamesEntered [numEntered++]) > 0);


	// Printing names as they were entered
		cout << "You entered the following names: " << endl << endl;
		for (index = 0; index < numEntered; index++)
			cout << pNamesEntered [index] << endl;
		cout << endl;
		
		
	// Sorting and printing
		Sort (pNamesEntered, numEntered);
		cout << "Your sorted names are: " << endl << endl;
		for (index = 0; index < numEntered; index++)
			cout << pNamesEntered [index] << endl;
		cout << endl;

		do {
			cout << "Enter a name to search for: ";
			pNameToSearch = ReadString ();
			compareResult = Search (pNameToSearch, pNamesEntered, numEntered);
			if (compareResult == -1)
				cout << "The name you entered is missing." << endl;
				else
					cout << "The name you entered is in number: " << compareResult << endl;	
			
			} while (strlen (pNameToSearch) > 0);
		
		// Deleting the array
		for (int index = 0; index < numEntered; index++)
			delete [] pNamesEntered [index];
		
		delete [] pNamesEntered;
		pNamesEntered = 0;
	}

That is the full code of the program, minus the headers and function files. If I run the program and use less than 21 elements, everything works fine. If I run the program and use 20+ elements, everything runs fine, it inputs as many names as I want, it sorts them, I can search them all successfully, but then when the program exits, I get the following error:

Microsoft Visual C++ Debug Library

Debug Error!

Program: ...

HEAP CORRUPTION DETECTED: after normal block (#118) at 0x00355928.
CRT detected that the application wrote to memory after the end of the heap buffer.

(Press Retry to debug the application)

Abort Retry Ignore

If I leave off the delete commands at the end, the for loop to delete the elements and the delete [] pNamesEntered; it exits properly, but again, I assume it doesn't free the memory.

Any ideas?

*edit
I was messing with it some more, and I also get a Visual Studio Just-in-Time debugger error.

An unhandled win32 exception error occurred in Program10.exe [12612]
 
Last edited:
  • #14
can u fix the indenting. TRy getting rid of all the stuff in the middle between the input adn the deletion. And see if it compiles...

another thing you might want to do is dispaly the pointer address to track what pointer addys' your getting when you create each name string and see if they are the same when you are using them for sort and search.

I'm still alittle confused at why your input code block works...
because your currsize is 20, and you start your counter at 0...and when it hits 19 on teh end of the loop it increments to 20 which should crash on the next iteration when you read in idx 20.
 
Last edited:
  • #15
punx said:
Code:
				{
				CurrSize += arrayExpansion;
				char **	pNew;
				pNew = new char * [CurrSize];
				for (index = 0; index < numEntered; index++)
					pNew [index] = pNamesEntered [index];
				
				}
This code is still your problem.

I see you have:
(1) Computed the size of the expanded array
(2) Declared a temporary variable to point to the expanded array while it's being created
(3) Allocated the expanded array
(4) Pointed the temporary variable to the expanded array
(5) Copied all of the values from your old array into the expanded array

Forget anything?
 
  • #16
Hurkyl said:
This code is still your problem.

I see you have:
(1) Computed the size of the expanded array
(2) Declared a temporary variable to point to the expanded array while it's being created
(3) Allocated the expanded array
(4) Pointed the temporary variable to the expanded array
(5) Copied all of the values from your old array into the expanded array

Forget anything?

Deleting the temporary array?
I am afraid I am at a loss at what to do at this point.
 

1. What is an array of pointers in C++?

An array of pointers in C++ is a data structure that stores multiple pointers (memory addresses) to other variables or objects. This allows for efficient memory management and data manipulation.

2. How do you expand an array of pointers in C++?

To expand an array of pointers in C++, you can use the "new" keyword to allocate more memory for the array. Then, you can use the "memcpy" function to copy the existing array elements into the new, expanded array. Finally, you can delete the original array and reassign the pointer to the new array.

3. What problems can arise when expanding an array of pointers in C++?

One common problem is memory fragmentation, where there are small chunks of unused memory scattered throughout the heap. This can lead to inefficient memory usage and performance issues. Another problem is the potential for memory leaks if the old array is not properly deleted after expansion.

4. How can you avoid memory fragmentation when expanding an array of pointers in C++?

To avoid memory fragmentation, you can use the "realloc" function instead of "new" to expand the array. This will attempt to allocate continuous memory space for the expanded array, reducing the likelihood of fragmentation. You can also periodically compact the heap to consolidate any scattered memory chunks.

5. Can you expand an array of pointers without losing the data already stored in it?

Yes, it is possible to expand an array of pointers without losing the data already stored in it. This can be achieved by using the "memcpy" function to copy the existing array elements into the new, expanded array before deleting the old array. However, it is important to note that if the expanded array exceeds the available memory, data loss may occur.

Similar threads

  • Engineering and Comp Sci Homework Help
Replies
17
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
8
Views
5K
  • Engineering and Comp Sci Homework Help
Replies
3
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
7
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
11
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
5
Views
2K
  • Programming and Computer Science
Replies
5
Views
884
  • Engineering and Comp Sci Homework Help
Replies
5
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
1
Views
6K
  • Engineering and Comp Sci Homework Help
Replies
4
Views
2K
Back
Top