How to use a dynamically resizing String Array? - c++

I'm trying to use an array in C++ that changes in size. For some reason the size does not change, it only ever holds 1 string. The difficult part is that the user cannot input the number of courses they are going to add, instead the addCourse function is called until the user stops. A vector cannot be used (this is for a school assignment, and a resizing array is required). I'm stuck as to why the array only seems to hold one string, I would think it to hold the equivalent of numCourses strings. How would I go about resizing to hold multiple strings after each call to the function?
void Student::addCourse(string* courseName)
{
int x;
numCourses += 1;//increments number of courses
string newCourse = *courseName;
string* newCourses = new string[numCourses];//temporary array
for(x=0; x<numCourses - 1; x++)//fills temp array with the values of the old
{
newCourses[x] = courses[x];
}
newCourses[numCourses - 1] = newCourse;//adds extra value
delete[] courses;//removes original array
courses = newCourses;//sets the new course list
}
Edit: For those asking why a vector cannot be used because the point of the assignment is to actively avoid memory leak using the heap. Using an array like this forces intentional delete of stored values.

The comment should have answered your question: there is no way for the debugger to know that a pointer to a string is pointed to an array, nor does it know its bounds, because no such information is kept at runtime (a std::vector will show its whole contents in the debugger, in contrast).

Your method prototype should read:
void Student::addCourse(const string& courseName);
If you don't want to have a memory leak, declare a pointer to courses in your class:
private:
string* courses;
Allocate space for an array of strings in your constructor:
Student::Student()
{
courses = new String[5];
}
Then deallocate in the destructor:
Student::~Student()
{
delete[] courses;
}
This gives you room for up to 5 courses. If you need more you need to adjust the size of the array of strings at run time:
void Student::ExtendArray()
{
delete[] courses;
courses = new String[10];
}
Note this code is not exception safe, but will give you the basic idea.

Related

Set one element in Array to nullptr

new to C++ for a school project and I cannot seem to get past this final part of my project.
I have a class "Roster" that has an array of object pointers
Student* classRoster[MAX_ROSTER] = {};
These "Student" objects have been dynamically added to the array with a Roster method that does:
classRoster[arrayLength++] = new Student(...);
Where
#define MAX_STUDENTS 5
int arrayLength = 0;
The goal is to remove a specific student from the array but keep the others. The function looks something like this:
for (int i = 0; i < MAX_STUDENTS; i++) {
if (classRoster[i]->getID() == studentID) {}
}
Now inside this function I have tried a number of different things, delete the memory and set the pointer to null, attempt to delete the memory and re-arrange the array, but nothing seems to work.
I found this question with an accepted answer: Set array of object to null in C++, but that isn't working for me and I cannot figure out why.
I have set a bool and position int in the function before the loop and tried removing the student after identification, removing in the loop etc.
I assumed this would be correct:
delete[] classRoster[i];
classRoster[i] = nullptr;
(Where i is the matched student) But this deletes the memory for all the elements in the array and if I just try
classRoster[i] = nullptr;
that makes all the elements after "i" also nullptr.
delete* classRoster[i];
gives an error that we cannot delete type 'Student'
and
delete classRoster[i];
does nothing since the array doesn't have objects but pointers to objects.
What am I doing wrong?

C++ dynamic array of pointer to another class

