Dynamic Array Using Strings in a Function Issues - c++

I'm trying to run a dynamic array that employs strings, but when I push it through a function I get compile errors 'dynamicArray': undeclared identifier, 'string':undeclared identifier, and illegal use of type 'void'. All of these errors point to the header for some reason.
I call the pointer here:
string* dynamicArray = NULL;
I call the function here:
populateArray(dynamicArray);
What is in the header:
void populateArray(string *&dynamicArray);
The function:
void populateArray(string *&dynamicArray)
{
char decide;
bool moreStrings = true;
int counter = 0;
while (moreStrings == true)
{
counter ++;
dynamicArray = new string[counter];
cout << "\nEnter your string here:";
cin >> dynamicArray[counter - 1];
cout << "\nDo you want to enter another string? Y/N:";
cin >> decide;
decide = toupper(decide);
if (decide == 'N')
{
moreStrings = false;
}
}
}
PS: vector may be better, but I'm afraid that isn't an option. Please only offer fixes that deal with pointers.

With #include <string> and using namespace std; added, it compiles just fine for me.
#include <string>
#include <iostream>
using namespace std;
void populateArray(string *&dynamicArray);
int main(){
string* dynamicArray = NULL;
populateArray(dynamicArray);
return 0;
}
void populateArray(string *&dynamicArray)
{
char decide;
bool moreStrings = true;
int counter = 0;
while (moreStrings == true)
{
counter ++;
dynamicArray = new string[counter];
cout << "\nEnter your string here:";
cin >> dynamicArray[counter - 1];
cout << "\nDo you want to enter another string? Y/N:";
cin >> decide;
decide = toupper(decide);
if (decide == 'N')
{
moreStrings = false;
}
}
}

You need to include <string> in your header file.
BTW, there might be potential memory leak in your code, if moreString is true, dynamicArray will point to another new string array, without deleting current one.

I see a bigger problem than the missing include and the using clause...
You wrote:
dynamicArray = new string[counter];
But this will allocate a new memory area for you every time. It does not copy the previously allocated elements. IF you don't want to use std::vector, you need to use malloc for the first element and than call realloc to copy your previously allocated data to your new one.
Check this form more info: What is C++ version of realloc(), to allocate the new buffer and copy the contents from the old one?

Related

Code exiting when Dynamic Array of class allocated

I am trying to dynamically allocate an array and whenever it gets to the part where it dynamically allocates the program exits. I would rather not use vectors as I am trying to learn how to do this using dynamic arrays.
This is the simplified code:
#include <iostream>
#include <string>
using namespace std;
class Student
{
private:
double calcAverage(double* testArray);
char calcGrade(double average);
public:
int nTests, sameTests, idNum;
string name;
double average, *testArray;
char grade;
};
int i;
Student fillStudentArray(int nStudents);
int main()
{
*studentArray = fillStudentArray(nStudents);
return 0;
}
Student fillStudentArray(int nStudents)
{
Student *newStudentArray = new Student[nStudents];
cout << "If you can see this I worked. ";
delete[] studentArray;
return *newStudentArray;
}
I have tried the solution posted here Creation of Dynamic Array of Dynamic Objects in C++ but it also exits in a similar way. The main for the code looks like this.
int main()
{
int nStudents = 3; //this number is just for testing, in actual code it has user input
Student** studentArray = new Student*[nStudents];
cout << "1 ";
for(i = 0; i < nStudents; i++)
{
cout << "2 ";
studentArray[i] = new Student[25];
cout << "3 ";
}
return 0;
}
close (heres a cigar anyway)
Student* fillStudentArray(int nStudents); <<== function must return pointer to students
int main()
{
int nStudents = 3; <<<=== declared nstudents
Student *studentArray = fillStudentArray(nStudents); <<< declare studentArray
return 0;
}
Student *fillStudentArray(int nStudents) <<<== return pointer
{
Student* newStudentArray = new Student[nStudents];
cout << "If you can see this I worked. ";
// delete[] studentArray; <<<== what were you trying to delete?
return newStudentArray; <<<=== return pointer
}
the second code you showed is not relevant, its creating a 2d array

What is the problem I am having with using arrays with classes?

