Making a pointer to an array of structures - c++

Having difficulty solving the below challenge.
My attempt is the code below the struct. I'm not quite clear as to how I would save the individual entries to the array as when I attempt to use a bracket to index each entry into the loop i'm met with an error.
Is there something I'm missing or overthinking?
Use the Time structure to define and dynamically allocate memory for an array of 10 times. After that return the allocated memory back to the operating system
struct Time {
int hrs;
int min;
int sec;
};
Time *t2 = new Time[10];
for(int i = 0; i < 10; i++){
cout << "Enter time in format HHMMSS "<< i + 1 << ": ";
cin >> t2->hrs>>t2->min>>t2->sec;
}
cout << setw(8) << "INDEX" << setw(10) << "Time" << endl;
for(int i = 0; i < 10; i++){
cout << setw(8) << i << setw(10) << t2->hrs <<":"<< t2->min<<":"<<t2->sec<< endl;
}
delete[] t2;

Related

C++ POINTERS (student * [n] gives the error that array type is not assignable)

#include <iostream>
#include "student.h"
using namespace std;
int main()
{
// inputting the number of students
int n;
cout << "How many students would you like to process?" << endl;
cin >> n;
student* s[n];
string tmp;
double t;
// entering each student details
for (int i = 0; i < n; i++)
{
// dynamically allocating object
s[i] = new student();
cout << "Enter first name for student " << (i + 1) << endl;
cin >> tmp;
s[i]->setFirstName(tmp);
cout << "Enter middle name for student " << (i + 1) << endl;
cin >> tmp;
s[i]->setMiddleName(tmp);
cout << "Enter last name for student " << (i + 1) << endl;
cin >> tmp;
s[i]->setLastName(tmp);
cout << "Enter GPA for student " << (i + 1) << endl;
cin >> t;
s[i]->setGPA(t);
}
double avgGPA = 0;
// printing the student details
cout << "Students:" << endl;
cout << "---------" << endl
<< endl;
for (int i = 0; i < n; i++)
{
cout << s[i]->getFirstName() << " " << s[i]->getMiddleName() << " " << s[i]->getLastName() << " " << s[i]->getGPA() << endl;
avgGPA += s[i]->getGPA();
}
avgGPA /= n;
// printing the average GPA
cout << endl
<< "Average GPA: " << avgGPA;
// freeing the memory allocated to objects
for (int i = 0; i < n; i++)
delete s[i];
return 0;
}
Under the main function student * s [n]; says the array type is not assignable to the line.It also gives an error that the expression must contain a literal. I thought I was doing everything right, but there was an error. What is the solution to this error can anyone help?
student* s[n]; is a Variable-Length Array (VLA), which is not in the standard C++.
You should use std::vector like std::vector<student*> s(n);.
Also add #include <vector> at the beginning of your code to use that.

I have a question about dynamic allocation of memory in c++

I'm new to c++ and I can't understand something in dynamic allocation.
why does the following program build but gives an error and stops?
#include <iostream>
using namespace std;
int main()
{
int amount;
int *p = new int[amount];
cout << "enter the size of array" << endl;
cin >> amount;
for(int i = 0; i < amount ; i++)
{
cout << "enter the " << i + 1 << " number" << endl;
cin >> p[i];
}
for(int i = 0; i < amount ; i++)
{
cout << "number " << i + 1 << " is : " << p[i] << endl;
}
delete []p;
}
You are trying to use amount before you have assigned any value to it. You need to read the user's input for amount first, THEN allocate using it. Not the other way around.
#include <iostream>
using namespace std;
int main()
{
int amount;
cout << "enter the size of array" << endl;
cin >> amount;
int *p = new int[amount];
for(int i = 0; i < amount ; i++) {
cout << "enter the " << i + 1 << " number" << endl;
cin >> p[i];
}
for(int i = 0; i < amount ; i++) {
cout << "number " << i + 1 << " is : " << p[i] << endl;
}
delete[] p;
}

