How to model a book-library system in C using structs? - c++

I am trying to learn C and C++ and I am struggling a bit with pointers. Concretely, I want to model a book-library system using some structs. A library could have more or less books, but we do not exactly the number. Below, I will post some snippet code:
This works but the number of books is known, not desired.
// library.h
#ifndef _LIBRARY_
#define _LIBRARY_
#include "book.h"
typedef struct {
int noBooks;
book books[10];
}library;
void addBook(book*, library*);
#endif
// library.c
#include "library.h"
void addBook(book* b, library* l) {
l->books[l->noBooks] = *b;
l->noBooks++;
}
// book.h
#ifndef _BOOK_
#define _BOOK_
#include <string.h>
#include <stdio.h>.
#include <stdlib.h>
typedef struct book_ {
int id;
char author[15];
char title[15];
}book;
void displayInfo(const book*);
#endif
//book.c
#include "book.h"
void displayInfo(const book* b) {
printf("Id: %d \n Author: %s \n Title: %s\n", b->id, b->author, b->title);
}
//main.cpp
#include<iostream>
extern "C" {
#include "book.h"
#include "library.h"
}
int main() {
std::cout << "Start" << std::endl;
book b1;
strcpy_s(b1.author, "Ab");
b1.id = 1;
strcpy_s(b1.title, "Ab");
book b2;
strcpy_s(b2.author, "Df");
b1.id = 2;
strcpy_s(b2.title, "Df");
library l1;
l1.noBooks = 0;
addBook(&b1, &l1);
addBook(&b2, &l1);
std::cout << l1.books[0].author << "\n";
std::cout << l1.books[1].author;
}
How should I modify it in order to add books without to know exactly the number (10 in this case)?
I tried more cases, for example:
// library.h
#ifndef _LIBRARY_
#define _LIBRARY_
#include "book.h"
typedef struct {
int noBooks;
book* books;
}library;
void addBook(book*, library*);
#endif
// library.c
#include "library.h"
void addBook(book* b, library* l) {
l->books[l->noBooks] = *b;
l->noBooks++;
}
Still, it does not work. Could you give me guidance/advice?
Thank you for your time!

To directly address the concern mentioned in your question, pointers aren't necessary for this program at all. At least not pointers that you need to write.
Given the discussion in the comments about what your code is, I'll chip in an answer that leans more into C++.
#include <iostream>
#include <string>
#include <vector>
class Book {
public:
Book() = default;
Book(int id, std::string auth, std::string title)
: m_id(id), m_author(auth), m_title(title) {}
friend std::ostream& operator<<(std::ostream& sout, const Book& book) {
return sout << "ID: " << book.m_id << "\nAuthor: " << book.m_author
<< "\nTitle: " << book.m_title << '\n';
}
private:
int m_id = 0;
std::string m_author;
std::string m_title;
};
class Library {
public:
void add_book(Book book) { m_books.push_back(book); }
std::size_t size() const { return m_books.size(); }
// The better approach would be to provide iterators so that you can access
// individial books from the library, much like you can with the vector,
// but that's a whole other level of work.
void print() const {
for (auto book : m_books) {
std::cout << book << '\n';
}
}
private:
std::vector<Book> m_books;
};
int main() {
Book b1(1, "Frank Herbert", "Dune");
Book b2(2, "Frank Herbert", "Dune Messiah");
Library l1;
l1.add_book(b1);
l1.add_book(b2);
l1.print();
std::cout << "Number of books in library: " << l1.size() << '\n';
}
Output:
ID: 1
Author: Frank Herbert
Title: Dune
ID: 2
Author: Frank Herbert
Title: Dune Messiah
Number of books in library: 2
As you can see, even a basic C++ (not C with std::cout, but idiomatic C++) implementation requires essentially a full re-write. And I noted one area where I really skimped. Your Library is just wrapping a container, and containers are typically built to be iterated through. But the effort of writing an iterator (it would just be wrapping the vector iterator) just didn't make sense for this answer.
For a toy program like this, you might be better off skipping the Library class completely and just declaring something like std::vector<Book> library; in your main() function and taking direct advantage of all the capabilities that std::vector provides.
The big takeaways in this snippet that will make the code easier to manage are:
Classes. Bundles your relevant data and functions together.
std::vector. A heap-allocated array that grows when needed and knows its own size.
std::string. Handles all the messy parts and far less error-prone.
Also on display is operator overloading. This allows you use your custom types as if they were native types. Much nicer than something like a display() function.
While all that C syntax is technically valid C++, philosophically it's completely wrong. You either want to learn C, or you want to learn C++. Choose one and stick with it. Blending the two the way you did will just lead to a bad time.

