I found a function to resize an array and am having trouble understanding how it works (or if it's working properly). For testing I set the "temp" array to a new value and "startCounter" does get assigned to that value, however the memory location for startCounter doesn't change. Here is my code:
int * startCounter;
void resizeArray(int *&arraySent,int origSize,int newSize) {
output << "&arraySent " << &arraySent << endl;
output << "arraySent[0] " << arraySent[0] << endl;
int* temp = new int[newSize];
output << "&temp " << &temp << endl;
for (int i=0; i<origSize; i++) {
temp[i] = arraySent[i];
}
temp[0]=744;
delete [] arraySent;
arraySent = temp;
output << "&arraySent " << &arraySent << endl;
}
//....
startCounter = new int [3];
startCounter[0]=345;
output << &startCounter << endl;
resizeArray(startCounter,3,10);
output << "startCounter[0]" << startCounter[0] << endl;
output << "&startCounter" << &startCounter << endl;
Here is the output I get from this:
&startCounter 0x60fab8
&arraySent 0x60fab8
arraySent[0] 345
&temp 0x82cfe54
&arraySent 0x60fab8
startCounter[0] 744
&startCounter 0x60fab8
My question is, why does the memory location of startCounter not change from 0x60fab8 after deleting it and assigning it to the new "temp" array? Shouldn't it now become 0x82cfe54?
P.S. I understand about vectors and such but am mainly concerned with understanding how this particular function works.
void resizeArray(int *&arraySent,int origSize,int newSize) {
output << "&arraySent " << &arraySent << endl;
outputs the address of the pointer variable, not the address that it holds.
simply omit the address operator to get the (probably) intended effect
&startCounter is the address of the pointer, not the address it points to. it's value won't change. simply use startCounter.
Related
I have just done a module on pointers and dynamic memory in C++ and am attempting to complete a personal assignment so that I can practice the concepts. The program manages an array of strings that are names. The goal that I set for myself is that the list is stored in the heap (to practice using "new"), and the list is dynamically sized as new names are entered.
Disclaimer: I realize that this is easily accomplished using vectors, and after struggling with this for hours I re-wrote my original code to use a vector for the list with no problems. However I want to learn where my understanding of how pointers work is broken.
The problem that I have with the program is this: I initialize the name array to have zero elements and have a function to add names that handles the dynamic sizing. When first called it seems to re-size the array correctly and add a new name to the the new array. Within the function to add a name, I can print the contents of the new array. I can also re-assign the old array pointer to the address of the new array on the heap. However when I call the print function from main after adding a name to the list, the list does not contain a name. By my understanding, since I'm using pointers I should be updating values directly, so after the add name function terminates, the values should persist. Also, if I attempt to add a second name the program crashes. What am I doing wrong with the handling of memory?
I've searched quite a bit and the closest that I can find for a resolution was this post:
How to make an array with a dynamic size? General usage of dynamic arrays (maybe pointers too)?
I modified my code based on what I understand from that but it still doesn't work properly.
#include <stdio.h>
#include <vector>
#include <iostream>
using namespace std;
void add_name_to_list(string * my_list, size_t * list_size);
string get_name();
void print_names(const string *const my_list, const size_t *const list_size);
int main()
{
string *name_list_ptr {nullptr};
name_list_ptr = new string [0];
size_t name_list_size{0};
size_t *name_list_size_ptr {&name_list_size};
print_names(name_list_ptr, name_list_size_ptr);
add_name_to_list(name_list_ptr, name_list_size_ptr);
print_names(name_list_ptr, name_list_size_ptr);
return 0;
}
void add_name_to_list (string * my_list, size_t *list_size)
{
string new_name{get_name()};
string *new_string_ptr{nullptr};
new_string_ptr = new string [*list_size+1];
// copy existing list into new list
cout << "List size is " << *list_size << " so *list size == 0 is " << (*list_size == 0) << endl;
if(*list_size == 0)
{
new_string_ptr[0] = new_name;
*list_size = *list_size +1;
cout << new_string_ptr[0] << " has been added to position " << *list_size << endl;
}
else
{
print_names(my_list, list_size);
for(size_t i{0}; i < *list_size; i++)
{
cout << "At position " << i << " original list is " << my_list[i] << endl;
new_string_ptr[i] = my_list[i];
cout << "The name " << new_string_ptr[i] << " has been added to position " << i << " of the new list" << endl;
}
new_string_ptr[*list_size - 1] = new_name;
*list_size = *list_size + 1;
}
print_names(new_string_ptr, list_size);
string *temp_ptr{nullptr};
temp_ptr = new string [*list_size-1];
cout << "temp ptr is " << temp_ptr << " and my list is " << my_list << endl;
temp_ptr = my_list;
cout << "temp ptr is " << temp_ptr << " and my list is " << my_list << endl;
my_list = new_string_ptr;
delete [] temp_ptr;
new_string_ptr = nullptr;
print_names(my_list, list_size);
}
string get_name()
{
cin.sync();
cin.clear();
string new_name{};
cout << "\nEnter the full name: ";
getline(cin, new_name);
cin.sync();
cin.clear();
if(new_name.size() <= 1)
return "0";
else
return new_name;
}
void print_names(const string *const my_list, const size_t *const list_size)
{
if(*list_size == 0)
cout << "The list is empty" << endl;
else
for(size_t j{0}; j < *list_size; j++)
cout << j << ". " << my_list[j] << endl;
}
One variation that I've tried based on what I learned from searching is:
cout << "temp ptr is " << temp_ptr << " and my list is " << my_list << endl;
//my_list = new_string_ptr;
//delete [] temp_ptr;
//new_string_ptr = nullptr;
delete [] my_list;
my_list = new string[*list_size];
my_list = new_string_ptr;
print_names(my_list, list_size);
Unfortunately the results are the same.
Without checking the logic of the implementation, your list doesn't update because you are assigning my_list = new_string_ptr; but your function received void add_name_to_list (string * my_list, size_t *list_size).
As you are newcomer to C++ world, let me explain clearly:
list_size is a pointer to a size_t, so if you modify the pointed memory, the change will persist, but if you modify the pointer itself, it will not.
list_size = new size_t; // This change doesn't persist
list_size++; // This change doesn't persist
*list_size++; // This change persists and the value of pointed memory was increased.
With my_list is happening exactly the same, you are trying to modify the pointer itself, not the pointed memory.
So, you should use:
void add_name_to_list (string * &my_list, size_t *list_size)
Or maybe you are more confortable with
void add_name_to_list (string ** my_list, size_t *list_size)
[...]
*my_list = new_string_ptr;
Hope this helps
I am trying to add pointers to an object to a vector in a function like this:
vector:
vector<struct Node*> vars;
function:
void fill_vec(){
struct Node* temp;
temp = new Node();
cout << token << endl;
temp->name = token;
temp->value = 0;
cout << temp << endl;
vars.push_back(temp);
}
fill_vec is being called in a while loop that stops when there aren't anymore variable names.
It is adding the correct amount of nodes to the vector, but everything is pointing to the same object. Token is being parsed.
output of above:
a
0x9c6010
b
0x9c6050
printing vector:
void print_vars(){
for(int i = 0; i < vars.size(); i++){
cout << "Name:" << vars[i]->name << endl;
cout << "Value:" << vars[i]->value << endl;
}
}
output:
Name:b
Value:0
Name:b
Value:0
My thought was that when I allocated new memory, the address would change. When I print the address of temp each time I call the function, the address is the same. I was printing the address wrong. The address is different for each call of the function. Thank you in advance for the help.
My thought was that when I allocated new memory, the address would change.
It does indeed.
When I print the address of temp each time I call the function, the address is the same.
That is because you are printing out the address of a local variable, which happens to reside at the same stack memory address each time fill_vec() is called. You should be printing out the memory address of the allocated Node instead.
Change this line:
cout << &temp << endl;
To this:
cout << temp << endl;
As it turns out, it was the token. Token is a char* and I was not using strdup() on it. So every time I updated token, name was being changed in each object.
So, I have been trying to learn C++ and in the tutorial book that I am reading, I have gotten stuck on a problem of pointers-to-pointers. What I am trying to do change the pointer a pointer-to-pointer is pointing to without changing the value of the original pointer. Here's some code...
#include <iostream>
void testFunc(int **func_p_to_p) {
int *createdPointer = new int(10);
*func_p_to_p = createdPointer;
cout << **func_p_to_p << endl; //prints 10 as I expect
}
int main() {
int **main_p_to_p = NULL;
int *mainPointer = new int(5);
main_p_to_p = &mainPointer;
testFunc(main_p_to_p);
cout << **test << endl;//prints 10, I expect this...
cout << *mainPointer << endl; //prints 10 as well, I don't want that.
}
I asked a similar question about this earlier, here and I understand sort of what is going on. However, I can't seem to figure out how I would change where a pointer-to-pointer is pointing to without changing the original value. Could anyone explain how I would do this? Thanks.
In the line
*func_p_to_p = createdPointer;
you first follow your pointer-pointer to what it is pointing to: The address of int *mainPointer.
Next you assign a new value to this pointer, the value of createdPointer which is the address of new int(10).
So your mainPointer is now changed to target the same memory as createdPointer. Does this make any sense to you?
You can't do that. main_p_to_p points to mainPointer, so modifying *main_p_to_p modifies mainPointer, full stop.
You might be looking for this, though:
int main() {
int **main_p_to_p = NULL;
int *mainPointer = new int(5);
int *secondPointer = mainPointer;
main_p_to_p = &secondPointer;
// prints 5 5 5
cout << *mainPointer << " " << *secondPointer << " " << **main_p_to_p << std::endl;
testFunc(main_p_to_p);
// prints 5 10 10
cout << *mainPointer << " " << *secondPointer << " " << **main_p_to_p << std::endl;
}
Note that you don't need the main_p_to_p variable, but I left it in for consistency with the question.
I'm new to c++ currently working on my assignment and encounter this runtime error "Access violation reading location" when trying to assign iterator pointer into array using for loop.
Flist = data.getFList();
for(Fit = Flist.begin(); Fit != Flist.end(); Fit++)
{
++counter;
cout << "(" << counter << ") Destination: " << Fit->getDest() << " [Class: " ><< Fit->getClass() << "]" << endl;
_getch();
fArr[counter] = *Fit;
}
Constructor
Staff::Staff()
{
counter = 0;
fArr = new Flight[counter];
};
Header
Flight *fArr;
int counter;
Any help will be great~
When you allocate memory in the constructor, you're creating an array of 0 size, that doesn't really make sense.
Instead, just use a vector of flights: std::vector<Flight> fArr, and push back to it:
fArr.push_back(*Fit);
This may a stupid question, but I'm gonna ask it anyway:
Suppose you have a pointer: Object* pointer which points at a dynamically allocated object.
class PointClass
{
Array<Object*> m_array1;
Array<Object*> m_array2;
void Delete1()
{
for (int i = 0; i < m_array1.Length; i++)
{
delete m_array1[i];
}
}
void Delete2()
{
for (int i = 0; i < m_array2.Length; i++)
{
delete m_array2[i];
}
}
}
Now, you put your pointer both in m_array1 and in m_array2.
When you try to delete the arrays, in one of them you will have a pointer which points to a deallocated space, so you can't delete it again!
I can't just assign the pointers NULL after the deletion because it wouldn't affect the pointer in the other array.
How would you solve it?
Well the simplest way would be to use a reference-counting pointer, like those available in boost::smart_ptrs.
Otherwise, you need to assign owners to the pointers - you need to decide which class will be responsible for allocating/deleting that particular pointer. If for some reason you decide that should be this class, then you could remove the duplicates from the arrays by adding all the pointers to a set before enumerating them.
If you have to share pointers in this way, something like a ref counted pointer may work well.
See this site which gives an exposé of various 'smart-pointer' techniques.
Smart Pointers
My initial answer is: Don't do that.
If you absolutely have to for some reason, you could wrap it in a smart pointer
Best solved is not passing the same pointer to both arrays. :P If you really need to, and you also need to reflect that change to all other "same" pointers, a pointer-to-pointer will do.
#include <iostream>
struct Object{};
int main(){
Object* ptr = new Object;
Object** ptrptr = &ptr;
delete *ptrptr;
*ptrptr = 0;
// both print 0
std::cout << *ptrptr << std::endl;
std::cout << ptr << std::endl;
}
On Ideone.
Another way is with a reference-to-pointer.
int main(){
Object* ptr = new Object;
Object*& refptr = ptr;
delete refptr;
refptr = 0;
// both print 0
std::cout << refptr << std::endl;
std::cout << ptr << std::endl;
}
But the second best way is probably a ref-counted smart pointer.
How would you solve it?
By not storing the same pointer in two different places. Doing this creates a duplication of data, and confuses ownership semantics. Who owns the memory pointed to by pointer? Ownership is not clear.
Under normal circumstances, dynamically allocated objects should be owned by the same module that allocated it, and only that module will have direct access to the objects or delete the memory. That's not to say other modules can't get at the data.
As others have suggested use smart pointers to solve your problem. If you have to solve it by writing your own code, I would make each of the delete function also search the "other" array to delete all pointers in the first array that can be found in the other array. And it is a last option option as this would not be my first solution to implement anything as your approach
void Delete2()
{
for (int i = 0; i < m_array2.Length; i++)
{
for (int j = 0; j < m_array1.Length; j++)
{
if (m_array2[i] == m_array1[j])
{
delete m_array1[j]
m_array1[j] = NULL;
}
delete m_array2[i];
m_array2[i] = NULL;
}
}
Then look for ways to optimise it
If I understood your question, you have the same (valid) pointer stored in 2 different arrays.
The problem is that after you delete it on array1, you can't do it again in the second array.
One way to do this is change your array definition to store the memory address of the pointer itself, instead of storing the address of the allocated memory:
const int array_size = 3;
int** m_array1[array_size];
int** m_array2[array_size];
and the rest of the code could be implemented as:
void Delete1()
{
for (int i = 0; i < array_size - 1; i++) // delete all memory but leave the last intact
{
if (*(int*)m_array1[i])
{
cout << "Delete1: erasing #" << i << " with mem addr " << std::hex << *m_array1[i] << std::dec << endl;
delete *m_array1[i];
*m_array1[i] = NULL;
}
}
}
void Delete2()
{
for (int i = 0; i < array_size; i++)
{
if (*m_array2[i])
{
cout << "Delete2: erasing #" << i << " with mem addr " << std::hex << *m_array2[i] << std::dec << endl;
delete *m_array2[i];
*m_array2[i] = NULL;
}
else
{
cout << "Delete2: !!! memory at #" << i << " was already deleted." << endl;
}
}
}
int main()
{
int* num1 = new int(10);
int* num2 = new int(20);
int* num3 = new int(30);
cout << "main: storing " << std::hex << &num1 << " which points to " << num1 << std::dec << endl;
cout << "main: storing " << std::hex << &num2 << " which points to " << num2 << std::dec << endl;
cout << "main: storing " << std::hex << &num3 << " which points to " << num3 << std::dec << endl;
m_array1[0] = &num1;
m_array1[1] = &num2;
m_array1[2] = &num3;
m_array2[0] = &num1;
m_array2[1] = &num2;
m_array2[2] = &num3;
Delete1();
Delete2();
}
Outputs:
main: storing 0xbfc3818c which points to 0x87b6008
main: storing 0xbfc38188 which points to 0x87b6018
main: storing 0xbfc38184 which points to 0x87b6028
Delete1: erasing #0 with mem addr 0x87b6008
Delete1: erasing #1 with mem addr 0x87b6018
Delete2: !!! memory at #0 was already deleted.
Delete2: !!! memory at #1 was already deleted.
Delete2: erasing #2 with mem addr 0x87b6028