I have an exercise to write down data to a dynamic table of structures using a function. Here's my code:
#include <iostream>
#include <cstdlib>
using namespace std;
struct student{ char name[15], surname[20]; int age; };
student * createTab(int tsize)
{
student *t = new student[tsize];
return t;
}
void fill(student *t, int tsize)
{
for (int i = 0; i<2; i++)
{
cout << "Enter a name: "; cin >> t[i].name;
cout << "Enter a surname: "; cin >> t[i].surname;
cout << "Enter age: "; cin >> t[i].age;
}
}
int main()
{
student *t = createTab(10);
fill(t, 20);
cout << t[0].surname << endl;
cout << t[1].name << endl;
system("pause");
delete[]t;
return 0;
}
It works, okay. But here, in fill() function I use the index syntax with student[].name. I always worked on tables with pointers like that: *(table+i) in a for loop. *(t+i).name doesn't work. Can I iterate on structure fields using pointers?
P.S - Am I freeing the memory correctly?
And I guess P.S 2 - How is it possible, that when I insert a pointer to a first element of my table to a function, and then I can operate on whole table with indexes?
The standard defines the subscripting as follows:
5.2.1/1 (...) The expression E1[E2] is identical (by definition) to *((E1)+(E2))
This is why, using a pointer t and an index i, *(t+i) and t[i] is the same. The problem with your code in the context of struct fields, is a question of priority: you may write (*(t+i)).name or better (t+i)->name, or much clearer, as you did: t[i].name.
P.S.: If you allocate a table with new[...] you have to free it with delete[]. So yes: it's ok !
Related
#include <iostream>
using namespace std;
class car{
string owner;
string car_num;
string issue_date;
car(string o, string cn, string id)
{
owner = o;
car_num = cn;
issue_date = id;
}
void getInfo()
{
cout << "Car's Owner's Name : " << owner << endl;
cout << "Cars' Number : " << car_num << endl;
cout << "Car's Issue Date : " << issue_date << endl;
}
};
int main()
{
int n;
cout << "Enter total number of cars stored in your garage : \n";
cin >> n;
car c1[n]; //incomplete code due to the issue
return 0;
}
Here I want to take the total car numbers from user. And also want to take the car properties from user by using a loop. But how Can I do that while using a constructor?
My advice is not to over use the constructor. It supposed to construct, and really should only construct. In your case, you don't even really need a constructor.
Instead add a new function to do initialization.
Traditional is to use an operator >> which is often an external function.
As for the loop...
car c1[n]; //incomplete code due to the issue
is not legal C++ (although it's allowed in C, and many compilers that are also C compilers)
It's better to use a vector. So...
vector<car> c1(n);
for (auto& c : c1)
cin >> c;
An advanced technique is to use a istream iterator, which will allow you to use algorithms like std::copy, calling the input operator for each member of the vector. However, it's really not required, just a "nicety"
car c1[n]; //incomplete code due to the issue
In fact, you have 2 issues here:
Variable-Length Arrays (VLA) are not allowed in standard C++. They
are optionally allowed in standard C, and are supported by some
C++ compilers as an extension.
You can't have an array of objects w/o default constructor (unless you fully initialize it).
Assuming you don't want to change the class (other than insert public: after the data members), the modern solution should use std::vector:
std::vector<car> c;
//incomplete part
for(int i = 0; i < n; i++){
std::string owner, car_num, issue_date;
//TODO: get the strings from the user here ...
c.emplace_back(owner, car_num, issue_date);
}
Use pointer array instead.e.g.
car* c1[n];
//incomplete part
for(int i = 0; i < n; i++){
//take input and process
c1[i] = new car(//put processed inputs here);
}
PS: I feel like I made a mistake somewhere but can't test it now. If it doesn't work, put a comment here.
You can use loop with std::cin, likefor(int i=0;i<n;++i){std::cin<<num;}. The 'n' I mentioned in the code can also be assigned by std::cin
int n;
std::cin>>n;
car* cars=new car[n];
for(int i=0;i<n;++i)
{
std::getline(cars[i].owner,std::cin);
// and something other you'd like to do, like to test its validity
}
#include <iostream>
using namespace std;
class car{
public:
string owner;
string car_num;
string issue_date;
void cars(string o, string cn, string id)
{
owner = o;
car_num = cn;
issue_date = id;
getInfo();
}
void getInfo()
{
cout << "Car's Owner's Name : " << owner << endl;
cout << "Cars' Number : " << car_num << endl;
cout << "Car's Issue Date : " << issue_date << endl;
}
};
int main()
{
int n;
string a,b,c;
cout << "Enter total number of cars stored in your garage : \n";
cin >> n;
car cas[n]; //incomplete code due to the issue
for(int i=0;i<n;++i)
{
cout<<"value1:";
cin>>a;
cout<<"value2:";
cin>>b;
cout<<"value3:";
cin>>c;
cas[i].cars(a,b,c);
}
return 0;
}
I made a simple array of struct I made a function to implement the array from users input
but I am struggling to find the right way to free or delete elements in the array ;
here is my code for a better understanding
#include <iostream>
using namespace std;
typedef struct InfStudent
{
int id;
int age;
int lvel;
}studentInfo;
void addElments(studentInfo *s)
{
int i=0;
for(i=0; i<2; i++) {
s[i].id = i;
s[i].age = i * i + 1;
s[i].lvel = i + i + 2;
}
}
int studCounter = 0 ;
void deltetElement(void *studentInfo1 ) {
for (int i = 0; i < 6; i++) {
cout << "empty " << endl;
free(studentInfo1);
}
}
int main()
{
int n;int i;
studentInfo st[2];
addElments(st);
for(i=0; i<2; i++) {
cout<<"enter the Id number of the student "<< endl;
cin >> st[i].id;
cout<<"enter the age of the student "<< endl;
cin >> st[i].age;
cout<<"enter the level of the student "<< endl;
cin >> st[i].lvel;
}
deltetElement(st);
for(i=0; i<2; i++) {
cout << "Id of the student " << i << "\t=" << st[i].id;
cout << "\t Age of the student " << i << "\t=" << st[i].age;
cout << "\tLevel of the student " << i << "\t=" << st[i].lvel;
cout<< endl;
}
return 0;
}
the output
enter the Id number of the student
1234
enter the age of the student
32
enter the level of the student
2
enter the Id number of the student
321
enter the age of the student
2
enter the level of the student
32
empty
it is printing empty, but the code still working like 3 second and then printing empty massage, but I did not understand it does delete or not, or there is a better way to do that;
Since you are using studentInfo st[2]; it's an array of VALUE types, meaning that studentInfo objects are not allocated in heap, and should not be deleted by free() or delete.
free or delete array of strcut c++
You create an array with automatic storage. Automatic objects are destroyed and their storage is released automatically when the variable goes out of scope. You cannot and you must not "free" them in any way other than by letting the execution proceed to the outside of the scope where the automatic object is defined.
Only thing that may be passed to free is a pointer that was returned by malloc (or certain other related C allocation functions) and hasn't previously been freed. Since that doesn't apply to what you pass to free, the behaviour of your program is undefined. That's bad. Don't do that.
P.S. Don't use malloc nor free in C++ if you can avoid it (and it can usually be avoided).
I am struggling to find the right way to free or delete elements in the array ;
The elements of an array are destroyed and their storage released when the array itself is destroyed and its memory is released. There is no way to separate those two.
I'm collecting names and test scores to populate a vector. Both the function and main method can't recognize the struct's members. How can I get it to see the members? Or is there a better way to populate a vector of structs with user input using a function?
I've searched other similar posts, but it seems like it's just a simple code error I missed.
#include <iostream>
#include <vector>
using namespace std;
const int classSize = 1;
struct StudentType {
string studentFName;
string studentLName;
int testScore;
char grade;
};
vector<StudentType> collectStudentData(vector<StudentType> students[classSize]) {
for (int i = 0; i < classSize; i++) {
cout << "Student " << i << "'s name and test score" << endl;
cin >> students[i].studentFName >> students[i].studentLName >> students[i].testScore;
}
return students[classSize];
};
int main() {
vector<StudentType> students[classSize] = {};
students[classSize] = collectStudentData(students);
cout << students[1].studentFName << students[1].studentLName << students[1].studentFName;
};
'studentFName': is not a member of 'std::vector>'
This line creates an array of vectors:
vector<StudentType> students[classSize] = {};
What you want is this a single vector:
vector<StudentType> students;
Where that gets initialized to a zero-length array.
When it comes to adding data you don't need to return from the other method, you can pass in a reference and add to it:
void collectStudentData(vector<StudentType>& students) {
for (int i = 0; i < classSize; i++) {
// Read in one at a time
StudentType student;
cout << "Student " << i << "'s name and test score" << endl;
cin >> student.studentFName >> student.studentLName >> student.testScore;
// Add to the array
students.push_back(student);
}
}
Ideally classSize is either passed in as an argument, or you just type a blank line to end input. Using a global variable is really messy and should be strongly discouraged.
vector<StudentType> students[classSize]
Is one issue. You are not declaring a function that takes a vector, you are declaring a function that takes an array of vectors.
Secondly, if you only applied that change you would be passing an empty vector, you can initialize vector to be a particular size by passing in the size to the constructor.
Furthermore, it seems that you would benefit from passing the students vector by reference
vector<StudentType>& students
instead, the & creates a reference. Right now your code is copying the vector when it is passed into the function
#include <iostream>
#include <vector>
using namespace std;
const int classSize = 1;
struct StudentType {
string studentFName;
string studentLName;
int testScore;
char grade;
};
void collectStudentData(vector<StudentType>& students) {
for (int i = 0; i < classSize; i++) {
cout << "Student " << i << "'s name and test score" << endl;
cin >> students[i].studentFName >> students[i].studentLName >> students[i].testScore;
}
return students;
};
int main() {
vector<StudentType> students{classSize};
collectStudentData(students);
cout << students[0].studentFName << students[0].studentLName << students[0].studentFName;
};
If you wanted to improve the code further, you would use an iterator in the for loop instead, and preferably you wouldn't need to construct the vector in main, and pass it into a function to mutate it. You could just construct it and return it from the function.
I'm refreshing my knowledge of C++ dynamic memory allocation and structs, and suddenly ran into some trouble. Below is the part of code, which stops executing after 3 line and the program terminates.
int n;
std::cout << "How many hotels do you want : ";
std::cin >> n;
hotel* hotels= new (nothrow) hotel[n];
for (int i= 0; i< n; i++) {
std::cout << "Hotel " << i+1 << " name : ";
std::cin >> hotels[i].name;
std::cout << "Hotel " << i+1 << " rating : ";
std::cin >> hotels[i].rating;
std::cout << "Hotel " << i+1 << " stars : ";
std::cin >> hotels[i].stars;
}
Here is the "hotel" declaration:
struct hotel {
char* name;
short int rating, stars;
};
I'm guessing there is something wrong with the dynamic declaration of "hotels". Where have I gone wrong?
Here, you need to allocated your char*. If not you will have an undefined behaviour (generally a segFault)
There is two more things in your code :
You should use std::string instead of char*. It is a better practice in C++. (At least in this case) :
#include <string>
struct hotel {
std::string name;
//^^^^^^^^^^^
short int rating, stars;
};
You may also want to use std::vector.
The issue here is that you need to allocate memory for char* name in your struct in order to store characters.
You can also use string instead of char * if you are using C++ (preferred way):
struct hotel {
string name;
short int rating, stars;
};
You'll need to include new to be able to use nothrow
http://www.cplusplus.com/reference/new/nothrow/
#include <new> //std::nothrow
One of the exercises in C++ Primer Plus is having me use fstream to open a txt file and input data into a structure then output it. First line of the txt file is the number of "donors". The problem I seem to be having is that (I think) when I use "inFile >> value;" to retrieve the number and then allocate the structure via new, its expecting an int and its getting a string? Is this correct? What should I be doing differently?
//ch6 p278 exercise #9
#include <iostream>
#include <cstring>
#include <fstream>
#include <cstdlib>
using namespace std;
const int SIZE = 60;
struct contributions
{
char name[20];
double dollars;
};
char filename[20];
string donors;
bool donated;
int main()
{
char filename[SIZE];
cout << "Enter name of file to scan: ";
cin >> filename;
fstream inFile;
inFile.open(filename);
if(!inFile.is_open())
{
cout << "Could not open the file " << filename << endl;
cout << "Program terminating.\n";
exit(EXIT_FAILURE);
}
inFile >> donors;
contributions * ptr = new contributions[donors];
for(int h = 0; h < donors; h++)
{
inFile >> ptr[h].name);
inFile >> ptr[h].dollars);
}
//BEGIN OUTPUT OF STRUCTURES
cout << "GRAND PATRONS:\n";
for(int i = 0; i < donors; i++)
{
if(ptr[i].dollars >= 10000)
{
cout << ptr[i].name << " donated " << ptr[i].dollars << endl;
donated = true;
}
}
if (!donated) {cout << "none.\n";}
donated = false;
cout << "PATRONS:\n";
for(int i=0; i < donors; i++)
{
if(ptr[i].dollars < 10000)
{
cout << ptr[i].name << " donated " << ptr[i].dollars << endl;
donated = true;
}
}
if (!donated) {cout << "none.\n";}
delete ptr;
return 0;
}
What should I be doing differently?
Well, if the code is based on what C++ Primer Plus has taught you - use a different text book. I don't want to insult you, but the code is really poor. For example, has the book covered the std::string class?
I would recommend junking it, and getting Accelerated C++ by Koenig & Moo (two of the original C++ team) which will teach you modern, good, idiomatic C++.
You are most certainly correct, I assume the code does not compile? You can just change the donors variable to an integer. The input streams are overloaded to work with all built in types, ie. bool, double, int etc.
The following will work, assuming the next value is an integer:
int numDonors;
inFile >> numDonors;
Note that the change to an integer is also necessary for the 'for' loops to work correctly, you are currently comparing a string to an integer, there is no built-in/default behavior for this.
Edit: I also noticed that when you delete your array of contributors you do:
delete ptr;
However, this will only clear out the first dynamically allocated block. The correct way to delete an array of dynamically allocated objects is:
delete [] ptr;
Edit 2: Thanks for the sample, so the reason it is not working correctly is the fact that the names are first and last, and the stream operator '>>' breaks on whitespace. So what is essentially happening is you first attempt to read the name, the stream reads the first name only and stops. Then you try to read the donated value, this attempts to read the last name as the value and cannot convert to an double so it returns 0.
donors is a string, and you are trying to use it as an array size:
string donors;
//...
inFile >> donors;
contributions * ptr = new contributions[donors];
You should make donors an int. Also it's usually better to use std::vector<> instead of manually messing with pointers to raw arrays. That would look something like this:
std::vector<contributions> contribs;
for (...) {
contributions contrib;
// .. Some way read contrib from inFile
contribs.push_back(contrib);
}