Passing array between structures C++ - c++

I am new to C++ and there is a basic problem I am dealing with. The code below gives complier error:
#include <iostream>
using namespace std;
struct contact_info {
long number;
string name;
};
contact_info take(){
contact_info takein[2];
for (int i=0; i<2; i++) {
cout<<"what is the name"<<"\n";
getline(cin,takein[i].name);
cout<<"what is the phone number"<<"\n";
cin>>takein[i].number;
};
return takein;
};
void give(contact_info takein){
cout<<"Name:"<<takein.name<<"\n"<<"Number:"<<takein.number;
};
int main(int argc, const char * argv[])
{
contact_info takein;
takein=take();
give(takein);
return 0;
}
The error comes from function "take" and is "No viable conversion from 'contact_info[2]' to 'contact_info'"
The code is supposed to take two contact informations in a loop and then prints them on the screen.
I think I need to use pointers for that to pass the "takein" from "take" function to "main" function. Can anyone says if I can fix the code using array and not pointer?

#include <iostream>
struct contact_info
{
long number;
string name;
};
void take(contact_info takein[2])
{
for (int i=0; i<2; i++)
{
cout<<"what is the name"<<"\n";
getline(cin,takein[i].name);
cout<<"what is the phone number"<<"\n";
cin>>takein[i].number;
};
};
void give(contact_info takein)
{
cout<<"Name:"<<takein.name<<"\n"<<"Number:"<<takein.number;
};
int main()
{
contact_info takein[2];
take(takein);
for(int i=0;i<2;++i)
give(takein[i]);
return 0;
}

return takein;
but
contact_info takein[2];
Compiler is upset because you're trying to return an array, use return takin[0]; or return takin[1]; to return a specific contact_info
Addendum
Don't be afraid to learn Python first, higher level languages are a lot more forgiving and python is by no means a toy language, Python and C++ are two things I use daily and I love them both. I tolerate Java, it can be good when you want static typing and something more forgiving than C++, or in my case Android :P
If you edit your question to describe what you want to do I am happy to provide some annotated code to demonstrate, leave a comment to this to get my attention.

contact_info[] take(){
...
}
if you are trying to return an array.
for returning an element, use
return takein[0];
or
return takein[1];

If your goal is "to take two contact informations in a loop and then prints them on the screen", you must pass an array to get information and pass an array to prints it:
contact_info * take(contact_info *takein){
for (int i=0; i<2; i++) {
cout<<"what is the name"<<"\n";
getline(cin, takein[i].name);
cout<<"what is the phone number"<<"\n";
cin>>takein[i].number;
};
return takein;
};
void give(contact_info * takein){
for (int i = 0; i < 2; i++)
cout<<"Name:"<<takein[i].name<<"\n"<<"Number:"<<takein[i].number;
};
int main(int argc, const char * argv[])
{
contact_info takein[2];
// pass takein as an array
take(takein);
give(takein);
return 0;
}

Secret's out! Arrays are pointers. Or at least, they implicitly convert to them. Even it you did have the right type, you'd be using undefined behavior, as the array is allocated on a place on the stack that no longer exists.
I'll assume you actually want to 'return two things', otherwise Alec's answer is perfectly valid.
Try a vector, or a 2 element struct. People often struggle mentally with the notion of creating a struct only to serve as a return value, but it's worth it from a maintainability standpoint. You get the power of naming the type and naming its contents, and that self-documents your intent.

In the main function takein is a variable of type contact_info
and here takein=take(); you are trying assign an array to a normal variable.

Related

Output parameters with arrays in one function with Arduino and C ++