If you want to do this in C:
You can try to implement your own resizable library.
Something like this :
typedef struct {
int length;
int capacity;
book *books;
} library;
int add_book(library *lib, book *b) {
// Add a book to the library
assert(lib != NULL); // Check if library is valid
assert(b != NULL); // Check if book is valid
if(lib->length + 1 > lib->capacity) { // We run out of space for new books
lib->capacity *= 2;
lib->books = realloc(lib->books, lib->capacity * sizeof(book)); // Check for errors
lib->books[lib->length] = *b;
lib->length++;
printf("Increased library capacity and added book to library\n");
return 0;
}
else {
lib->books[lib->length] = *b;
lib->length++;
printf("Book added to library\n");
return 0;
}
}
If you want to do this in C++ (much easier):
You can use vector and just append values.

Here is a minimal implementation demonstrating how to dynamically add a book to your library and clean up the resources allocated:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct book {
int id;
char author[15];
char title[15];
};
struct library {
unsigned noBooks;
struct book *books;
};
// check for duplicate id?
struct library *library_add(struct library *l, struct book *b) {
if(!l) return NULL;
struct book *books = realloc(l->books, sizeof(struct book) * (l->noBooks + 1));
if(!books) {
printf("realloc failed\n");
return NULL;
}
l->books = books;
l->books[l->noBooks].id = b->id;
strcpy(l->books[l->noBooks].author, b->author);
strcpy(l->books[l->noBooks].title, b->title);
l->noBooks++;
return l;
}
void library_print(struct library *l) {
if(!l) return;
for(unsigned i = 0; i < l->noBooks; i++) {
printf("id = %d, author = %s, title = %s\n",
l->books[i].id,
l->books[i].author,
l->books[i].title
);
}
}
void library_destroy(struct library *l) {
if(!l) return;
free(l->books);
}
int main() {
struct library l = { 0, NULL };
library_add(&l, &(struct book) { 1, "Ab", "Ab"});
library_add(&l, &(struct book) { 2, "Df", "Df"});
library_print(&l);
library_destroy(&l);
return 0;
}

Related

Member function doesn't work when using pointer to class