Hello i'm trying to create a dynamic array of pointer to an object Student from Gradesclass but i can't figure out how to declare it in the header
that's the header:
class Grades
{
private:
Student** array;
int _numofStud;
public:
Grades();
Grades(const Grades& other);
~Grades();
and the grades constructor (i'm not sure it's right)
Grades::Grades()
{
this->array = new Student * [2];
for (int i = 0; i < 2; ++i)
{
this->array[i] = NULL;
}
this->array[0]= new Student("auto1", "12345");
this->array[1]= new Student("auto2", "67890");
this->_numofStud = 2;
}
The probleme is that before it even enter to the constructor, it creating me an array of Size 5 in Grades because i have 5 elements in the Student constructor
Student::Student(const char* name, char* id)
{
this->_numofgrade = 0;
this->setName(name);
this->setId(id);
this->_grades = NULL;
this->_average = 0;
}
And i can't add or modify this size
I want to put a default size of Grades to an array of 2 pointers to student object that i'll define as default then i'll have an other methods that add new Students by creating them and adding their pointers to the array
Th problem is i can't change the size of array and i don't understand why
I hope i was clear in my explanation thanks for your help
Edit:
that's the debuger and you can see when it's creating a new object Grades g1
it's creating an array of 5 instead off two
fill the 2 first as i asked for
and the 3 left i have no idea why they have been created and whats inside them
OK, so to be clear, in any actual programs you should use std::vector or other containers, they have a lot of features I ignored here (being templates, supporting move semantics, not requiring a default constructor, etc.), a lot of saftey (what if a constructor throws an exception? What if I do array.add(array[0])?), while still being pretty well optimised for general purpose usage.
And you should also really look at std::unique_ptr, manual new, delete, is generally asking for leaks and other mistakes, in C++ a manual "free" or "delete" of any resource is almost never needed.
Also note in C++ size_t is often used for sizes/lengths of objects and containers.
So the basic idea of a dynamic array is it changes it's size based on current requirements, so Grades() can just start off empty for example.
Grades::Grades()
: array(nullptr), _numofStud(0)
{}
Then when adding a new item, a new larger array is made, and all the existing items are copied (roughly what std::vector::push_back(x) does).
void Grades::addStudent(Student *student)
{
// make a larger array
Student **newArray = new Student*[_numofStud + 1];
// copy all the values
for (int i = 0; i < _numofStud; ++i)
newArray[i] = array[i]; // copy existing item
// new item
newArray[_numofStud] = student;
++_numofStud;
// get rid of old array
delete[] array;
// use new array
array = newArray;
}

Copy array then delete original

I have an array of a structure (with the parameters of name and number), and the initial array takes in elements from a document that I've made. The initial list size starts at 1000. When the list fills up, I call another method that I'm struggling with. I would like for it to copy the data into a new array that doubled the size, and then delete the old array.
If I name it: array1 and array2, I have my program use array1 throughout. I need help with the pointers that would get array2 to work as array1.
Is there a way to copy the array to a temp array of the same or new size, and then remake the initial array reassigning back to that? For this exercise, I can't use vectors. While I know how to use them, and that they solve this issue while being better, I'm trying to do it with only arrays.
using namespace std;
struct Information {
char functionality;
int SSN;
string name;
};
int numPeople = 1000;
//Gets called if the initial array (whatever size) is filled
void doubleArray(Information *array){
numPeople = numPeople * 2;
//Will now be the doubled array size
Information temp[numPeople]
for(int i = 0; i < numArray; i++){
temp[i].SSN = array[i].SSN;
temp[i].name = array[i].name;
}
//Normally makes it crash
delete[] array;
}
edit: This is what I currently have
void doubleArray(Information *person){
numPeople = numPeople * 2;
Information* temp = new Information[numPeople];
memcpy(temp, person, numPeople);
delete[] person;
person = temp;
}
It gets to numPeople = 1000 (the initial list size) but then crashes shortly after. Is the doubling array correct?
Arrays are fixed size. You cannot change the capacity of the original array.
{Use std::vector}
You can have a pointer to an array. And use the same pointer. When the array is full, you can allocate another array, copy old array items to new array, delete the old array and assign your array pointer to the new array.
{Did I mention std::vector?}
By the way, there is a data structure that performs resizing as necessary. If I recall correctly, it is std::vector. Try it out. :-)
Assuming you are using std::array (which you should be), then copying the array is very easy.
std::array<myStruct, 1000> array1{};
std::array<myStruct, 2000> array2{};
// codes...
std::copy(array1.begin(), array1.end(), array2.begin())
However, this is a specific scenario in which you only use these two arrays. It will not dynamically double the size of the array as you simply cannot do this dynamically with stack-based arrays, just like c arrays[].
What you can, and should, be using is std::vector<myStruct>. This will dynamically grow as you need it. Until you provide us with code and a more specific issue, this is the best advice that I can offer with the information provided.
If you aren't allowed to use std::vector, as one of your comments stated, then you'll want to look at dynamic allocation.
size_t sz = [whatever];
// Dynamically allocate an array of size sz.
T* T_array = new T[sz];
// Do whatever...
delete[] T_array; // new[] needs to be paired with delete[].
T_array = nullptr; // Not strictly necessary, but a good idea if you have more code after.
As the size doesn't need to be constant for a dynamic array, this will allow you to allocate memory as necessary. You can then use std::copy() to copy data from one array to the other, as Goodies mentioned.
[For more information on dynamic allocation, see here.]

pointer to string that can be used to dynamically allocate array of strings