I have been working on a project for my computer science class and have encountered an issue with the code working. I am shown no error except when I try to compile and I get an error that reads:
Exception thrown: write access violation.
_Left was 0xCCCCCCCC.
The purpose of my project is to take a list of names from an external file, read them into an array, sort said array and then output the sorted list all while using a class for the code.
Here is a copy of my code and I would like to extend my gratitude to whoever can help me through my issue:
**Header File**
#include <iostream>
using namespace std;
class person
{
public:
person();
bool get(ifstream&);
void put(ofstream&);
private:
int capacity = 0;
string first_name[CAPACITY];
string last_name[CAPACITY];
int age[CAPACITY];
};```
**Header function definitions cpp file**
#include<iostream>
#include<string>
#include<fstream>
#include<cstdlib>
const int CAPACITY=20;
using namespace std;
#include "Person.h"
//Names constructor
//Postcondition both first name and last name initialized to zero
person::person()
{
first_name[CAPACITY] = "";
last_name[CAPACITY] = "";
age[CAPACITY]=0;
}
bool person::get(ifstream& in)
{
in >> first_name[CAPACITY] >> last_name[CAPACITY] >> age[CAPACITY];
return(in.good());
}
void person::put(ofstream &out)
{
out << first_name[CAPACITY] << last_name[CAPACITY] << age[CAPACITY];
}
**cpp file which holds main**
#include<iostream>
#include<cstdlib>
#include<fstream>
#include<string>
const int CAPACITY = 20;
using namespace std;
#include "Person.h"
void pop(string *xp, string *yp);
void sort(string name[CAPACITY], int count);
int main()
{
class person names[CAPACITY];
ifstream infile;
ofstream outfile;
string filename;
string name[CAPACITY];
int n = 0;
cout << "Enter the file name you wish to open" << endl;
cin >> filename;
infile.open(filename + ".txt");
outfile.open("Person_New.txt");
if (infile.fail())
{
cout << "The file requested did not open" << endl;
exit(1);
}
while (!infile.eof())
{
names[n].get(infile);
n++;
}
sort(name, CAPACITY);
for (int i = 0; i < CAPACITY; i++)
{
names[i].put(outfile);
}
cout << "The file has been created" << endl;
infile.close();
}
void pop(string *xp, string *yp)
{
string temp = *xp;
*xp = *yp;
*yp = temp;
}
void sort(string name[CAPACITY], int count)
{
int i, j;
for (i = 0; i < count - 1; i++)
{
for (j = 0; j < count - i - 1; j++)
{
if (name[j] > name[j + 1])
{
pop(&name[j], &name[j + 1]);
}
}
}
}
Once again Thank you for any support
It sounds to me like the compiler is getting upset that you are trying to write (i.e. assign a value) at an address that you do not have permission to access. I believe your constructor for the class person might be at fault because of how this class stores its variables, as well as the class header:
Constructor for the class person:
`person::person(){
first_name[CAPACITY] = "";
last_name[CAPACITY] = "";
age[CAPACITY] = 0;
}`
Class header for the class person:
`class person{
public:
//stuff
private:
int capacity = 0;
std::string first_name[CAPACITY];
std::string last_name[CAPACITY];
int age[CAPACITY];
//more stuff
}`
C++ is very specific about its naming conventions, so it makes a distinction between capacity and CAPACITY. Because of this, the variable CAPACITY is not defined within the Person.h file.
Also, because CAPACITY is set to a fixed value in your Person.cpp file, whenever you use first_name[CAPACITY], last_name[CAPACITY], or age[CAPACITY] to assign new values, you are only updating the values at the index equal to CAPACITY unless you update the value of CAPACITY itself. In the code you provided, CAPACITY is equal to 20, so your program attempts to update exclusively index 20 with each method call. This will likely cause issues since the person class only attempts to make its arrays on the runtime stack, with a size of 0 each.
Separately, it seems like you want an array of people, but it appears that you are attempting to use a single person object to store the names and ages of multiple people by making these all arrays. Instead, I would recommend making first_name, last_name, and age not arrays, but rather single variables. Then, you can manipulate an array of type person using your CAPACITY variable. You got pretty close, but you can instead declare it as person myPersonArray[CAPACITY] (no need to mention "class" in front of it -- just be sure that you have #include "Person.h" in your main.cpp file). When you want to update a specific person, you can perform an operation like myPersonArray[updateThisIndexNum].update(newFirstName, newLastName, newAge) or some logical equivalent.
As a final note, I almost always highly recommend against using !infile.eof() to control your while loop when reading any file because eof() only indicates whether you have tried to read past the end of an input file. I would highly recommend checking out this post on Stack Overflow where people far more knowledgeable than I explain exactly why this is usually dangerous and how to avoid it.

How to proper inizialize a pointer to char array?

i need some help for this sorting function. The aim of this function is to create an array of pointer to char to let the user fill it with some words an gets it back sorted with alphabetical order. This is part of the code:
void Sort(bool flag)
{
if(flag == false)
{
//ordina stringhe
int NumString = 0;
cout<<"Number of strings: ";
cin>>NumString; //!!
char *Vector[NumString];
for(int i=0;i<NumString;i++)
{
cout<<"Insert the "<<i<<" element: ";
cin>>Vector[i];
int Val = 0;
char* swap;
for(int i=0;i<NumString;i++)
{
for(int j=0;j<NumString;j++)
{
Val = strcmp(Vector[i],Vector[j]);
if(Val > 0)
{
swap = Vector[i];
Vector[i]=Vector[j];
Vector[j]=swap;
}
}
}
for(int i=0;i<NumString;i++)
{
cout<<Vector[i];
cout<<endl;
}
}
}
And when i try to run it i get this error but i don't understand why.
This is the output of the program:
Number of strings: 3
Insert the 0 element: abc
read from master failed
: Input/output error
RUN FAILED (exit value 1, total time: 7s)
char *Vector[NumString] is defined as an array of char pointers.
More on this:
https://www.codeproject.com/Articles/7042/How-to-interpret-complex-C-C-declarations
Since none of the char* elements are initialized, your program is making an illegal memory access when attempting cin and gets closed/crashes.
To avoid this, you can use std::string instead which takes care of memory allocation for you.
Edit:
If you must use char arrays, you can do the following:
you can pre-allocate the char array lengths like so: char Vector[numString][noteLength]. Then use std::cin >> std::setw(noteLength) >> Vector[i].
You could also dynamically allocate the pointers using your previous definition of char *Vector[NumString] and calling Vector[i] = new char[noteLength]. Don't forget to call delete Vector[i] when you're done!
You'd also have to #include <iomanip> to use std::setw

push object in the heap using pointer to the static container

class Node_Str{
public:
string name;
string value;
string type;
Node_Str(string name,string value,string type){
name=name;
value=value;
type=type;}};
static stack<Node_Str> s;
void find_token(string input){
int cursor=0;
string current="";
while(cursor<input.length()){
char value;
value=input[cursor];
cout<<value<<endl;
if(value=='('||value==')'||value=='+'||value=='-
'||value=='*'||value=='/'){
Node_Str* p=new Node_Str("pare",string(1,value),"Pare");
s.push(*p);
cursor++;
delete p;}
if(value==' '){
cursor++;
}
if(value=='1'||value=='2'||value=='3'||value=='4'){
Node_Str* p=new Node_Str("num",string(1,value),"Number");
s.push(*p);
cursor++;
delete p;}}}
int main(){
while(!s.empty()){
cout<<s.top().value<<" ";
s.pop(); }
return 0; }
The find_token function should separate the input string by white Space and constructing the Node_Str object with the value of that string. Then in the
main function, I would like to print it. The characters are limit. Just '1', '2','3','4','+,'-','*','/'.
Input is 4 + 4 , output should be 4+4. However, there is no output.
The comments already said about memory leak and forgetting to call find.
In addition to that, stack is a container in which to last to be pushed in would be the first to be popped out. In order to output 0 1 2 3, you would need to push in the stack in the sequence of 3 2 1 0.
Just giving a better version.
#include <iostream>
#include <stack>
using std::cout;
using std::stack;
static stack<int> s;
void find()
{
int* p;
for (int i = 3; i >= 0; i--) {
p = new int(i);
s.push(*p);
delete p; // p itself does not have to be returned so it can be safely deleted here
//This can also ne replaced by directly using s.push(i)
}
}
int main() {
find();
while (!s.empty())
{
cout << s.top() << " ";
s.pop();
}
return 0;
}
as suggested by leyanpan, data should be pushed into reverse order, to get the desired output. One more point is no need of dynamic allocation for int type. It is always better to store non array built in types in stack rather than heap.
Also allocating stack data structure as static variable will extend scope up to program termination. Better to use stack object as a local variable in main and pass it as are reference argument to function find.

Adding element to array of struct c++

Can someone explain why this code does not work? It keeps crashing when it asks for input in addCar().
I think something is wrong with copying an array, but I can't figure out what exactly. I also tried to use copy() but it didn't work either.
#include <iostream>
#include <string>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct Car{
string Brand;
string model;
long mileage;
};
void addCar(int *ptr, struct Car *arra){
*ptr=*ptr+1;
Car *newArr = new Car[*ptr];
memcpy(newArr, arra, (*ptr)*sizeof(Car));
cout<<"Brand ";
getline(cin,newArr[*ptr].Brand);
cout<<"Model ";
getline(cin, newArr[*ptr].model);
cout<<"mileage ";
cin>>newArr[*ptr].mileage;
arra=newArr;
};
int main(int argc, char** argv) {
int size=1;
int *ptr_size;
ptr_size=&size;
Car *tab=new Car[*ptr_size];
tab[0].Brand = "Audi";
tab[0].model = "A8";
tab[0].mileage = 14366;
addCar(*ptr_size, tab);
return 0;
}
The fail is probably here:
getline(cin,newArr[*ptr].Brand);
A bit above, you did this: *ptr=*ptr+1; and made newArr an array of *ptr elements. Arrays are origin zero. That means the first item in the array is newArr[0]. The last will be at newArr[*ptr-1], so writing into newArr[*ptr] is writing over someone else's memory. Generally a bad thing to do.
But this is also not cool:
*ptr=*ptr+1;
Car *newArr = new Car[size+1];
memcpy(newArr, arra, (*ptr)*sizeof(Car));
You increment the size of the array. That's OK.
You create a new array with the new size. That's OK.
You copy new size number of elements from the old array to the new array and over shoot the end of the old array. Not OK.
The best answer is given by Jerry Coffin and Paul McKenzie in the comments: use a std::vector. If this is not allowed... Ick.
But alrighty then.
First, memcpy literally copies a block of memory. It does not know or care what that block of memory is or what it contains. Never use memcpy unless you are copying something really, really simple like basic data type or a structure made up of nothing but basic data types. String is not basic. The data represented by a string might not be inside the string. In that case, you copy a pointer to the string and that pointer will not be valid after the death of the string. That's not a problem in your case because you don't kill the string. That leads to problem 2. Let's fix that before you get there. The easiest way (other than vector) is going to be:
for (int index = 0; index < *ptr-1; index++)
{
newArr[index] = arra[index];
}
An optimization note. You don't want to resize and copy the array every time you add to it. Consider having two integers, one size of array and the other index into array and double the size of the array every time the index is about to catch up with the size.
When you allocate any memory for data with new somebody has to clean up and put that memory back with delete. In C++ that somebody is you. so, before you arra=newArr; you need to delete[] arra;
Passing in the array index as a pointer overcomplicates. Use a reference or just pass by value and return the new index. Also, don't name a variable ptr. Use something descriptive.
void addCar(int &arrasize, struct Car *arra){
or
int addCar(int arrasize, struct Car *arra){
Next problem: int addCar(int arrasize, struct Car *arra){ passes in a pointer to arra. But you passed the pointer by value, made a copy of the pointer, so when you change the pointer inside the function, it's only the copy that got changed and the new array is not going to come back out again. So,
int addCar(int arrasize, struct Car * & arra){
Passes in a reference to the pointer and allows you to modify the pointer inside the function.
Putting all that together:
int addCar(int size, struct Car * & arra)
{
Car *newArr = new Car[size + 1];
for (int index = 0; index < size; index++)
{
newArr[index] = arra[index];
}
cout << "Brand ";
getline(cin, newArr[size].Brand);
cout << "Model ";
getline(cin, newArr[size].model);
cout << "mileage ";
cin >> newArr[size].mileage;
delete[] arra;
arra = newArr;
return size+1;
}
int main()
{
int size=1;
Car *tab=new Car[size];
tab[0].Brand = "Audi";
tab[0].model = "A8";
tab[0].mileage = 14366;
size = addCar(size, tab);
// do more stuff;
// bit of test code here
for (int index = 0; index < size; index++)
{
cout << "Car " << index << " brand =" <<tab[index].Brand << " Model=" << tab[index].model << " mileage=" <<tab[index].mileage << endl;
}
delete[] tab;
return 0;
}
When you are copying the old array to the new one you are accessing invalid memory, remember that, in that point, arra has size *ptr-1 not *ptr, so the line should be
memcpy(newArr, arra, (*ptr-1)*sizeof(Car));
also in the other lines you should insert the new value in the *ptr-1 position because the indexes in newArr go from 0 to size-1 ie *ptr-1:
cout<<"Brand ";
getline(cin,newArr[*ptr-1].Brand);
cout<<"Model ";
getline(cin, newArr[*ptr-1].model);
cout<<"mileage ";
cin>>newArr[*ptr-1].mileage;