Scenario: I have two classes, each contains a pointer to the other (when using them, being able to refer to the other is going to be important so I deemed this appropriate). When I try accessing a private variable from one class via using the pointer to the other and a getter function inside that, it works perfectly.
Problem: Using a setter (in this case, addPoints)/manipulating the variables however leads to no result.
I'm new so anything here might be "improper etiquette" and bad practice. Feel free to point them out! But please also try to provide a solution. This is also my first question on SO, so please be gentle!
Related code pieces:
Team.h
#include "Driver.h"
using namespace std;
class Team {
int Points = 0;
vector<Driver*> Drivers;
public:
void addPoints(int gained); //does not work
int getPoints(); //works perfectly
Driver getDriver(int nr);
void setInstance(vector<Driver*> drivers);
};
Team.cpp
#include "Team.h"
#include "Driver.h"
using namespace std;
void Team::addPoints(int gained) {
this->Points = this->Points + gained;
}
int Team::getPoints() {
return this->Points;
}
Driver Team::getDriver(int nr) {
return *Drivers[nr];
}
void Team::setInstance(vector<Driver*> drivers) {
this->Drivers = drivers;
}
Driver.h
using namespace std;
class Team;
class Driver {
int Points = 0;
Team* DriversTeam;
public:
void SetTeam(Team& team);
Team getTeam();
int getPoints(); //works
void addPoints(int gained); //doesn't work
};
Driver.cpp
#include "Driver.h"
#include "Team.h"
using namespace std;
void Driver::SetTeam(::Team& team) {
this->DriversTeam = &team;
}
Team Driver::getTeam() {
return *DriversTeam;
}
int Driver::getPoints() {
return this->Points;
}
void Driver::addPoints(int gained) {
this->Points = this->Points + gained;
}
Initializer.cpp (linking drivers to teams)
void InitializeData(vector<Team>& teams, vector<Driver> &drivers) {
//(...)
//reads each team in from data file to memory
//key part:
vector<Driver*> teamsDrivers;
for (auto& iter : drivers) { //this loop mainly determines which driver to link with which teams
if (iter.getName().compare(values[4]) == 0) { //values is csv line data in a string vector. I guess not the prettiest parsing method here but will be revised
teamsDrivers.push_back(&iter);
}else if(iter.getName().compare(values[5]) == 0) {
teamsDrivers.push_back(&iter);
}
}
tempTeam.setInstance(teamsDrivers);
teams.push_back(tempTeam);
}
(linking driver to team)
//drivers are linked to teams last, as they are declared first (so I cannot link them to the yet nonexisting teams)
void LinkTeam(vector<Driver>& drivers, vector<Team>& teams) {
for (auto& driverIter : drivers) { //iterate through drivers
for (auto& teamIter : teams) { // iterate through teams
bool found = 0;
for (size_t i = 0; i < teamIter.DriverAmount(); i++) {
if (driverIter.getName() == teamIter.getDriver(i).getName()) {
driverIter.SetTeam(teamIter);
found = 1;
break;
}
}
if (found) { //exit iterating if driver is found
break;
}
}
}
}
Example of use in main.cpp
teams[0].addPoints(10);
drivers[3].getTeam().addPoints(15); //driver 3 is linked to team 0
cout << teams[0].getPoints(); //15
cout << drivers[3].getTeam().getPoints(); //15
teams[0].getDriver(1).addPoints(20); //driver 1 of team 0=driver[3]
drivers[3].addPoints(25);
cout << drivers[3].getPoints(); //25
cout << teams[0].getDriver(1).getPoints(); //25
Thanks for the help in advance.
This is quite simple:
Your getTeam() and getDriver() functions are returning copies of the objects, not references, so the addPoints() are performed on temporary copies and not the real ones.
To fix it, simply change the return types to references (add &):
Team& getTeam();
and
Driver& getDriver();

Segmentation Fault in memcpy operation of a struct