C++ array structures

I was reading the chapter on structures in my book, and it got me re-modifying a program I already made, but this time using structures which I have never used before; however, after finishing the program, there's one issue I'm not understanding. The output of the program only displays once. It's in a for loop, and yet even though it asks me to input my information three times, it only outputs the first information.
I'm probably just not understanding how arrays in structures work.
An example of my issue is the following.
I have my output on the following loop
for(int counter = 0; counter <size; counter++)
The size is 3, which would mean I'll get the output printed three times; however the answer I'm getting is the same as if I was asking for the following.
Listofnames[0].F_name
When what I actually want is
Listofnames[0].F_name Listofnames[1].F_name Listofnames[2].F_name
However, I don't want to have to write it three times, I did to test it and it actually worked, but is that the only way to do it? Or did I miss something in my program?
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
struct Names
{
string F_name; //Creating structure called Names.
string L_name;
char Mi;
};
struct Payrate
{
double rate;
double hoursworked; //Creating structure called Payrate.
double gross;
double net;
};
int main()
{
double stateTax = 0, federalTax = 0, unionFees = 0, timeHalf = 1.5; //Initializing variables.
const int size = 2; //Array size.
Payrate employee[size]; //Structure variables
Names Listofnames[size];
for (int counter = 0; counter < size; counter++) //Initializing for loop.
{
cout << "What's your first name?: " << endl;
cin >> Listofnames[counter].F_name;
cout << "What's your last name?: " << endl; //Displaying names, and hours worked, rate.
cin >> Listofnames[counter].L_name;
cout << "What is your middle initial?: " << endl;
cin >> Listofnames[counter].Mi;
cout << "How many hours did you work? Please enter a number between 1-50: " << endl;
cin >> employee[counter].hoursworked;
cout << "What is your hourly rate? Please enter a number between 1-50: " << endl;
cin >> employee[counter].rate;
if (employee[counter].hoursworked < 0 || employee[counter].hoursworked >50) //Initializing conditional statements.
{
cout << "Sorry you entered a erong entry. Pc shutting off " << endl; //Displays what happens is user inputs a number under 0 or over 50.
}
if (employee[counter].rate < 0 || employee[counter].rate > 50) //Initializing conditional statements.
{
cout << "Sorry you entered a erong entry. Pc shutting off " << endl; //Displays what happens is user inputs a number under 0 or over 50.
}
if (employee[counter].hoursworked <= 40) //Initializing conditional statements.
{
employee[counter].gross = employee[counter].hoursworked * employee[counter].rate; //Calculating gross.
}
else if (employee[counter].hoursworked > 40) //Initializing conditional statements.
{
employee[counter].gross = employee[counter].hoursworked * (employee[counter].rate * timeHalf); //Calculating gross.
}
stateTax = employee[counter].gross * 0.06;
federalTax = employee[counter].gross * 0.12; //Calculates all the tax fees, and net.
unionFees = employee[counter].gross * 0.02;
employee[counter].net = employee[counter].gross - (stateTax + federalTax + unionFees);
}
cout << "FirstN " << "MI " << "LastName " << "\t" << "Rate " << "HoursWorked " << "TimeHalf " << "StateTax " << "FederalTax " << "UnionFees " << "Gross " << " " << "Net " << endl; //Displays header of output.
cout << "==================================================================================================================" << endl;
for (int counter = 0; counter <= size; counter++)
{
//Output.
cout << Listofnames[counter].F_name << "\t" << fixed << setprecision(2) << Listofnames[counter].Mi << " " << Listofnames[counter].L_name << "\t" << employee[counter].rate << "\t" << employee[counter].hoursworked << "\t" << setw(7) << timeHalf << "\t" << setw(8) << stateTax << setw(12) << federalTax << "\t" << unionFees << "\t" << employee[counter].gross << "\t" << employee[counter].net << endl;
system("pause");
}
}
P.s If you had to re modify this program again, what would you use to simplify it. Asking so I can keep re-modifying, and learn more advanced stuff. Vectors, pointers? Thanks in advance.
You have an array with 3 indexes but your loop is only going upto 2 indexes. Change your for loop to this.
for (int counter = 0; counter <= size; counter++)
Now, this loop will print the all the indexes.
Instead of using a static value you can also use this.
for (int counter = 0; counter < sizeof(Listofnames)/sizeof(Listofnames[0]); counter++)
sizeof(Listofnames)/sizeof(Listofnames[0]) This will give you the total size of your array.
Ideone Link