Im writing a project and its for a car lot and im creating classes. I need to fullfill certain requirements. For accessory descriptions I need to use a pointer to a string that can be used to dynamically allocate an array of strings with the exact number of accessories. Each element will hold the name of the accessory.
If the number of accessories is 0, there is no need to allocate space, set the pointer to null.
And also pointer to a double that can eb used to dynamically allocate an array of doubles with the same number of elements as accessories. Each element will hold the cost of the associated accessory, that is, the cost in element 0 is the cost of the accessory in element 0.
If the number of accessories is zero, set the pointer to null since there is no need to allocate space.
Heres what my class is so far without those last two requirements. Im stumped.
#ifndef VEHICLE_H
#define VEHICLE_H
class Vehicle
{
public:
Vehicle();
protected:
int vin_number;
string manufacturer;
string model;
string color;
double basecost;
int accessories;
string accessory_list;
private:
};
#endif // VEHICLE_H
Please help it's an online course and ive been googling and reading for hours.
You should not dynamically allocate an array of string.
If you decide to use C++, you should be using STL and collections. Like this:
std::list<std::string> accessory_list;
If you decide to use C, a dynamically allocated string list could look like this:
//init
int accessory_count = 0;
int accessory_cap = 20;
char** accessory_list = calloc (sizeof(char*), accessorry_cap);
//add:
if (accessory_count==accessory_cap) {
accessory_cap += 20;
accessory_list = realloc (accessory_list, sizeof(char*)* accessorry_cap);
}
accessory_list[accessory_count++] = new_accessory.
If you really need a dynamic array of strings, you can do:
int accessory_arr_cap = 20;
string* accessory_arr = new string[accessory_arr_cap];
But since there is no realloc possible in this case, you will have to copy the entire array into new one if you need to enlarge it.
If the cost and name of the option are related, put them in a struct:
struct Option
{
char* Name;
double price;
}
Than what you are looking for is a collection, perhaps a std::vector<Option>. I'll leave it up to you to google the std::vector, it's a good learning exercise.
On a side note, do you have to use C++? You might find another language like C#, or Java a little easier to learn to program with.
If you can't use vectors, make your own collection. I won't post the code because I sense this is an assignment but here's how they normally work:
instantiate with a default size array of say 10.
keep a variable with this max in it
keep a variable with the current number of items in it (starts at 0, maybe call it count or something)
when you add a pointer, put it in element 'count' and increment the counter
if count = capacity then allocate a new array 2*capacity, copy all elements into it, delete the old one and assign the new array to the variable that was the old array.

how to grow a dynamic array of char pointers (in C++)?

I am trying to work with an array of char pointers.
Let's say I dynamically declare such an array like so:
int numrows=100;
char** array = new char*[numrows];
And then I populate it by using getline to get strings from a file, converting the strings to char arrays, then setting a pointer in my array to point to said char array like so:
string entry;
int i=0;
while (getline(file,entry)){
char* cstring = new char[entry.length()];
array[i]=strncpy(cstring,entry.c_str(),entry.length());
free(cstring);
i++;
}
(this works, but is there a better way to do this?)
The problem is, I don't know how to grow the array once i becomes greater than numrows.
I know how to do this for a single-dimensional array, but the two-dimensionality is throwing me off.
I'm thinking I should be able to grow it the way you would grow a single-dimension array, right?
if (i==numrows){
char** temp = new char*[numrows+numrows];
for (int j=0;j<i;j++){
char* cstring = new char[strlen(array[i])];
temp[i]=strncpy(cstrin,array[i],strlen(array[i]));
free(cstring);
}
delete [] array;
array = temp;
}
So if the current array becomes full, make a second array that is twice the size of the current array and fill it with the contents of the current array. Then delete array and let array point to temp. I'm fine up to making temp the new array. I can get the contents of array into temp, but when I delete array and set array = temp, the contents of array aren't the contents of temp.
So my question is how can/should I be growing this dynamic array of char pointers?
use std::vector - it is your friend
std::vector<std::string> arr;
while(getline(file, entry))
{
arr.push_back(entry);
}
done
sort can be done using vector sort with custom compare
bool less3(const std::string &s1, const std::string &s2)
{
return s1.compare(0, 3, s2, 0, 3) == 0;
}
std::sort(arr.begin(), arr.end(), less3);
I bet that less3 could be made more efficient but readability wins unless you really suffer
edit fixed as per nice comment from gman
Apart from the remarks by Tyler McHenry, and the fact that you should use the STL, the problem is most likely that you are freeing each cstring after having copied it. Perhaps you intended to free the original string instead?
for (int j=0;j<i;j++){
char* cstring = new char[strlen(array[i])];
temp[i]=strncpy(cstring,array[i],strlen(array[i]));
delete[] array[i];
}
When you first populate the array, DO NOT call free() on the string. First of all, you should use delete[], but more importantly, you still want to access that string later, right?
now i see you say that this is a class that does allow you to use STL. A class teaching c++ that forbids one of the major language features! - anyway passing along
You do not need to be copying the strings to resize the array , you just need to copy the pointers.
if (i==numrows){
char** temp = new char*[numrows+numrows];
for (int j=0;j<i;j++){
temp[j]=array[j];
}
delete [] array;
array = temp;
}
i am sure there are still out by ones there - left as homework