I am adding the header file and cpp file (it has main fucntion).
AuctionPrices.h
#ifndef AuctionPrices_h
#define AuctionPrices_h
/*
*
* class AuctionPrices - maintains Buy Order, Sell Order books
*/
#include <bits/stdc++.h>
#include <map>
//#pragma pack(1)
struct Order
{
char * itemId;
char * auctionId;
int Side;
};
class AuctionPrices
{
public:
virtual int AddNewOrder(char *itemId, char *auctionId, int Side, int Price) = 0;
virtual int DeleteOrder(char *itemId, char *auctionId) = 0;
virtual int Print() = 0;
};
class AuctionPrice_Imp : public AuctionPrices
{
public:
AuctionPrice_Imp();
~AuctionPrice_Imp();
std::map <int, Order, std::greater< int >> BuyMap;
std::map <int, Order, std::less< int >> SellMap;
int AddNewOrder(char *itemId, char *auctionId, int Side, int Price);
int DeleteOrder(char *itemId, char *auctionId);
int Print();
};
#endif
AuctionPrices_Imp.cpp
/**
* Auction Price Class implementation
* Constructor, AddNewOrder, DeleteOrder, Print
*
*/
#include <bits/stdc++.h>
#include <map>
#include "AuctionPrices.h"
using namespace std;
AuctionPrice_Imp::AuctionPrice_Imp()
{
}
AuctionPrice_Imp::~AuctionPrice_Imp()
{
}
int AuctionPrice_Imp::AddNewOrder(char *itemId, char *auctionId, int Side, int Price)
{
Order order;
memcpy(order.itemId, itemId, strlen(itemId)+1);
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
order.Side = Side;
if (Side == 1)
{
BuyMap.insert (std::pair<int,Order>(Price,order));
//buyLevels_.insert( std::pair< OfPrice, Level< OrderEntry > >( price, buyLevel ) );
}
else if (Side == 2)
{
SellMap.insert (std::pair<int,Order>(Price,order));
}
else
{
return 0;
}
return 1;
}
int AuctionPrice_Imp::DeleteOrder(char *itemId, char *auctionId)
{
return 0;
}
int AuctionPrice_Imp::Print()
{
std::map <int,Order,std::greater< int >>::iterator buy_it;
std::map <int,Order,std::less< int >>::iterator sell_it;
// Print Sell Map
for ( sell_it = SellMap.begin();sell_it != SellMap.end(); sell_it++)
{
std::cout << sell_it->first << '\t' << std::endl;
}
// Print Buy Map
for ( buy_it = BuyMap.begin();buy_it != BuyMap.end(); buy_it++)
{
std::cout << buy_it->first << '\t' << std::endl;
}
return 1;
}
int main()
{
AuctionPrice_Imp * auctionPrice_Imp = new AuctionPrice_Imp();
/*
AddNewOrder(“item1”, “auction1”, 1, 100)
AddNewOrder(“item1”, “auction2”, 1, 101)
AddNewOrder(“item2”, “order3”, 1, 99)
AddNewOrder(“item2”, “order4”, 2, 100)
*/
auctionPrice_Imp->AddNewOrder("item1", "auction1", 1, 100);
auctionPrice_Imp->AddNewOrder("item1", "auction2", 1, 101);
auctionPrice_Imp->AddNewOrder("item2", "order3", 1, 99);
auctionPrice_Imp->AddNewOrder("item2", "order4", 2, 100);
auctionPrice_Imp->Print();
}
When I am running the code its giving segmentation fault at the line:
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
Please anyone can help or correct the code.
The functions I am calling are supposed to add the orders to the Maps: BuyMap and SellMap. Once they have added to those map, I am using a print function to print the values.
Order order;
This creates a new Order object. Order does not have a constructor, so none of its class members, itemId, and auctionId, get initialized to point to anything. These pointers are uninitialized, random garbage. Immediately afterwards:
memcpy(order.itemId, itemId, strlen(itemId)+1);
memcpy(order.auctionId, auctionId, strlen(auctionId)+1);
Since neither itemId, nor auctionId, point to sufficient memory that are at least strlen(itemId)+1 or strlen(auctionId)+1 in size, respectively, this results in undefined behavior, and your crash.
In C++, before using a pointer, it is your responsibility to make sure that the pointer is valid, and points to the correct object, objects, or sufficiently-sized memory buffers. C++ will not do that for you, you have to do all that work yourself.
But if your intent is to write modern C++ code, it is much simpler just to use C++ classes, like std::strings instead of plain char * pointers. std::strings automatically handle all these low-level details, manage memory properly, without making it your responsibility to do so. You will find a complete description of std::string and many examples of using it in your C++ textbook.
You should use std::string to avoid having to deal with low level issues of pointers and memory allocation. These are the issues that you are getting wrong in your code. Here's your code rewritten to use std::string
struct Order
{
std::string itemId;
std::string auctionId;
int Side;
};
int AuctionPrice_Imp::AddNewOrder(std::string itemId, std::string auctionId, int Side, int Price)
{
Order order;
order.itemId = itemId;
order.auctionId = auctionId;
order.Side = Side;
See how easy that is? The code to use std::string is no different to the code that handles int.

How to transfer objects from an array of objects to another in C++?

I have an array of objects and I want to transfer the objects to another array. I've written the code bellow to do so but it did not work. It is basically a code where 52 card objects are created in one array and distributed between two arrays.Can anyone help me?
class card
{
public:
string suit;
string value;
void setValue(string v);
void setSuit(string s);
};
void card::setValue(string v)
{
value=v;
}
void card::setSuit(string s)
{
suit=s;
}
int main()
{
string suites[]={"Spades","Hearts","Diamonds","Clubs"};
string values[]={"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
card cards[52];
int i=0;
for(int j=0;j<4;j++){
for(int k=0;k<13;k++){
cards[i].setSuit(suites[j]);
cards[i].setValue(values[k]);
i++;
}
}
card player1_cards[26];
card player2_cards[26];
for(int a=0;a<52;a++){
if(a%2==0){
player1_cards[a]=cards[a];
}
else{
player2_cards[a]=cards[a];
}
}
return 0;
}
If you want every 2nd card to be added to player1_cards and the others to be added to player2_cards you can change your for-loop to:
for(int a=1;a<26;a++) {
player1_cards[a] = cards[2*a];
player2_cards[a] = cards[2*a-1];
}
As Eljay said in the comment to your question your index went past the end of the array.
I tried to compile the code myself and it seems like the following code splits the cards in to two different arrays, althought it is not random (which you might want to add if you are doing a card game).
#include <iostream>
#include <string>
class card
{
public:
std::string suit;
std::string value;
void setValue(std::string v);
void setSuit(std::string s);
std::string printSV();
};
void card::setValue(std::string v)
{
value=v;
}
void card::setSuit(std::string s)
{
suit=s;
}
std::string card::printSV() {
return suit + ": " + value + "\n";
}
int main()
{
std::string suites[]={"Spades","Hearts","Diamonds","Clubs"};
std::string values[]={"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
card cards[52];
int i=0;
for(int j=0;j<4;j++){
for(int k=0;k<13;k++){
cards[i].setSuit(suites[j]);
cards[i].setValue(values[k]);
i++;
}
}
card player1_cards[26];
card player2_cards[26];
for(int a=1;a<26;a++){
player1_cards[a] = cards[2*a];
player2_cards[a] = cards[2*a-1];
// prints the suite and value for each card in player1's and player2's hand.
std::cout << player1_cards[a].printSV();
std::cout << player2_cards[a].printSV();
}
return 0;
}
Outputs Suite: Value for each of the cards in cards[52].
As #Eljay notes, you are trying to access elements past the end of the arrays. If you were to use a debugger to step through your program, you would see this.
However, this is also a lesson for you to be careful of writing raw loops, with a lot of "magic-number" indices, and prefer using pre-existing patterns from the libraries (especially std::algorithm) when relevant. See this talk by Sean Parent about this general principle.
Specifically, you could have written your program as follows:
#include <range/v3/view.hpp>
#include <string>
#include <array>
#include <iostream>
struct card {
std::string suite;
std::string value;
};
std::ostream& operator<<(std::ostream& os, const card& c)
{
return os << c.value << " of " << c.suite;
}
int main()
{
using namespace ranges;
std::array suites {"Spades","Hearts","Diamonds","Clubs"};
std::array values {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
auto cards =
views::cartesian_product(suites, values) |
views::transform([](const auto& suite_and_value) -> card {
return { std::get<0>(suite_and_value), std::get<1>(suite_and_value) };
});
auto num_players { 2 };
auto player1_cards =
cards | views::stride(num_players);
auto player2_cards =
cards | views::drop(1) | views::stride(num_players);
std::cout << "Player 1 got: " << player1_cards << '\n';
std::cout << "Player 2 got: " << player2_cards << '\n';
}
in which case you don't use any loops and any index variables. This uses Eric Niebler's ranges-v3 library. See also this quick reference to understand faster what's going on in this code if you're not familiar with the terms.
See this Live on GodBolt.

C++: Setters and Getters for Arrays

I am struggling to find the correct format for initializing a (private) array within a class and getting/setting the values from outside the class.
My code is semi-functional, but feels awkward in incorrectly formatted.
It is returning only the first element of the array, I want it to return all the contents. Read code comments for additional details.
Note: This is (a very small part of) a project I am working on for school -- an array must be used, not a vector or list.
student.h
class Student {
public:
// Upon researching my issue, I read suggestions on passing pointers for arrays:
void SetDaysToCompleteCourse(int* daysToCompleteCourse[3]);
int* GetDaysToCompleteCourse(); // Ditto # above comment.
private:
int daysToCompleteCourse[3];
student.cpp
#include "student.h"
void Student::SetDaysToCompleteCourse(int* daysToCompleteCourse) {
// this->daysToCompleteCourse = daysToCompleteCourse; returns error (expression must be a modifiable lvalue)
// Feels wrong, probably is wrong:
this->daysToCompleteCourse[0] = daysToCompleteCourse[0];
this->daysToCompleteCourse[1] = daysToCompleteCourse[1];
this->daysToCompleteCourse[2] = daysToCompleteCourse[2];
}
int* Student::GetDaysToCompleteCourse() {
return daysToCompleteCourse;
}
ConsoleApplication1.cpp
#include "pch.h"
#include <iostream>
#include "student.h"
int main()
{
Student student;
int daysToCompleteCourse[3] = { 1, 2, 3 };
int* ptr = daysToCompleteCourse;
student.SetDaysToCompleteCourse(ptr);
std::cout << *student.GetDaysToCompleteCourse(); // returns first element of the array (1).
}
I gave this my best shot, but I think I need a nudge in the right direction.
Any tips here would be greatly appreciated.
I would say:
// student.h
class Student
{
public:
// If you can, don't use numbers:
// you have a 3 on the variable,
// a 3 on the function, etc.
// Use a #define on C or a static const on C++
static const int SIZE= 3;
// You can also use it outside the class as Student::SIZE
public:
void SetDaysToCompleteCourse(int* daysToCompleteCourse);
// The consts are for "correctness"
// const int* means "don't modify this data" (you have a setter for that)
// the second const means: this function doesn't modify the student
// whithout the const, student.GetDaysToCompleteCourse()[100]= 1 is
// "legal" C++ to the eyes of the compiler
const int* GetDaysToCompleteCourse() const; // Ditto # above comment.
Student()
{
// Always initialize variables
for (int i= 0; i < SIZE; i++) {
daysToCompleteCourse[i]= 0;
}
}
private:
int daysToCompleteCourse[SIZE];
// On GCC, you can do
//int daysToCompleteCourse[SIZE]{};
// Which will allow you not to specify it on the constructor
};
// student.cpp
void Student::SetDaysToCompleteCourse(int* newDaysToCompleteCourse)
{
// It's not wrong, just that
// this->daysToCompleteCourse[0] = daysToCompleteCourse[0];
// use another name like newDaysToCompleteCourse and then you can suppress this->
// And use a for loop
for (int i= 0; i < SIZE; i++) {
daysToCompleteCourse[i]= newDaysToCompleteCourse[i];
}
}
const int* Student::GetDaysToCompleteCourse() const
{
return daysToCompleteCourse;
}
// main.cpp
#include <iostream>
std::ostream& operator<<(std::ostream& stream, const Student& student)
{
const int* toShow= student.GetDaysToCompleteCourse();
for (int i= 0; i < Student::SIZE; i++) {
stream << toShow[i] << ' ';
}
return stream;
}
int main()
{
Student student;
int daysToCompleteCourse[3] = { 1, 2, 3 };
// You don't need this
//int* ptr = daysToCompleteCourse;
//student.SetDaysToCompleteCourse(ptr);
//You can just do:
student.SetDaysToCompleteCourse(daysToCompleteCourse);
// On C++ int* is "a pointer to an int"
// It doesn't specify how many of them
// Arrays are represented just by the pointer to the first element
// It's the FASTEST and CHEAPEST way... but you need the SIZE
const int* toShow= student.GetDaysToCompleteCourse();
for (int i= 0; i < Student::SIZE; i++) {
std::cout << toShow[i] << ' ';
// Also works:
//std::cout << student.GetDaysToCompleteCourse()[i] << ' ';
}
std::cout << std::endl;
// Or you can do: (because we defined operator<< for a ostream and a Student)
std::cout << student << std::endl;
}
You can check out it live here: https://ideone.com/DeJ2Nt

C++ Implementing a copy constructor

I am writing some code to implement a deep copy of an object.
Here is my code:
//---------------------------------------------------------------------------
#pragma hdrstop
#include <tchar.h>
#include <string>
#include <iostream>
#include <sstream>
#include <conio.h>
using namespace std;
//---------------------------------------------------------------------------
class Wheel
{
public:
Wheel() : pressure(32)
{
ptrSize = new int(30);
}
Wheel(int s, int p) : pressure(p)
{
ptrSize = new int(s);
}
~Wheel()
{
delete ptrSize;
}
void pump(int amount)
{
pressure += amount;
}
int getSize()
{
return *ptrSize;
}
int getPressure()
{
return pressure;
}
private:
int *ptrSize;
int pressure;
};
class RacingCar
{
public:
RacingCar()
{
speed = 0;
*carWheels = new Wheel[4];
}
RacingCar(int s)
{
speed = s;
}
RacingCar(RacingCar &oldObject)
{
for ( int i = 0; i < sizeof(carWheels)/sizeof(carWheels[0]); ++i)
{
Wheel oldObjectWheel = oldObject.getWheel(i);
carWheels[i]=new Wheel(oldObjectWheel.getSize(),oldObjectWheel.getPressure());
}
}
void Accelerate()
{
speed = speed + 10;
}
Wheel getWheel(int id)
{
return *carWheels[id];
}
void printDetails()
{
cout << carWheels[0];
cout << carWheels[1];
cout << carWheels[2];
cout << carWheels[3];
}
private:
int speed;
Wheel *carWheels[4];
};
#pragma argsused
int _tmain(int argc, _TCHAR* argv[])
{
RacingCar testCar;
testCar.printDetails();
RacingCar newCar = testCar;
newCar.printDetails();
getch();
return 0;
}
//---------------------------------------------------------------------------
For some reason, my C++ builder crashes after compiling this code. Is there anything above that is not correct that would cause this to crash. There is no compile error, the program just crashes.
The problem is:
Wheel *carWheels[4];
and
*carWheels = new Wheel[4];
this only allocates 4 Wheels for carWheels[0]. Along with
return *carWheels[id];
If id is not 0, this will lead to undefined behavior because, as previously stated, only the first element is a valid pointer.
Besides this, the code is horrible. Avoid raw pointers. There are much better alternatives in C++. Use std::vector or std::array where you'd use a C-array, and smart pointers where you'd use raw ones.
Generally in my experience, if my compiler/tool crashes, I'm probably doing something so wrong that it never even occurred to the compiler writers to check for it.
The best way to track down such things is to comment out code until it works again, then slowly bring stuff back in until you find the offending part.
As a design note, I'd say that if it were me, I'd implement a copy constructor for Wheel as well, rather than having to write a complex deep copy constructor for classes like RacingCar that use it.