Not outputting the calculation, just 0

I have my code here and it runs, however, when I try to output the percentage it just outputs 0, I've spent a long time trying to figure out what I'm missing and I'm clueless. Basically I'm trying to output the percent of votes for each candidate out of total votes. Any help would be appreciated. Here is my output;
Output display Also, im aware that the winner loops through every user until it reaches the end for some reason, still trying to work out the kinks.
Here is my code -
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
class candidatesElection
{
public:
string last;
float votePercent;
void winnerOfElection();
void outputDis();
int total = 0;
};
int main()
{
string lastName[5];
int amountOfVotes[5];
double percentTotal[5];
int total = 0;
int winnerNo = 0;
int winningCandidate;
string winningName;
for (int i = 0; i < 5; i++)
{
cout << "Enter the last name of the Candidate: " << endl;
cin >> lastName[i];
cout << endl;
cout << "Enter the votes received by the Candidate: " << endl;
cin >> amountOfVotes[i];
total += amountOfVotes[i];
cout << "Total number of votes is: " << total << endl;
}
for (int i = 0; i < 5; i++)
{
if (amountOfVotes[i] > amountOfVotes[winnerNo]) winnerNo = i;
amountOfVotes[i] = amountOfVotes[winnerNo];
}
for (int i = 0; i < 5; i++)
{
percentTotal[i] = (amountOfVotes[i] / total) * 100.0; // need to make it floating point
}
void outputDis();
{
cout << endl << left << setw(25) << "Candidate" << right << setw(25) << "Votes Received" << setw(25) << "% of Total Votes" << endl;
for (int i = 0; i < 5; i++)
cout << endl << left << setw(25) << lastName[i] << right << setw(25) << amountOfVotes[i] << setw(25) << percentTotal[i] << endl;
cout << endl << left << setw(25) << "Total" << right << setw(25) << total << endl;
for (int i = 1; i < 5; i++)
{
int winHigh = amountOfVotes[0];
string win = lastName[0];
if (amountOfVotes[i] > winHigh)
{
winHigh = amountOfVotes[i];
win = lastName[i];
}
cout << "The Winner of the Election is " << win << endl;
}
}
system("pause");
};
The coefficient amountOfVotes[i] / total in (amountOfVotes[i] / total) * 100.0 is evalated in integer arithmetic: i.e. any fraction is discarded.
So you end up with 0 * 100 for all cases where amountOfVotes[i] is less than total.
The solution is to rearrange the formula to 100 * amountOfVotes[i] / total;, or, even better 100.0 * amountOfVotes[i] / total; which will force evaluation in double precision floating point - you are in danger of overflowing an int which, on some systems, can have an upper limit as low as 32767.
That's not immediately obvious even when using a line-by-line debugger. But do use that debugger to work out the other "kinks".

Creating and clearing an array of structures

