Dynamic memory allocation array

Pages: 12
Hey everyone I have a question thats ben bugging me for over a month now and I seem to be stuck on this chapter of my c++ book (alex allains jumping into c++)

so the chapter is Dynamic memory allocation I'm so confused as to how this code actually works here is the description of what he wants the code to do this is a snippet taken from the book with his explanation
"int count_of_numbers;
cin >> count_of_numbers;
int *p_numbers = new int[count_of_numbers];

this code asks the user how many numbers are needed and then uses that variable to determine the size of the dynamically allocated array.in fact,we don't even need to know up-front the exact number-we can just reallocate the memory as the values grow.this means we'll be doing some extra copying,but it's possible.let's look at a program that demonstrates this technique ,let's have this program read in numbers from the user,and if the user enters more numbers than can fit in the array,we'll resize it."

so heres the code I'll comment what parts confuse me and what I think I understand comments with the star are mine

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
  #include <iostream>

using namespace std;

int *growArray (int* p_values, int *size);
void printArray (int* p_values, int size, int elements_set);

int main ()
{
	int next_element = 0;
	int size = 10;
	int *p_values = new int[ size ]; // sets array size to 10 understand
	int val;
	cout << "Please enter a number: ";
	cin >> val;
	while ( val > 0 )
	{
		if ( size == next_element + 1 ) // *don't understand
		{                   // *how can size = next element plus one?
			// now all we need to do is implement growArray 
			// notice that we need to pass in size as a pointer
			// since we need to keep track of the size of the array as
			// it grows!
			p_values = growArray( p_values, & size );
		}
		p_values[ next_element ] = val;
		next_element++;
		cout << "Current array values are: " << endl;
		printArray( p_values, size, next_element );
		cout << "Please enter a number (or 0 to exit): ";
		cin >> val;
	}
	delete [] p_values;
}

void printArray (int *p_values, int size, int elements_set)
{
	cout << "The total size of the array is: " << size << endl; 
	cout << "Number of slots set so far: " << elements_set << endl;
	cout << "Values in the array: " << endl;
	for ( int i = 0; i < elements_set; ++i )
	{
		cout << "p_values[" << i << "] = " << p_values[ i ] << endl;
	}
}

int *growArray (int* p_values, int *size)
{
	*size *= 2;
	int *p_new_values = new int[ *size ];
	for ( int i = 0; i < *size; ++i )
	{
		p_new_values[ i ] = p_values[ i ];
	}
	delete [] p_values;
	return p_new_values;
}



to be honest I really have very little clue as to whats happening here i'm lost,I must have read the example literally hundreds of times but I can't figure out how to make sense of all this could someone try break this down with me step by step? I would be very thankful and appreciate it more than anything it's stressing me out bad and my exams are fast approaching for college =( I'm sorry if it's a long question or long to break down
Hi,
I found a logic error in this example. It is "Segfaults", a pretty potential danger.

So is this a solution you made?
no this is the example in the book I'm totally lost
> No this is the example in the book I'm totally lost
How funny. How come they made a mistake like that?
The next_element variable contains the index where the next value will be stored in the array. When the user inputs more and more numbers this value will grow and eventually it reach the value of size (the size of the array). At that point you need to reallocate the array to make room for more elements.

I have no idea why they check the size against next_element + 1 because the array doesn't need to be reallocated until size is exactly equal to next_element. It's probably just a mistake. It's not a huge deal, just means it will waste a little more memory on average.

Last edited on
closed account 5a8Ym39o6 wrote:
How come they made a mistake like that?
What mistake?

adam2016 wrote:
*how can size = next element plus one?
Within each iteration of the loop (line 16) next_element is increased (line 27). So at one point the amount of elments (next_element) does not fit in the allocated buffer (size).

At this moment the condition if ( size == next_element + 1 ) is true.

And that is the moment the allocated buffer must grow, hence within in the body of the if (line 18) growArray() is called.
Thanks Peter it's slowly starting to make sense allthough still not quite sure how it works I have a better understanding now I'm breaking it down into smaller chunks it's helping a lot so heres my code which I have broken it down a little just getting user input but I have a question how come I don't need to include the [] for the array in the parameters of my function I thought when you are passing an array you have to declare this in the function parameters

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

#include <iostream>

using namespace std;

void printArray(int *ray,int size,int elements_set){

     cout << "number of elements set = " << elements_set << endl;
     for(int i = 0;i < elements_set;i++){


        cout << "ray[" << i << "] = " << ray[i] << endl;

     }

}


int main()
{

   int size = 10;
   int *ray = new int[size];
   int nextElement = 0;
   int val;
   cin >> val;

   while(val > 0){

       ray[nextElement] = val;
       nextElement++;
       printArray(ray,size,nextElement);

       cin >> val;
   }

}


