Im having trouble with the syntax here. We are studying structures and pointers in class currently and are tasked with creating a dynamic array of a single structure with a pointer array inside to both be allocated and deleted by the end of the program. (Hopefully that made sense)
Here are the snippits of code im working with, note how the entry of scores works:
std::cin << stuArray[i].stuScore[j]
But then the deletion in a similar manner, does not:
delete[] stuArray[count].stuScore[j];
Deletion Code:
do
{
for (unsigned short j = 0; j < numTests; j++)
{
delete[] stuArray[count].stuScore[0]; //Syntax???????
}
count++;
} while (count < numStudents);
delete[] stuArray;
Score Entry Code (Which Works)
bool ScoreEntry(Student * stuArray, unsigned short numStudents, unsigned short numTests)
{
//Local Variables
unsigned short idTempChoice = 0;
//Get Id Number
std::cout << "\nChoose a student by ID and enter the test scores: ";
std::cin >> idTempChoice;
//Id lookup
for (unsigned short i = 0; i < numStudents; i++)
{
//Id Check
if (idTempChoice == stuArray[i].stuId)
{
std::cout << "Student selected: " << stuArray[i].stuName << std::endl;
//Score Entry
for (unsigned short j = 0; j < numTests; j++)
{
std::cout << "Test " << j + 1 << "'s Score: ";
std::cin >> stuArray[i].stuScore[j];
}//End For Loop j
return true;
}
}//End For Loop i
//Student Id not found
std::cout << "Student not found!\n";
return false;
}
Allocation Code (Struct):
void MemAllocation(Student * &stuArray, unsigned short &numStudents)
{
//Get Number of students
std::cout << "How many students have taken the test: ";
std::cin >> numStudents;
std::cout << std::endl;
//Dynamically allocate pointers
stuArray = new Student[numStudents];
}
Allocation Code (Pointer inside struct):
for (unsigned short i = 0; i < numTests; i++) //Allocate Dynamic array for each student
{
stuArray[i].stuScore = new float[numTests];
}
This is Literally all the code you need reference, this is not a bug its a syntax problem :)
Try delete[] stuArray[count].stuScore;
not delete[] stuArray[count].stuScore[j];
delete [] is made to delete an array allocated with new type[n]
You want to delete the pointer to the memory, not the actual memory.
You can delete delete[] stuArray[count].stuScore but not delete[] stuArray[count].stuScore[j] - drescherjm
Fixed using:
do
{
delete[] stuArray[count].stuScore;
count++;
} while (count < numTests);
Related
So it's a simple c++ program which takes 2 sorted arrays from user dynamically using new operator and sum ups their size to create a third array which is equal to the length of the both array sum..
Like final_arr = arr1_size +arr2_size;
Everything is working fine but the problem is that is that I am taking array values from user so I need to check up that array entered by user is sorted or not, if array is not sorted then program must take that array values from user until he entered in correct order. I am using label with goto statement for checking the array, if some element smaller than previous element is found, then we will go at the top of the for loop through goto statement..as shown in code below.
//receiving array 1 input from user dynamically...
cout << "How many numbers you want to enter for array 1" << endl;
cin >> arr1_size;
arr1 = new int [arr1_size]; //creating array dynamically
arr1_label: //goto label
cout << "Enter numbers " << endl; //just to display
for (int i = 0; i < arr1_size; i++) { //loop for taking value from the user for arr1
cin >> arr1[0];
}
for (int i = 1; i < arr1_size; ) {//loop for checking for unordered array, if detects restart the input for loop
if (arr1[i--] > arr1[i]) {
cout << "Array 1 is not sorted" << endl;
goto arr1_label;
break;
}
i++;
}
It's a task in which I can't use vector ... I only have to use arrays dynamically.....Complete code of project is given below..
int main()
{
int arr1_size, arr2_size, final_arr_size;
int* arr1; int* arr2; int* final_array;
//receiving array 1 input from user dynamically...
cout << "How many numbers you want to enter for array 1" << endl;
cin >> arr1_size;
arr1 = new int [arr1_size]; //creating array dynamically
arr1_label: //goto label
cout << "Enter numbers " << endl; //just to display
for (int i = 0; i < arr1_size; i++) { //loop for taking value from the user for arr1
cin >> arr1[0];
}
for (int i = 1; i < arr1_size; ) {//loop for checking for unordered array, if detects restart the input for loop
if (arr1[i--] > arr1[i]) {
cout << "Array 1 is not sorted" << endl;
goto arr1_label;
break;
}
i++;
}
//receiving array 2 input from user dynamically...
cout << "How many numbers you want to enter for array 2" << endl;
cin >> arr2_size;
arr2 = new int[arr2_size];
cout << "Enter numbers " << endl;
for (int i = 0; i < arr2_size; i++) {
cin >> arr2[i];
}
//Merged array code here...
final_arr_size = arr1_size + arr2_size;
final_array = new int[final_arr_size];
int i = 0, j = 0, k = 0;
while (i < arr1_size && j < arr2_size) {
if (arr1[i] < arr2[j]) {
final_array[k++] = arr1[i++];
}
else {
final_array[k++] = arr2[j++];
}
}
while (i < arr1_size) {
final_array[k++] = arr1[i++];
}
while (j < arr2_size) {
final_array[k++] = arr2[j++];
}
//displaying final array
for (int i = 0; i < final_arr_size; i++) {
cout << final_array[i] << " ";
}
//deleting dynamically allocated memory.
delete[] arr1;
delete[] arr2;
delete[] final_array;
return 0;
}
#include <algorithm>
// ...
// check if arr1 is sorted
bool input_is_sorted = std::is_sorted(arr1, arr1 + arr1_size);
See https://en.cppreference.com/w/cpp/algorithm/is_sorted
Of course you would better replace bare pointers with std::vector etc.
Getting 0xC0000005: Access violation writing location 0xCDCDCDCD with the code below.
I know I must have not allocated the pointer properly, but I'm not sure where.
I'm trying to have **scoreSet refer to sets of *scores and *scores is to be entered in manually. The names pointer to array is working fine and seems to be allocated properly. The problem is when I try to mimic the same for scoreSet, with the difference being scoreSet is a pointer to an array of pointers scores. I feel like the way I'm trying to dynamically allocate the arrays that this pointer is pointing to is completely wrong.
Basically trying to get something like this to be possible after user input:
scoreSet0 = {22,33,44}
scoreSet1 = {35, 45, 65, 75}
scoreSet3 = {10}
#include <iostream>
#include <string>
using namespace std;
int inputData(string*& names, double**& scores);
int main() {
string *names = nullptr;
double *scores = nullptr;
double **scoreSet = &scores;
int size = 0;
size = inputData(names, scoreSet);
for (int i = 0; i < size; i++) {
cout << *(names+i) << endl;
}
}
int inputData(string*& names, double**& scoreSet) {
int numStudents = 0;
cout << "How many students do you have in the system? ";
cin >> numStudents;
while (numStudents <= 0) {
cout << "Invalid number of students. Please enter number of students: ";
cin >> numStudents;
}
names = new string[numStudents];
cin.ignore(10000, '\n');
for (int i = 0; i < numStudents; i++) {
int numTests = 0;
cout << "Enter the student's name: ";
getline(cin,names[i]);
cout << "Enter how many tests " << *(names + i) << " took: ";
cin >> numTests;
*(scoreSet + i)= new double[numTests]; //Pretty sure this is wrong.
cin.ignore(10000, '\n');
for (int j = 0; j < numTests; j++) { //This loop is causing the error.
cout << "Enter grade #" << j + 1 << ": ";
cin >> *(scoreSet+i)[j];
}
}
return numStudents;
}
Per PaulMcKenzie suggestion, this is how it would roll. It may be a bit much for you to use templates, but if you can... Otherwise create the name and score containers separately. But then you have duplicate code to maintain.
The idea is to keep all your stuff in some kind of order. Note that now the memory management is taken care of in the container.
I dropped handling std::cin and the scores, but it should be much easier for you to code that stuff back without a lot of fluff in the way. At that, develop without std::cin, it is a waste of time. You should write so you can just edit and run.
Also, get out of the habit of using namespace std; It will pay off in the long run.
#define DEV
template<typename T>
struct container {
size_t size;
T* ar;
container(size_t size) :size(size) {
ar = new T[size];
}
~container() { delete[]ar; }
T& operator [](size_t pos) { return ar[pos]; }
};
using names_c = container<std::string>;
using scores_c = container<double>;
size_t inputData(names_c& names, scores_c& scores);
int main() {
container<std::string> names(2);
container<double> scoreSet(2);
auto size = inputData(names, scoreSet);
for (int i = 0; i < size; i++) {
std::cout << names[i] << endl;
}
}
size_t inputData(names_c& names, scores_c& scores) {
#ifdef DEV
size_t numStudents = 2;
names[0] = "tom";
names[1] = "mary";
#else
//do your std::cin stuff
#endif
return names.size;
}
I wasn't going to go there, but. You can extend the concept so that you have containers in containers. Much easier to know what scores go with what student.
struct student_type {
using scores_c = container<double>;
std::string name;
scores_c scores;
};
using student_c = container<student_type>;
I've taken your code, and modified it to work. I've removed your comments, and placed comments in on the lines that I changed.
#include <iostream>
#include <string>
using namespace std;
int inputData( string *&names, double **&scores );
int main() {
string *names = nullptr;
double **scores = nullptr; // Changed to double ** so it's "2D"
// double **scoreSet = &score; // removed, this was unneeded and probably causing problems
int size = 0;
size = inputData( names, scores );
for ( int i = 0; i < size; i++ ) {
cout << *( names + i ) << endl;
}
}
int inputData( string *&names, double **&scoreSet ) {
int numStudents = 0;
cout << "How many students do you have in the system? ";
cin >> numStudents;
while ( numStudents <= 0 ) {
cout << "Invalid number of students. Please enter number of students: ";
cin >> numStudents;
}
names = new string[numStudents];
scoreSet = new double*[numStudents]; // allocate an array of pointers
// cin.ignore( 10000, '\n' ); // Removed from here, placed inside loop
for ( int i = 0; i < numStudents; i++ ) {
cin.ignore( 10000, '\n' ); // placed here so that it always clears before getting the name
int numTests = 0;
cout << "Enter the student's name: ";
getline( cin, names[i] );
cout << "Enter how many tests " << names[i] << " took: "; // simplified
cin >> numTests;
scoreSet[i] = new double[numTests]; // simpliefied left hand side
//cin.ignore( 10000, '\n' ); // not needed
for ( int j = 0; j < numTests; j++ ) {
cout << "Enter grade #" << j + 1 << ": ";
cin >> scoreSet[i][j]; // simplified
}
}
return numStudents;
}
The strange problem appears in my program. It is working, but in debugging it shows the "Exception thrown" in random places at the outputting
cout<<"Average value:"<<u3.apr();
_getch();
Sometimes, it even throws this error after the main function (Behind the {})
It is quite annoying because the program just closes after 3 seconds because of these errors.
(Maybe that's because of class, but I'm trying to learn it ;) )
Have tried already changing lines order, rewriting class name and array name.
#include <iostream>
#include <conio.h>
using namespace std;
class vid
{
private:
int i, j;
double rez, sum=0;
public:
int size;
double *arr = new double[size];
double apr()
{
for (i = 0; i < size; i++)
{
sum += (*(arr + i));
}
return sum / size;
}
};
int main()
{
vid u3;
cout << "Enter array length:";
cin >> u3.size;
for (int i = 0; i < u3.size; i++)
{
cout << "Enter array's " << i << " element:" << endl;
cin >> *(u3.arr+i);
}
cout << "Your array:" << endl;
for (int i = 0; i < u3.size; i++)
{
cout << *(u3.arr + i) << "\t";
}
cout << endl;
cout<<"Average value:"<<u3.apr();
_getch();
}
Thanks for any help ;)
arr is initialised when u3 is constructed.
But you didn't populate u3.size until later.
So, your array has indeterminate length (which is already UB), and your accesses later may be invalid.
You're going to have to manage your class's member a bit more cleverly!
Such classes generally have a "resize" function that performs the allocation per the requested size. Don't forget to safely kill any prior allocation, transplanting data if necessary. You can find online plenty of examples of a vector implementation.
Certainly renaming classes and randomly re-ordering the lines of your program's source code is not going to solve anything.
u3.size is not set until after u3 is constructed. By setting u3.size you can avoid this compiler-time error.
It seems that as an alternative solution, you might want to consider how to get rid of the new call and the need to write a destructor that will delete arr.
By creating a constructor that takes a size parameter AND by switching arr to a std::vector, you can allow the class to hold the vector and handle memory allocation and deallocation:
#include <iostream>
#include <vector>
using namespace std;
class vid
{
private:
int i, j;
double rez, sum=0;
public:
int size;
std::vector<double> arr;
// constructor requires size to be passed in;
// constructor initializes the arr array with the passed in size to zeroes.
vid(int argSize) : size(argSize), arr(argSize, 0.0){ }
double apr()
{
for (i = 0; i < size; i++)
{
sum += arr[i];
}
return sum / size;
}
};
int main()
{
uint size;
cout << "Enter array length:";
cin >> size;
vid u3(size);
for (int i = 0; i < u3.size; i++)
{
cout << "Enter array's #" << i << " element:" << endl;
cin >> u3.arr[i];
}
cout << "Your array:" << endl;
for (int i = 0; i < u3.size; i++)
{
cout << u3.arr[i] << "\t";
}
cout << endl;
cout<<"Average value:"<<u3.apr();
char ch;
cin >> ch;
}
Firstly, I want to say that I'm a beginner. Sorry for my stupid questions.
My program should ask for the amount of words you want to put in. It's specifically said that this tab length is the length of pointers tab pointing to the words tab (may sound confusing, but English isn't my first language, my apologies, I also dont really understand pointers yet).
The words tab should also have exact length for each word, hence the strlen. What am I doing wrong?
int il,len;
string x;
cout<<"Amount of words: ";
cin>>il;
int **t;
t=new int*[il];
for(int i=0; i<il; i++)
{
cout<<"Word: ";
cin>>x;
len=strlen(x);
t[i]=new string[len];
cout<<endl;
}
cout<<"You wrote:"<<endl;
for(int i=0; i<il; i++)
{
cout<<t[i];
delete [] t[i];
}
delete[] t;
strlen() doesn't take a class string object but instead it takes a pointer to character string char*:
len = strlen(x); // error so correct it to:
len = x.length();
also you cannot initialize a pointer to an integers to class string:
int **t;
t[i]=new string[len];
you really want an array of strings but the code is really a mess so if you want this how:
int il;
cout << "Amount of words: ";
cin >> il;
string *t;
t = new string[il];
for(int i = 0; i < il; i++)
{
cout << "Word: ";
cin >> t[i]; // there's no need for a temporary string `x`; you can directly input the elements inside the loop
cout << endl;
}
cout << "You wrote: " << endl;
for( int i = 0; i < il; i++)
cout << t[i] << endl;
delete[] t;
Hey so I want to create n arrays (based off user input) of size x (also off user input). The way I was thinking of doing it was having a for loop perform n iterations and inside the loop ask the user for x. The problem is I'm not sure how to name the array using the variable n, I was thinking something like:
cout << "Enter n: ";
cin >> n
for (i = 0; i < n; i++)
{
cout << "Enter x: ";
cin >> x;
double*array+i;
array+i = new double[x]
}
To sum up my question is: can you create/name an array using a variable in C++?
Unfortunately, you can't do this in C++. Try something like this...
std::cout << "Enter n: ";
std::cin >> n
std::vector<std::vector<double> > arrays(n);
for (std::size_t i = 0; i < n; i++)
{
std::cout << "Enter x: ";
std::cin >> x;
arrays[i].reserve(x);
}
reserve only allocates, but does not construct the objects in the std::vector; if you want to construct them too, use resize.
PS Never use using namespace std; it makes your code harder to read and debug.
Since you are programming in C++, you should use STL containers (especially std::vector) instead of C-style arrays.
If you need to access an array by using the string that has been created in runtime, then you could use std::map< std::string, std::vector<double> >, which is pretty crazy idea though:
typedef std::vector<double> MyVector;
std::map<std::string, MyVector> myVectors;
// create an array:
std::string arrayName;
arrayName = std::string("someArray"); // could be: std::cin >> arrayName;
myVectors[arrayName] = MyVector(10, 1.23); // new vector of size 10
std::cout << myVectors["someArray"][4]; // prints 1.23
I'm not sure what exactly is what you are trying to achieve, but there are most likely more appropriate solutions. Is it really necessary to access these arrays via their names? I'm pretty sure that common std::vector< std::vector<double> > would suffice here.
Here's 3 solutions: the first is closest to your example code, the second is an improvement in order to be able to correctly retrieve the array elements within bounds, and the third is the reason why you are better served with vectors.
Solution 1:
It looks like you want your arrays to have names that are distinguishable by your loop iterator. Like Joe said, you could have an array of an array, so the inner arrays will be named array[0], array[1], ..., array[n - 1]. This will be achieved by using a pointer to pointer to double. Each of the inner pointers will be used to dynamically allocate arrays of double. Don't forget to delete the dynamically allocated memory.
#include <iostream>
int main()
{
unsigned int n;
std::cout << "Enter number of arrays: ";
std::cin >> n;
double** array = new double*[n];
for (int i = 0; i < n; ++i)
{
unsigned int size;
std::cout << "Enter size of array " << i << ": ";
std::cin >> size;
array[i] = new double[size];
for (int j = 0; j < size; ++j)
{
int element;
std::cout << "Enter element " << j << " of array " << i << ": ";
std::cin >> element;
array[i][j] = element;
}
}
for (int i = 0; i < n; ++i)
{
delete [] array[i];
}
delete[] array;
return 0;
}
Solution 2:
However, with the above code, you will have trouble accessing the elements of each inner array. Unless you memorized the size of each inner array you create with this, you might access something out of bounds. Therefore, an update to this code would be to add yet another array, let's call it sizeOfInnerArrays, where each of its element i keeps track of the size of inner array array[i]. Here's the update:
#include <iostream>
int main()
{
unsigned int n;
std::cout << "Enter number of arrays: ";
std::cin >> n;
double** array = new double*[n];
unsigned int* sizeOfInnerArrays = new unsigned int[n];
for (int i = 0; i < n; ++i)
{
std::cout << "Enter size of array " << i << ": ";
std::cin >> sizeOfInnerArrays[i];
array[i] = new double[sizeOfInnerArrays[i]];
for (int j = 0; j < sizeOfInnerArrays[i]; ++j)
{
int element;
std::cout << "Enter element " << j << " of array " << i << ": ";
std::cin >> element;
array[i][j] = element;
}
}
//prints out each array as curly-brace enclosed sets of doubles
for (int i = 0; i < n; ++i)
{
std::cout << "{";
for (int j = 0; j < sizeOfInnerArrays[i] - 1; ++j)
{
std::cout << array[i][j] << ", ";
}
std::cout << array[i][sizeOfInnerArrays[i] - 1] << "}" << std::endl;
}
// free dynamically allocated memory
for (int i = 0; i < n; ++i)
{
delete [] array[i];
}
delete[] array;
delete[] sizeOfInnerArrays;
return 0;
}
Solution 3:
However, that is too complicated, so you are better off using a container, like vector, as Joe suggested, whose data member keeps track of its size.
#include <iostream>
#include <vector>
int main()
{
unsigned int n;
std::cout << "Enter number of vectors: ";
std::cin >> n;
std::vector<std::vector<double> > myVec;
// ^ space between closing angle brackets not needed
// if using C++11 conforming compiler
for (int i = 0; i < n; ++i)
{
unsigned int size;
std::cout << "Enter size of vector " << i << ": ";
std::cin >> size;
std::vector<double> temp;
temp.reserve(size);
for (int j = 0; j < size; ++j)
{
double value;
std::cout << "Enter next value of vector " << i << ": ";
std::cin >> value;
temp.push_back(value);
}
myVec.push_back(temp);
}
for (int i = 0; i < myVec.size(); ++i)
{
std::cout << "{";
for (int j = 0; j < myVec.at(i).size() - 1; ++j)
{
std::cout << myVec.at(i).at(j) << ", ";
}
std::cout << myVec.at(i).back() << "}" << std::endl;
}
return 0;
}