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.
name_list_ptr = new string [0];allocates an array of zero size. There's not that much you can do with such an object. You can safelydeleteanullptr, so I'd save the trouble of allocating and having todeletean unusable allocation and just leavename_list_ptrpointing atnullptr.std::vectorI write a simple poor-man'svector. Getting even a simple mockvectorworking is quite educational and well worth the time invested.