so on line 6 I thought it should be (int* ray[]) instead of (int *ray)
Last edited on
@coder777
1
2
3
4
5
6
7
8
9
10
11
int *growArray (int* p_values, int *size)
{
	*size *= 2;
	int *p_new_values = new int[ *size ];
	for ( int i = 0; i < *size; ++i )
	{
		p_new_values[ i ] = p_values[ i ];
	}
	delete [] p_values;
	return p_new_values;
}


Assuming p_values points to a dynamically allocated array with (size == 10). The (size) doubles (20), then the program attempts to allocate another array that doubles the size of the old one. Then it will perform a copy operation to transfer data from the old array to the new array using a temporary index variable (i). Then what happens? The old array only contains 10 elements, and when (i) exceeds 9 (or when it is 10 or larger), the program encounters segfaults.
also thanks coder777 and closed account,any of you guys know what I mean just above in my last post ^^
It is indeed a bug to copy the doubled size.
adam2016 wrote:
how come I don't need to include the [] for the array in the parameters of my function I thought when you are passing an array you have to declare this in the function parameters

When you pass an array to a function you are actually passing a pointer to the first element in the array. You could write the function parameter as int* ray or int ray[], it doesn't matter.
Last edited on
Hi guys thanks for helping me get through the first part of this problem the printArray function I fully understand it now but now I move to the second part and the main problem "growing the array"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


int *growArray (int* p_values, int *size)
{
	*size *= 2;
	int *p_new_values = new int[ *size ];
	for ( int i = 0; i < *size; ++i )
	{
		p_new_values[ i ] = p_values[ i ];
	}
	delete [] p_values;
	return p_new_values;
}



I have a few questions regarding this I'm still quite confused when it comes to this function

A)why do we use *growArray as the function declaration and not just growArray?
B)how come it uses *size but not size? I thought that when you create a pointer variable you can just use it by it's name without the asterix in front of it
C)why do we use delete [] on the array p_values when p_values was not even declared in this function? I thought we would do this outside the function?

Thanks in advance

Adam
A) The * belongs to the int return type, not the function name. The function's return type is a pointer to an int.

B) Because you want to use the int that the pointer points to, not the pointer itself.

C) Because you want only one array allocated when you exit. The caller is going to be doing:
 
  p_values = growArray (p_values, &p_size)l;

After the call to growArray(), p_values is going to be pointing to the larger area. The caller is still responsible for releasing the new p_values.

BTW, you're going to be making an out of bounds reference to the old array at line 9. You've doubled size, but p_values has only *size entries, not (2*(*size)).


Thanks Anon

thanks B totally makes sense I should have knew that one,but going back to the question A how come we have a pointer as the return type and why can't we just return an ordinary int instead of an int pointer?


and on C what would happen if I didn't delete p_values the original array?

how come we have a pointer as the return type and why can't we just return an ordinary int instead of an int pointer?

Because you want to tell the caller where the new array is.

what would happen if I didn't delete p_values the original array?

You would have a memory leak.

Thanks a million for the help Anon much appreciated I understand both B and C now,

I'm still a little bit iffy on A ,I'm still not too sure why I couldn't just use growArray instead of *growArray (having return type as a pointer)I thought you could get the same thing accomplished without using a pointer as the return why would the caller (p_values in this case) need to know where the array is and how would it know?

sorry if I'm been confusing
,I'm still not too sure why I couldn't just use growArray

The caller allocates an array (more than 1 int) and assigns it to p_array. The caller stores some values into p_array. Now at some point your code decides that the array (p_array) is not big enough., so it calls grow_array(). grow_array() needs to allocate the array someplace else because p_array is not big enough. Fine, line 6 does that. When you exit grow_array(), the caller wants to continue accessing the bigger p_array as if nothing had happened.
Note the line I posted above:
 
p_values = growArray (p_values, &p_size)l;  // updates p_array (pointer) with the pointer returned by grow_array 

If you don't return the address of the new area, how is the caller going to know where the new area is?

Last edited on
aww that's very true because the array I assigned is a pointer

int *p_values = new int[size]

that makes sense now thanks,much appreciated

just a side question not necessarily to with the original question but how come

you can use p_values = growArray (p_values, &p_size)

to make one array = another array(new array returned by growArray)

but not make one array = another array this way

1
2
3
4
5
int one[3];
int two[3];

one = two;
Last edited on
Pointers (of the same type) can be reassigned freely*. one and two are not pointers. They are arrays. If line 4 were legal, you would lose addressability to the original space occupied by one (a memory leak).

* When using pointers and dynamic memory you must be careful not to introduce memory leaks.
Last edited on

now I get it =)

p_values is a pointer pointing to an array *p_values = new int[size];

BUT

we then change where the pointer p_values is pointing to when we use p_values = growArray(parameters)

after that line the pointer p_values is pointing to the new array,

am I right?






and thanks I'm going to study over my pointer section again much appreciate
Last edited on
Pages: 12