I have a problem with the initialization with various parameters in my function.
It works if I have created an array int params [] = {...}. However, it doesn't work if I want to write the parameters directly into the function.
declaration (in the .h)
void phase_an(int led[]);
in the .cpp
void RS_Schaltung::phase_an(int led[])
{
for (size_t i = 0; i < LEN(led); i++) {
digitalWrite(led[i], HIGH);
}
}
if I try this way, it won't work. I would like it to be like that. But I couldn't find anything about it on the internet. ...:
in the Arduino sketch:
RS.phase_an(RS.ampelRot, RS.ampelGelb, ..... ); <--- is there a way to do it like that?
what amazes me is that it works this way:
int p_an [5] = {RS.ampelRot, RS.ampelGelb, RS.ampelGruen, RS.rot, RS.gelb};
...................
RS.phase_an (p_an);
does anyone have a suggestion?
There are several ways of making a function accepting a variable number of arguments here.
However, in your current code there is a problem: when you pass a native array of unknown size as argument of a function (e.g. void f(int a[])), the argument will be managed a pointer to an array, and there is no way inside this function to know the real length of that array. I don't know how LEN() is defined, but chances are high that it doesn't works well in your code.
A safer and more practical alternative is to use a vector<int> instead:
#include <iostream>
#include <vector>
using namespace std;
void f(const vector<int>& a){
for (int i=0; i<a.size(); i++) {
cout<<a[i]<<" ";
}
cout<<endl;
}
int main() {
vector<int> test={1,2,3,4};
f(test);
f({1,2,3,4});
return 0;
}
In this case, you can pass your multiple values between bracket in the function call (e.g. ({RS.ampelRot, RS.ampelGelb, RS.ampelGruen, RS.rot, RS.gelb})and C++ will automatically convert it to a vector.

How do I add elements to a vector of objects and print them?

Our teacher told us to create a vector of objects and perform operations on it, but I couldn't understand how to properly do that: I tried to make a simple project with minimum data so that I could know what I was doing.
I have this class
class Obj {
private:
int num;
public:
Obj();
void setNum(int nuovo_num);
int getNum();
};
And then this one, with a vector of Obj
class VettObj{
private:
vector<Obj> vett;
public:
VettObj();
void setVett();
void stampaVett();
};
My initial thought was to use an iterator but I was just making a total mess and, with almost useless research, I decided to use a common integer counter.
I found that I shouldn't write anything in the VettObj costructor, as it automatically initialize stuff, so I left it blank.
The method that adds elements is this
void VettObj::setVett(){
Obj temp;
int i;
i = 0;
while(i < 5){
temp.setNum(10);
vett.push_back(temp);
i++;
}
}
And the one that prints elements
void VettObj::stampaVett(){
int i;
i = 0;
while(i < 5){
vett[i].getNum();
i++;
}
}
When I compile, everything goes well, but when I run the program I get nothing on the screen. I don't want to use mostly vector functions(if not necessary) as I saw that a lot of people can do it like this. I would really like to know how to do it with iterators too. Help pls ????
You are not actually printing anything in the stampaVett() method.
You could try with:
void VettObj::stampaVett(){
int i = 0;
while (i < 5){
std::cout << vett[i].getNum();
i++;
}
}
I'd also suggest using English for method or variable instead of Italian, since SO is an international community.

Problems with default value of pointer to pointer in constructor

When we are using a "double" pointer to class, what are we writing in the constructor with arguments? Are we using one pointer for the allocated memory ?
Here is the code. It doesn't compile and I don't understand why. Thanks for the help.
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
class Article{
private:
char title[100];
char author[50];
char *content;
bool publish;
public:
Article(char *title="", char *author="", char *content="", bool publish=0){
strcpy(this->title, title);
strcpy(this->author, author);
this->content=new char[strlen(content)+1];
strcpy(this->content, content);
this->publish=publish;
}
void show(){
cout<<title<<endl;
cout<<author<<endl;
cout<<content<endl;
}
~Article(){
delete [] content;
}
};
class Newspaper{
private:
char name[100];
Article **p;
int articles;
Article first;
public:
Newspaper(char *name="", Article **p=Article(), int articles=0, Article first=Article()){
strcpy(this->name, name);
}
};
int main() {
char title[100], author[50], content[100];
int n;
cin >> n;
char name[100];
cin.getline(name, 100);
cin.getline(name, 100);
Article first("VAZNO","OOP","Vezba:OOP",true);
Newspaper v(name,first);
Article **s = new Article*[n];
for(int i = 0; i < n; ++i) {
cin.getline(title, 100);
cin.getline(author, 50);
cin.getline(content, 100);
v.addArticle(Article(title, author, content, true)); //se koristi copy konstruktor
}
v.showFirst();
v.showLongest();
cout << v.totalofauthor(author) << endl;
for(int i = 0; i < n; ++i) {
delete s[i];
}
delete [] s;
return 0;
}
Solution to your question:
From your code it seems that a Newspaper uses a pointer to a pointer (what you call a double pointer) for keeping track of the Articles:
Newspaper(char *name, Article **p , // This would be ok
int articles = 0, Article first = Article())
but that you've trouble to define a default argument for it:
Newspaper(char *name="", Article **p=Article(), // oops doesn't compile
int articles = 0, Article first = Article())
The reason is that a "double" pointer is not the same as the object itself. If you want a default argument here, you must provide a double pointer as well.
This code does exactly this:
Newspaper(char *name = "", Article **p = new Article*, // this is ok !
int articles = 0, Article first = Article()){
So this is the solution to your question.
But what's your problem ?
But what's the purpose or providing a dummy pointer, pointing to nowhere as default argument ?
Later you try to create a Newspaper based on an article again:
Newspaper v(name, first); // won't work, because first is not a pointer either
So the problem is not the constructor, but the whole principle. It seems that you really want to create a Newspaper based on an Article, and that you use defaults to cover the case where someone wants to create a Newspaper without Article.
Apparently your design also foresees that Articles may be added dynamically:
v.addArticle(Article(title, author, content, true));
Finally it seems that you really have a problem with pointers: when in the constructor you write, you didn't initialise the poitner to a memory region large enough to hold the name:
Newspaper(char *name = "", ...) {
strcpy(this->name, name); // Ouch !! pointer name is not initalized !
}
So once you'll get your code compiled, your programme won't work ! As this->name is a pointner that is never initialized, your strcpy() will cause memory corruption and undefined behaviour (crash!?).
Recommendations
First, get a book or a tutorial to understand and master pointers. If you do'nt you'll quickly be completely lost in your C++ class.
In the meantime, get rid of your char* and strcpy() and alike, and use std::string instead.
Last, consider the use of std::vector to manage the dynamic Article container. A dynamic array of poitners implemented with Article** would need extra logic, such as maintaining the size, reallocation of memory once the number of article grows, not speaking of the ownership (allocation/deallocation) of the Articles you put in the array.
Based on these recommendations, your Newspaper would look like this:
class Newspaper{
private:
string name;
vector<Article> p; // p.size() will provide the number of articles
public:
Newspaper(string name = "") : name(name) { } // empty newspaper
Newspaper(string name, Article& a) : Newspaper(name) { // combo
addArticle(a);
}
void addArticle(Article &a) {
p.push_back(a); // add and article to the vector
}
... // rest of the code, here
};
And here a little more

How to manage objects in a fixed array?

This if for my homework.
I have a class called Student that takes 3 parameters (id, name, class) and I want to store each student in an array called Roster (which can only have 7 students).
The user will provides input to add or remove students. Thus, I have to manage the array by creating or deleting students. So if the user specify the student ID, I have to remove him for the array.
I tried to use a fixed array, but I'm struggling to make it works. Is there a better way to implement this?
I must not use a vector or any STL container.
student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <iostream>
#include <string>
static const int SIZE = 7;
class Student {
private:
int student_id;
std::string name;
std::string classification;
public:
Student(int, std::string, std::string); // constructor; initialize the list to be empty
~Student();
void print();
};
#endif
student.cpp
#include <iostream>
#include <string>
#include "student.h"
#define PROMPT "class> "
using namespace std;
Student::Student(int a, string b, string c){
student_id = a;
name = b;
classification = c;
}
Student::~Student(){
//delete Student
}
void Student::print(){
cout<<"Enrolled:"<<endl;
cout<<student_id<<"-"<<name<<"-"<<classification<<endl;
}
main.cpp
#include <iostream>
#include <string>
//#include <sstream>
#include "student.h"
#define PROMPT "class> "
using namespace std;
//**** Implement Error Handling ****\\
enum errorType {
UNKNOWN_ERROR,
INPUT_ERROR,
HANDLER,
NUM_ERRORS
};
// error messages
string errorMessage[NUM_ERRORS] = {
"Unknown Error\n",
"Input Error\n",
};
// error handler
void handleError(errorType err) {
if(err > 0 && err < NUM_ERRORS)
cout<< "Error: "<< errorMessage[err];
else cout<< "Error: "<< errorMessage[UNKNOWN_ERROR];
}
//**** END Error Handling ****\\
void enroll(Student newStudent){
cout<<"test";
Student roster[SIZE];
for(int i=0;i<SIZE;i++){
newStudent->roster[i];
}
}
void handleInput() {
int id; string n, c;
cin>>id>>n>>c;
Student newStudent(id,n,c);
newStudent.print();
enroll(newStudent);
//cout<<"hello3"<<endl;
return;
}
int main() {
//Student newStudent; /* <-- why doesn't this work?!*/
string input = "";
bool finished = false;
cout<<PROMPT; // prompt the user
while(!finished) {
if(input!="") cout<<PROMPT;
cin>>input;
if(input=="enroll") {
cout<<PROMPT<<"Enroll student:"<<endl;
handleInput();
}
else if(input=="drop") {
cout<<PROMPT<<"Enter ID:"<<endl;
}
else if(input=="roster") {
cout<<"This will print formatted list of students"<<endl;
}
else if(input=="quit") {
finished=true;
}
else handleError(errorType(1));
}
}
Since it is a homework, I'd like to point out some mistakes you did because it is important to understand what you are doing in the first place.
You must not program by coincidence, but by trying to understand exactly what's going on. By doing that you will become better and better and the answers should fall in place.
What you've done
So, from what you are describing, the array is fixed. Thus it is a good idea to use a constant as you did (SIZE).
However, as we can see below you a declaring an array of size SIZE in the function. By doing that, your array is like a temporary variable, because its scope is inside the function. Each time you call this function, the array will be declared again and then deleted at the exit. So it should be declared outside.
void enroll(Student newStudent)
{
cout<<"test";
Student roster[SIZE]; // Here 'roster' will be available only inside the function.
for(int i=0;i<SIZE;i++)
{
newStudent->roster[i]; // Here there is few mistakes see my explanation below*
}
}
If we look at this part:
newStudent->roster[i];
First of all, the arrow '->' is used with pointers. The dot '.' is used with objects. In both case, it does the same thing, access to public members of Student.
Since you passed
void enroll(Student newStudent)
you should use '.' instead.
newStudent.SomeOfYourMembers;
If the parameter was a pointer to a Student
void enroll(Student *newStudent)
Then, you'd have to use the arrow '->' like you did.
Back to the original statement:
newStudent->roster[i];
This means, you want to access to 'roster' array at position 'i' inside your Student object (newStudent). As you can see in your code, roster is not declared inside Student (and should not be since you want an array of Students), so that won't work.
Guidelines
As I mentionned, your array should be outside the function, so at a higher scope.
Then, if you need an array of student, basically, 'roster[i]' will give you access to the student 'i'. Thus, if you want to print the student, you would do something like that:
roster[i].print();
This would be valid because 'print()' is defined as public.
In order to store a student inside the array, you can do something like:
roster[i] = new Student(0 /* id*/, "name", "classification");
But don't forget, each time you use new, you have to balance it with a delete. And if you are creating the student like this in a loop, you will have to clean them the same way:
for(int i = 0; i < SIZE; ++i)
{
delete roster[i];
}
Good luck!
Don't hesitate if there is there anything that I could clarify. I hope this helps!
Edit: In reply to your first comment.
Concerning the roster array
No, it is not mandatory to create a class roster you could declare roster in the main.cpp.
The key concept is that by defining
Student roster[SIZE];
the array will contains objects of type Student.
What roster[i].print() means is that you are printing one of the Student of that array, in fact the one at position 'i'.
Concerning the print() function
What is powerfull with Object Oriented language, each object will have the same print() function. So, you do not need to convert the array to string.
However, if you want a string to be printed out (or returned) you can write the code inside the print() function that will do this job.
The advantage of this, is that if further on you need to change your array in some ways, your print() function will always work.
Concerning the Delete
When you are doing something like this on an array that contains objects:
delete roster[i];
It will delete the object at the position 'i'. Thus, the destructor of that Student 'i' will be called. If your object Student would contains other object, you would have to delete them in the destructor.
Further notices
Since ID is an input that you are storing into a string, you will have to convert the ID to the same type of the student_id, which is a int. Then you can always write a loop for each student and check their ID to delete the proper one.
Concerning the container, a fixed array might not be the best to achieve this job. You might want to look the LinkedList concept.
It doesn't make much sense for enroll to be a member function, so
I'd wrap the roster into a class to get automatic clean up of my
pointers.
#include <cstddef>
struct Student {};
class Roster
{
private:
static const size_t size = 7;
// non-copyable
Roster(const Roster&);
Roster& operator=(const Roster&);
public:
Roster() {
for(unsigned i = 0; i < size; ++i) {
roster_[i] = NULL;
}
}
~Roster() {
for(unsigned i = 0; i < size; ++i) {
delete roster_[i];
}
}
// enroll by copy
bool enroll(const Student& s) {
for(unsigned i = 0; i < size; ++i) {
if(roster_[i] == NULL) {
roster_[i] = new Student(s);
return true;
}
}
// out of space
return false;
}
// enroll by taking ownership
bool enroll(Student* s) {
for(unsigned i = 0; i < size; ++i) {
if(roster_[i] == NULL) {
roster_[i] = s;
return true;
}
}
// out of space
return false;
}
private:
// data
Student* roster_[size];
};
int main()
{
Roster r;
Student s;
r.enroll(s);
Student* sp = new Student();
r.enroll(sp);
return 0;
}
What about this?
Student * roster[2];
roster[0] = new Student(5,"first","2A");
roster[1] = new Student(2,"Second","5B");
Ps:
Enrol and Size shouldn't be members of the student class.
Print should ideally be externalized and a ToString function should be added instead.
You should use the inline constructor initialization instead:
Student(int a,string b,string c):id(a),name(b),class(c){}
You've used the keyword class as a variable name of type string. You shouldn't do that. Does it even compile like that?
enroll should have two arguments: void enroll( Student enrollee, Student Roster[]). You should probably change the name of Roster to roster because it's not a class and typically class names are capitalized.
If your array will only ever have 7 students then you could use some sentinel value to mark that the current student as an invalid student. Perhaps the id will be -1 to mark this. It means basically that you need some way to keep track of which spots in the array you can still use. If you don't do this then declaring an array of Students will get you an array of students with garbage member variables. You wouldn't be able to tell which students are real ones and which are just place holders for when someone new enrolls in the class. I would create a default constructor of Student and initialize its member variables like this:
id=-1;
name="";
name_of_class="";
I changed the name of your string class to avoid confusion.
After all that, enroll would look something like this:
void Student::enroll( Student enrolee, Student roster[]){
//search through roster to check for the first student with an
//id of -1
//if there are no students with id of -1, produce an error message
//that the class is full
//overwrite the student with id of -1 with the id, name, and
//name_of_class of enrollee
}
Although I'm not sure what exactly string class is there for. Does it store what class the Student is in? Is it their year in school like Freshman, Sophomore?
If you're suppose to use dynamic allocation of roster, though, it's a different story, but you said it will only ever have seven students.

Problem passing a list of objects to another class, C++

Below I have written a sample program that I have written to learn about passing a list of objects to another class. I talk about the problems I am having below.
#include <iostream>
#include <vector>
using namespace std;
class Integer_Class
{
int var;
public:
Integer_Class(const int& varin) : var(varin) {}
int get_var() { return var; }
};
class Contains_List
{
typedef Integer_Class* Integer_Class_Star;
Integer_Class_Star list;
public:
Contains_List(const Integer_Class_Star& listin) : list(listin) {}
Integer_Class* get_list() { return list; }
};
int main (int argc, char * const argv[])
{
// Create a vector to contain a list of integers.
vector<Integer_Class> list;
for(int i = 0; i < 10; i++)
{
Integer_Class temp_int(i);
list.push_back(temp_int);
}
This is where the errors start occuring. Could someone please look at the second class definition and the code below and shed some light on what I'm doing wrong. Thank you so much, as always!
// Import this list as an object into another object.
Contains_List final(list);
// Output the elements of the list by accessing it through the secondary object.
for(int i = 0; i < 10; i++)
{
cout << final.get_list()[i].get_var();
}
return 0;
}
You don't mention what sort of errors you are getting, but one very obvious problem with your code is that the constructor for Contains_List expects a pointer to Integer_Class while the parameter you are sending it (list) is of type vector<Integer_Class>.
A vector is not the same as an array, so you cannot pass it as pointer to the type it contains. Either change your constructor to accept a vector or pointer/reference to vector, or change the code that is causing you problems so that it sends it a pointer to an array.
The 'Contains_List' constructor takes in an 'Integer_Class*'
You declare 'list' to be of type 'vector', yet you pass it to the the 'Contians_List' constructor. You should change the 'Contains_List' class so that it holds a vector instead of an Integer_List array. The two are not interchangeable.
You could also change the vector to be an array of Integer_List's instead, if you so wished.