I've been trying to write a short program allowing the user to add entries to a "database", listing the entries they have put in, and the ability to clear all the entries without ending the program. Here's what i've got
#include <cstdlib>
#include <iostream>
#include <string>
using namespace std;
struct BIRTH
{int month; int year;};
struct ID
{string name; bool vip; float score;
struct BIRTH date;} ;
int main(int argc, char** argv) {
ID **ptrarr;
ptrarr = new ID * [10];
for (int r=0; r<10; r++)
{ptrarr[r] = new ID[1] ;}
int counter = 0;
while(counter<100){
cout << "Type add to create a new entry" << endl;
cout << "Type list to see all entries" << endl;
cout << "Type clear to delete all entries" << endl;
cout << "Type exit to terminate" << endl;
string command = "0";
getline (cin,command);
if(command=="add")
{
cout << "Enter name" << endl;
getline (cin,ptrarr[counter][1].name);
cout << "VIP? 1 for yes, 0 for no" << endl;
cin >> ptrarr[counter][1].vip;
cout << "Enter score" << endl;
cin >> ptrarr[counter][1].score;
cout << "Month of birth" << endl;
cin >> ptrarr[counter][1].date.month;
cout << "Year of birth" << endl;
cin >> ptrarr[counter][1].date.year;
counter++;
}
else if(command=="list")
{
for (int i=0; i<counter; i++)
{int n=i+1;
cout << n << " "
<< ptrarr[i][1].name << " ";
if (ptrarr[i][1].vip)
{cout << "VIP ";}
cout << "Score: " << ptrarr[i][1].score << " "
<< "Born: " << ptrarr[i][1].date.month << "/" << ptrarr[i][1].date.year << endl;
}
}
else if(command=="clear")
{delete[] ptrarr;
cout << "Entries cleared" << endl;}
else if(command=="exit")
{return 0;}
else
cout << "try again" << endl;
}
return 0;
}
Now here's the deal: the following code successfully compiles, but when I type in the "add" command, the program crashes (achievement unlocked, didn't think it's possible to obtain with such a short code). The most important thing is that the array is made of a multitype structure and that the "clear" command wipes out all the entries in the array.
NOTE: I understand that there are thousand better ways to write this piece of code, but I'm writing it to practice the things I have covered so far regarding C++. So unless it is absolutely necessary for the code to run, please do not introduce any new gimmicks =)
Replace all ptrarr[counter][1] with ptrarr[counter][0] fixes the problem.
Further advices:
I. This code has redundancy:
ID **ptrarr;
ptrarr = new ID * [10];
for (int r=0; r<10; r++)
{ptrarr[r] = new ID[1] ;}
Replace it with:
ID *ptrarr;
ptrarr = new ID [10];
Then you do not need extra [0] at the end of each ptrarr[counter]
II. functions make your code more readable:
if(command=="add")
add();
else if(command=="list")
list();
else if(command=="clear")
clear();
else if(command=="exit")
return 0;
else
cout << "try again" << endl;
Then decisions are made in a smaller area (Good practice for large programs.)
III. There is another mistake in your code:
else if(command=="clear")
{delete[] ptrarr;
cout << "Entries cleared" << endl;}
Here you should reset the counter. Also if you regard my point (I) this part is fine. Otherwise, if you use new with a for loop, I am afraid that you need to delete with a for loop too. Merely removing the root of the array tree brings you memory leak!
Also, if you cleared the list by delete, wont you need to store data in the list anymore? Using delete in linked lists is a good idea, but it does not apply here. Just reseting the counter does the job and it does not show IDs in the list anymore. The for inside the list does only count up to the counter.
If you exit the program don't you free the memory?
I say
delete [] ptrarr;
is good for being at exit.
You are creating an an array of pointers, each one of which points to one element:
ptrarr[r] = new ID[1] ;
The maximum index that you can use with ptrarr[r] is 0. Since you are using ptrarr[counter][1], you are accessing memory that is out of bounds. This leads to undefined behavior. Crashing is one such undefined behavior.
There are other issues with your code that you may want to fix.
More out of bounds memory access
You are using:
int counter = 0;
while(counter<100){
...
getline (cin,ptrarr[counter][1].name);
That is again going to lead to undefined behavior if counter > 10 since you allocated only 10 pointers for ptrarr.
Deleting the contents
You are using:
else if(command=="clear")
{
delete[] ptrarr;
cout << "Entries cleared" << endl;
}
There are couple of problems with this:
You have memory leak. You never call delete [] on what ptrarr[0] - ptrarr[9] point to. You'll have to use:
else if(command=="clear")
{
for ( int i = 0; i < 10; ++i )
{
delete [] ptrarr[i];
}
delete[] ptrarr;
cout << "Entries cleared" << endl;
}
Remember that every allocation must have a corresponding deallocation. Otherwise, you are leaking memory.
Once you call delete [] ptrarr;, it points to dangling memory. I don't see any code that reallocates memory for ptrarr while you continue to use it.
You need to reallocate memory and reset counter to 0 when the user chooses "clear".
My suggestion
You don't two levels of pointers. You just need something like:
int const MAX_ITEMS = 100;
ID* IDarr = new ID[MAX_ITEMS];
Instead of ptrarr[counter][1], use IDarr[counter].
Use MAX_ITEMS in the expression of the while statement instead of the magic number 100.
int counter = 0;
while(counter<MAX_ITEMS){
When processing "clear", you don't need to deallocate or allocate memory. Just reset counter.
else if(command=="clear")
{
counter = 0;
cout << "Entries cleared" << endl;
}
Make sure to deallocate memory before returning from main.
Here's the complete main function with the changes:
int main(int argc, char** argv) {
const int MAX_ITEMS = 100;
ID* IDarr = new ID[MAX_ITEMS];
int counter = 0;
while(counter < MAX_ITEMS){
cout << "Type add to create a new entry" << endl;
cout << "Type list to see all entries" << endl;
cout << "Type clear to delete all entries" << endl;
cout << "Type exit to terminate" << endl;
string command = "0";
getline (cin,command);
if(command=="add")
{
cout << "Enter name" << endl;
getline (cin, IDarr[counter].name);
cout << "VIP? 1 for yes, 0 for no" << endl;
cin >> IDarr[counter].vip;
cout << "Enter score" << endl;
cin >> IDarr[counter].score;
cout << "Month of birth" << endl;
cin >> IDarr[counter].date.month;
cout << "Year of birth" << endl;
cin >> IDarr[counter].date.year;
counter++;
}
else if(command=="list")
{
for (int i=0; i<counter; i++)
{
int n=i+1;
cout << n << " " << IDarr[i].name << " ";
if (IDarr[i].vip)
{
cout << "VIP ";
}
cout
<< "Score: " << IDarr[i].score << " "
<< "Born: " << IDarr[i].date.month << "/" << IDarr[i].date.year << endl;
}
}
else if(command=="clear")
{
counter = 0;
cout << "Entries cleared" << endl;
}
else if(command=="exit")
{
// Don't use return 0;
// Just break out of the while loop so that memory
// can be deallocated at the end of this function.
break;
}
else
cout << "try again" << endl;
}
delete [] IDarr;
return 0;
}
Array indices start at 0.
ptrarr[counter][1] refers to the second element of ptrarr[counter]. ptrarr[counter] points to an array of one element.
try this :
if(command=="add") {
cout << "Enter name" << endl;
getline (cin,ptrarr[counter][0].name);
cout << "VIP? 1 for yes, 0 for no" << endl;
cin >> ptrarr[counter][0].vip;
cout << "Enter score" << endl;
cin >> ptrarr[counter][0].score;
cout << "Month of birth" << endl;
cin >> ptrarr[counter][0].date.month;
cout << "Year of birth" << endl;
cin >> ptrarr[counter][0].date.year;
counter++;
}
else if(command=="list") {
for (int i=0; i<counter; i++){
int n=i+1;
cout << n << " "<< ptrarr[i][0].name << " ";
if (ptrarr[i][0].vip){
cout << "VIP ";
}
cout << "Score: " << ptrarr[i][0].score << " "
<< "Born: " << ptrarr[i][0].date.month << "/" << ptrarr[i][0].date.year << endl;
}
}
Conclusion :
Just as you initialized counter with 0 you should have used 0 index to access the first element;
Same goes while listing.
Arrays are 0 index based.