Strange behavior for int / counter - c++

I'm trying to add some songs to a vector inside a class. One of the values I'm storing is an int representing the song. It's essentially a counter. The first song I add should have the value 1, the second value two and so forth. But It's getting other strange values like big random numbers (positives and negatives). I can't wrap my head around what I'm doing wrong. This is the code:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Jukebox{
public:
void addSong(string artist, string title, string filename) {
song s {++songCounter, artist, title, filename};
Songs.push_back(s);
}
void printSong (int song) {
cout << Songs[song].no << ". ";
cout << Songs[song].artist << " - ";
cout << Songs[song].title << " : ";
cout << Songs[song].filename << endl;
}
private:
struct song {
int no;
string artist;
string title;
string filename;
};
vector<song> Songs;
int songCounter;
};
int main() {
Jukebox jbox;
jbox.addSong("U2", "Magnificent", "U2-Magnificent.mp3");
jbox.addSong("Sting", "Englishman in New York", "Sting-Englishman_in_New_York.mp3");
jbox.addSong("U2", "One", "U2-One.mp3");
jbox.printSong(0);
jbox.printSong(1);
jbox.printSong(2);
return 0;
}
Update
Ok, I'm probably stupid and should read more about classes before trying to implement this. But I think I did read and I still don't get it. This is what my class looks like now (which won't work):
class Jukebox(): songCounter(0)
{
public:
void addSong(string artist, string title, string filename) {
songCounter++;
song s {songCounter, artist, title, filename};
Songs.push_back(s);
}
void printSong (int song) {
cout << Songs[song].no << ". ";
cout << Songs[song].artist << " - ";
cout << Songs[song].title << " : ";
cout << Songs[song].filename << endl;
}
private:
int songCounter;
struct song {
int no;
string artist;
string title;
string filename;
};
vector<song> Songs;
};
Final word
Ok. From the example I've seen of c++ contructor classes I had some kind of wrong impression of how they worked. Now I think I'm getting it a little bit more. But the syntax still seems strange to me. But I try to read more so I really understand it. Here is what I did and to seems to work:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Jukebox {
public:
void addSong(string artist, string title, string filename) {
songCounter++;
song s {songCounter, artist, title, filename};
Songs.push_back(s);
}
void printSong (int song) {
cout << Songs[song].no << ". ";
cout << Songs[song].artist << " - ";
cout << Songs[song].title << " : ";
cout << Songs[song].filename << endl;
}
Jukebox(): songCounter(0) {} // Constructor
private:
int songCounter;
struct song {
int no;
string artist;
string title;
string filename;
};
vector<song> Songs;
};
int main() {
Jukebox jbox;
jbox.addSong("U2", "Magnificent", "U2-Magnificent.mp3");
jbox.addSong("Sting", "Englishman in New York", "Sting-Englishman_in_New_York.mp3");
jbox.addSong("U2", "One", "U2-One.mp3");
jbox.printSong(0);
jbox.printSong(1);
jbox.printSong(2);
return 0;
}

You did not initialize songCounter in your constructor.
Jukebox(): songCounter(0),//....other members
If you do not initialize it, then it may have any random value and that leaves your program in an Undefined State.
Always be careful while using unitialized variables, it often leads to Undefined Behavior and your program is a good example of it.
Also, I am not sure of your design but probably it should be a static member if you want to use it as a counter, which maintains state for all objects of your Song class.
Or
You will have to explicitly set it to a proper value at time of creating a Song object.
Okay its a counter for JukeBox and not Song class so its still okay to be a member.

You didn't initialize the variable songCounter.
Add the following to the class definition of Jukebox:
Jukebox(): songCounter(0) {}

you need a constructor for Jukebox and in that you need to initialise the counter to 0.

I think you should initialize songCounter to be 0. In the public part of the class:
public Jukebox() : songCounter(0) {}

Where do you initialise songCounter? In C++, primitives aren't zero initialised by default. You need to add
: songCounter(0)
to your constructor.

Related

Constructor error anytime I use private variables in VS Code

We're learning about constructors in class and I was trying to experiment with an overloaded constructor. When I run my program I keep getting an error written in the color red that says...
~
The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double quotation marks ("&") to pass it as part of a string.
^This only happens when I try to use private variables, when everything is public nothing goes wrong.
///Here's my code
#include <iostream>
using namespace std;
class JCole {
private:
string song;
string album;
int albumNum;
JCole::JCole(string _song, string _album, int _Num) {
song = _song;
album = _album;
albumNum = _Num;
}
};
int main() {
JCole album1("Punchin the clock", "The Off-Season", 6);
JCole album2("ATM","KOD",5);
cout << album1.song << " " << album1.album << " " << album1.albumNum << endl;
cout << album2.song << " " << album2.album << " " << album2.albumNum << endl;
return 0;
}
Your constructor is declared as private because you haven't changed the access setting.
Try this:
class JCole {
private:
string song;
string album;
int albumNum;
// Insert:
public:
JCole::JCole(string _song, string _album, int _Num) {
song = _song;
album = _album;
albumNum = _Num;
}
};
A private constructor is a nasty thing; only members of the class can call it. Thus wreaking havoc with external code that wants to instantiate this class.
Also, you can use many public:, private:, protected: within your class and in any order.

Passing array of strings to a function

I am trying to create a program that uses class, arrays, and functions to show information about two students(Name, id#, classes registered). The part I am struggling with is passing arrays to a function. How do I do that?
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;
class Student // Student class declaration.
{
private:
string name;
int id;
string classes;
int arraySize;
public:
void setName(string n)
{
name = n;
}
void setId(int i)
{
id = i;
}
void setClasses(string c, int num)
{
classes = c;
arraySize = num;
}
string getName()
{
return name;
}
int getId()
{
return id;
}
void getClasses()
{
for (int counter=0; counter <arraySize; counter++) {
cout << classes[counter] << endl;
}
}
};
int main()
{
//Student 1
string s1Name = "John Doe";
int s1Id = 51090210;
int const NUMCLASSES1 = 3;
string s1Classes[NUMCLASSES1] = {"C++","Intro to Theatre","Stagecraft"};
//Student 2
string s2Name = "Rick Harambe Sanchez";
int s2Id = 666123420;
int const NUMCLASSES2 = 2;
string s2Classes[NUMCLASSES2] = {"Intro to Rocket Science","Intermediate Acting"};
//
Student info;
info.setName(s1Name);
info.setId(s1Id);
//info.setClasses(s1Classes, NUMCLASSES1);
cout << "Here is Student #1's information:\n";
cout << "Name: " << info.getName() << endl;
cout << "ID: " << info.getId() << endl;
//cout << "Classes: " << info.getClasses() << endl;
info.setName(s2Name);
info.setId(s2Id);
// info.setClasses(s2Classes, NUMCLASSES1);
cout << "\n\nHere is student #2's information:\n";
cout << "Name: " << info.getName() << endl;
cout << "ID: " << info.getId() << endl;
//cout << "Classes: " << info.getClasses() << endl;
return 0;
}
The usual way to pass around variable-length lists in C++ is to use an std::vector. A vector is a single object that you can easily pass to a function, copying (or referencing) its contents. If you are familiar with Java, it's basically an ArrayList. Here is an example:
#include <vector>
#include <string>
using namespace std;
class foo {
private:
vector<string> myStrings;
public:
void setMyStrings(vector<string> vec) {
myStrings = vec;
}
}
//...
foo myObj;
vector<string> list = {"foo","bar","baz"};
myObj.setMyStrings(list);
If don't want to use the standard library though, you can pass an array C-style. This involves passing a pointer to the first element of the array, and the length of the array. Example:
void processStrings(string* arr, int len) {
for (int i = 0; i < len; i++) {
string str = arr[i];
//...
}
}
string array[] = {"foo","bar","baz"};
processStrings(array, 3); // you could also replace 3 with sizeof(array)
Passing raw arrays like this, especially if you wanted to then copy the array into an object, can be painful. Raw arrays in C & C++ are just pointers to the first element of the list. Unlike in languages like Java and JavaScript, they don't keep track of their length, and you can't just assign one array to another. An std::vector encapsulates the concept of a "list of things" and is generally more intuitive to use for that purpose.
Life lesson: use std::vector.
EDIT: See #nathanesau's answer for an example of using constructors to initialize objects more cleanly. (But don't copy-paste, write it up yourself! You'll learn a lot faster that way.)
You can pass array of any_data_type to function like this
void foo(data_type arr[]);
foo(arr); // If you just want to use the value of array
foo(&arr); // If you want to alter the value of array.
Use std::vector. Also, don't add functions you don't need. Here's an example of using std::vector
#include <string>
#include <iostream>
#include <vector>
using std::string;
using std::vector;
class Student // Student class declaration.
{
private:
vector<string> classes;
string name;
int id;
public:
Student (const vector<string> &classesUse, string nameUse, int idUse) :
classes (classesUse),
name (nameUse),
id (idUse)
{
}
void print ()
{
std::cout << "Name: " << name << std::endl;
std::cout << "Id: " << id << std::endl;
std::cout << "Classes: ";
for (int i = 0; i < classes.size (); i++)
{
if (i < classes.size () - 1)
{
std::cout << classes[i] << ", ";
}
else
{
std::cout << classes[i] << std::endl;
}
}
std::cout << std::endl;
}
};
int main()
{
Student John ({"C++","Intro to Theatre","Stagecraft"},
"John",
51090210);
John.print ();
Student Rick ({"Intro to Rocket Science","Intermediate Acting"},
"Rick",
666123420);
Rick.print ();
return 0;
}
Name: John
Id: 51090210
Classes: C++, Intro to Theatre, Stagecraft
Name: Rick
Id: 666123420
Classes: Intro to Rocket Science, Intermediate Acting
In the private variables of class Student, you are storing a string:
String classes;
where as you should be storing an array of strings like:
String classes[MAX_NUM_CLASSES];
then in the set classes function, pass in an array of strings as the first argument, so it should be :
void setClasses(string[] c, int num)
{
classes = c; //not sure if simply setting them equal will work, rather copy entire array using a for loop
arraySize = num;
}
This should point you in the right direction
Also, use std::vector instead of string[], it will be easier.

In C++, how do I ask the user to input a string, have that string stored, and be able to recall it in any/many functions?

I want to be able to have the user enter their name, store it and be able to recall it in different functions. This is my first code, first program. I am sure there is an easier way to do this, so if you could offer both an answer to the question and a easier way of accomplishing this task it would be much appreciated. Thank you in advance.
This is what I have so far:
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
#include <sstream>
using namespace std;
void game();
void other();
class NameClass{
public:
string name;
};
int main()
{
int a;
int age;
string name;
cout << "Hello user, what is you name? \n\n";
/*Not sure if class and operator needs to be here. I was hoping that when the user
input the stream(their name) it would be stored in the class as well as being able
to use it in the main function.*/
NameClass person;
//This line is here to get name from user.
getline(cin, name);
cout << "Well " << name << ", are you having a good day? \n\n";
cout << "1=Yes 2=No \n\n";
cin >> a;
cout <<"\n";
if(a==1){
cout << "Well that is good to hear.\n\n";
}else{
cout << "I am sorry to hear that. I hope things get better for you. \n\n";
}
cout << "Do you want to play a game? \n\n";
cin >> a;
if(a==1){
game();
}else{
other();
return 0;
}
return 0;
}
void game(){
/*It is in this function that I want the be able to recall the name that the user input in the main function.*/
cout << "Cool "<< name <<",let get started." << endl;
}
void other(){
cout << "Well then "<< name <<", lets do something else.";
}
I assume you aren't aware of the OOP concepts.
Do this (make methods part of the class):
class NameClass{
public:
string name;
void game();
void other();
};
int main()
{
...
NameClass person;
getline(cin, person.name);
...
}
Or this (pass name as parameter):
int main()
{
string name;
...
game(name);
}
void game(string name)
{
cout << "Cool "<< name <<",let get started." << endl;
}
If you want to pass information from one function to another then you use a function parameter (or more than one).
void game(string name);
int main()
{
string name;
...
game(name);
}
void game(string name)
{
cout << "Cool "<< name <<",let get started." << endl;
}
It's a fundamental concept that pretty much all programming languages have.
Just pass the name as a parameter in both your functions, it should be something like this:
//functions
void game(string name);
void other(string name);
In your main function when you call either function just pass the name to it.
if(a == 1)
{
game(name);
}
else
{
other(name);
}

Passing a class object to a list table

I have a struct list, a class castomer. I want to store my castomer to the list. For that I am creating a castomer each time and I strore them to a list table. There are no errors except that the program crashes each time I try to store a castomer into my table.
I have this list and class:
class castomer{
private:
string name;
string lastname;
int number;
double time;
public:
void setAll(string,string,int,double);
int numberR(){return number;}
double timeR(){return time;}
void displayAll();
};
struct node {
castomer person;
struct node *next;
};
This function for adding castomer:
void add(clock_t *start,struct node *table[])
{
*start = clock();
double time=(double)*start;
int i=0;
while(table[i]!=NULL)
{
i++;
}
if(i > 24)
cout << "We are not able to add another castomer becase we are full please wait for ont to go "<<endl;
else{
castomer c1;
cout<<i;
cout<< "Give me the castomers name and lastname :";
string temp1,temp2;
cin>>temp1;
cin>>temp2;
c1.setAll(temp1,temp2,i,time);
table[i]->person=c1;//my program crases here anyone knows why?
}
}
ps: In my main the table[] looks like this struct node * table[25];
struct node* table[25]
This is declaring table to be an array of 25 pointers. You have to allocate memory for each of these pointers which from looking at your code is missing.
After your while-loop, table[i] will be NULL.
table[i]->person = c1; // Your program crashes here because of that.
Using your code as it is, you should do
table[i] = new node;
table[i]->person = c1;
But the code looks very strange, like you want to implement a linked list (the node structure) but are sticking to using arrays for some reason.
If you're aiming for a linked list, you need to rethink a lot of your code.
If you're not, you can lose the node type completely.
Since you are using (or trying to use) C++ I will make mention of a few things you can do to improve your code and make your own life easier.
In C++ you can define constructors for initializing objects.
Your function setAll is a bad practice. You don't really want to change all data of a person after you have created. You just want to initialize the data at creation time. Well use constructors.
You don't need pointers
For what you want to do you don't need complicate the code using pointers you could pass the arguments by reference.
You are using C++, use STL
Specifically vector I guarantee it, will help you.
Use cout << for displaying yuor object
you could add a friend ostream& operator<< function to your class in order to be able to write code like:
Customer a;
cout << a << endl;
A complete example:
#include <iostream>
#include <vector>
#include <ctime>
#include <string>
using namespace std;
class Customer
{
public:
Customer(){} // default constructor.
Customer(string pname, string plastname): name(pname), lastname(plastname)
{
id = ++idgen; // Set an id number.
time = (double)clock(); // initialize time.
}
int getId() {return id;} // former numberR().
double getTime() {return time;} // former timeR().
friend ostream& operator<<(ostream &out, Customer obj)
{out << obj.name << " " << obj.lastname << ". " << "Id: " << obj.id << " Time: " << obj.time;}
private:
static int idgen; // static values are a good way for keep some sort of id.
int id; // former member: number.
double time; // Why don't use clock_t directly?
string name, lastname;
};
int Customer::idgen = 0; // Initialize static variable.
int main()
{
int const MAX_NUMBER_PERSONS = 2;
std::vector<Customer> customer_list;
string name, lastname;
while (customer_list.size() < MAX_NUMBER_PERSONS)
{
cout << "Give me the castomers name and lastname <name> <lastname>:";
cin >> name >> lastname;
customer_list.push_back(Customer(name, lastname));
}
for (auto &x: customer_list) // If you're learnign C++ its a good moment for search
{ // for c++11 doc.
cout << x << endl;
}
return 0;
}

error pushing structure objects with string members into a std::vector

I'm a C#, C programmer learning C++ and I'm having a bit of a trouble.
I'm trying to push an object of the struct type 'Person' into a vector but the string values which are members of the Person type are not copied. Also the code exits with an error message - posted at the bottom:
#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <string.h>
using namespace std;
typedef struct Person {
string Name;
string Lastname;
int Age;
} Person;
void CreatePerson(Person* in_person, string in_name, string in_last,
int in_age)
{
Person t_person;
t_person.Name = in_name;
t_person.Lastname = in_last;
t_person.Age = in_age;
memcpy(in_person, &t_person, sizeof(t_person));
}
int main(int argc, char *argv[])
{
vector<Person> people;
Person t_ppl;
CreatePerson(&t_ppl, "Zareh", "Petros", 13);
people.push_back(t_ppl);
CreatePerson(&t_ppl, "Tina", "Yarroos", 26);
people.push_back(t_ppl);
int ii;
for(ii=0; ii < people.size() ; ii++) {
cout << "Element - " << ii << endl;
cout << "name:" << people[ii].Name << endl;
cout << "lastname:" << people[ii].Lastname << endl;
cout << "age:" << people[ii].Age << endl;
}
return 0;
}
And here is the error message:
*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x09d48048 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x75ee2)[0xb74e8ee2]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdlPv+0x1f)[0xb76e551f]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZNSs4_Rep10_M_destroyERKSaIcE+0x1b)[0xb76cc99b]
/usr/lib/i386-linux-gnu/libstdc++.so.6(+0x909dc)[0xb76cc9dc]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZNSsD1Ev+0x2e)[0xb76cca4e]
std::string is a class and should not be copied by a memcpy operation. It may hold instance-specific data, which will get scrambled if held by two different instances (and probably that's the cause of your problems).
Imagine, that std::string is something like:
class string
{
private:
char * data;
int dataLength;
};
If you memcpy one string to another, both data and dataLength are copied to another place (lately being treated as a normal string instance). However, when the destructor is called on these strings (when they run out of scope), they will attempt to free the data held in data field. First string (which is an actual owner of this pointer) will free memory pointed to by this pointer. But then another destructor of your copied string will run and will try to free this memory again, what is not permitted.
Note, that it's exactly, what your system is reporting: double freeing of memory.
Your code is very C-style. In C++ one would create a class with constructor rather than a function, which fills in a struct. I would write your code in the following way:
#include <iostream>
#include <vector>
#include <string>
#include <stdio.h>
#include <string.h>
using namespace std;
struct Person
{
public:
string Name;
string Lastname;
int Age;
Person(string newName, string newLastname, int newAge)
: Name(newName), Lastname(newLastname), Age(newAge)
{
}
};
int main(int argc, char *argv[])
{
vector<Person> people;
Person person1("Zareh", "Petros", 13);
people.push_back(person1);
Person person2("Tina", "Yarros", 26);
people.push_back(person2);
for(unsigned int i=0; i < people.size() ; i++)
{
cout << "Element - " << i << endl;
cout << "name:" << people[i].Name << endl;
cout << "lastname:" << people[i].Lastname << endl;
cout << "age:" << people[i].Age << endl;
}
getchar();
return 0;
}
The role of your creation method takes the class constructor. It fills in fields of the class properly. Also, C++ provides default copy-constructor and assignment operator, which will handle assigning one person to another properly.
Some side notes about your code style.
In C++ avoid using memcpy. If you have a need of using it, you probably should consider creating proper copy constructor, std::copy or simply making an assignment (what would work perfectly in your situation). memcpy should be used only when copying raw chunks of memory.
typedef is no longer required for structs in C++. Instead of writing:
typedef struct Name { ... } Name;
You can simply write:
struct Name { ... };
You've already been told you shouldn't be using memcpy in this situation, so I won't bother repeating that.
The problem with your CreatePerson goes well beyond using memcpy, and just changing to std::copy isn't really going to make it right.
Instead of a free function to create a person, you should almost certainly write that functionality as a constructor instead:
struct Person {
string Name;
string Lastname;
int Age;
Person(string Name, string Last, int Age)
: Name(Name), LastName(Last), Age(Age)
{}
};
With this, we can create Person objects much more cleanly:
std:::vector<Person> people;
people.push_back(Person("Zarah", "Petros", 13));
people.push_back(Person("Tina", "Yarroos", 26));
I'd also write an inserter that's responsible for displaying a Person in the proper format:
std::ostream &operator<<(std::ostream &os, Person const &p) {
return os << "Name: " << p.Name < "\n"
<< "Last: " << p.LastName << "\n"
<< "Age: " << p.Age << "\n";
}
With this, your mainstream of your code can insert complete Person objects into a stream without paying attention to the internal details of what a Person contains or how it should display:
for (int i=0; i<people.size(); i++)
std::cout << people[i] << "\n";
If you want to be a little more ambitious, you can use a standard algorithm instead:
std:copy(people.begin(), people.end(),
std::ostream_iterator<Person>(std::cout, "\n"));
Or, if you're using a relatively new compiler, you can use a range-based for loop:
for (auto &p : people)
std::cout << p << "\n";
Putting all that together, your complete program ends up something like this:
#include <string>
#include <iostream>
#include <vector>
using std::string;
struct Person {
string Name;
string LastName;
int Age;
Person(string Name, string Last, int Age)
: Name(Name), LastName(Last), Age(Age)
{}
};
std::ostream &operator<<(std::ostream &os, Person const &p) {
return os << "Name: " << p.Name << "\n"
<< "Last: " << p.LastName << "\n"
<< "Age: " << p.Age << "\n";
}
int main(){
std::vector<Person> people;
people.push_back(Person("Zarah", "Petros", 13));
people.push_back(Person("Tina", "Yarroos", 26));
for (auto &p : people)
std::cout << p << "\n";
return 0;
}
Do not use memcpy() on non-POD types. It does not call copy-constructors.
Use std::copy() instead.
In this case, it is easier to do an assignment. Replace:
memcpy(in_person, &t_person, sizeof(t_person));
with
*in_person = t_person;