Why does my code have an "Apple Mach-O Linker Error?" - c++

I get this error when i build the program: Apple Mach-O Linker (ld) Error Linker Command failed with exit code 1. Usually when I try to fix this error, its because the file with the main function is #include-ing a file more than once. However, I do not believe that that is the case this time. I am also notified by X Code that the duplicate symbol _passed in: ranker.o and olympic.o.
//competitor.h
#ifndef __Olympic_Lab__competitor__
#define __Olympic_Lab__competitor__
#include <iostream>
using namespace std;
class Competitor {
char* name = nullptr;
int laneAssignment;
float time;
public:
Competitor(char n[], int lane);
~Competitor();
void setTime(float f);
char* getName(){ return name; }
int getLane(){ return laneAssignment; }
float getTime(){ return time; }
void print(){ cout << name << endl; }
};
#endif
//competitor.cpp
#include "competitor.h"
Competitor::Competitor(char n[], int lane){
name = n;
laneAssignment = lane;
}
Competitor::~Competitor(){
//does nothing for now
}
void Competitor::setTime(float t){
time = t;
}
//ranker.h
#ifndef __Olym__ranker__
#define __Olym__ranker__
#include <vector>
#include "competitor.h"
using namespace std;
int passed = 0;
class Ranker {
bool boolean = true;
public:
vector<Competitor*> rv;
Ranker(int lanes);
~Ranker();
int addList(Competitor* c);
Competitor* getLane(int lane);
Competitor* getFinish(int finish);
int getFilled();
};
#endif
//ranker.cpp
#include "ranker.h"
Ranker::Ranker(int lan){
rv.resize(lan - 1);
for(int i = 0; i <= rv.size(); i++){
rv[i] = nullptr;
}
}
Ranker::~Ranker(){
for(int i = 0; i <= rv.size(); i++){
delete rv[i];
}
}
int Ranker::addList(Competitor *c){
if(c != NULL && passed <= 4){
rv[passed++] = c;
return passed - 1;
}
return 0;
}
Competitor* Ranker::getLane(int lane){
for(int i = 0; i <= rv.size(); i++){
if(rv[i]->getLane() == lane && rv[i] != NULL){
return rv[i];
}
}
return rv[0];
}
Competitor* Ranker::getFinish(int finish){
if(boolean){
Competitor *temp = nullptr;
int highestIndex;
for(int i = rv.size(); i >= 0; i--){
highestIndex = i;
for(int j = i; j >= 0; j--){
if(rv[j] != nullptr && rv[highestIndex] != nullptr){
if(rv[j]->getTime() > rv[highestIndex]->getTime())
highestIndex = j;
}
}
temp = rv[i];
rv[i] = rv[highestIndex];
rv[highestIndex] = temp;
}
delete temp;
temp = *new Competitor*;
boolean = false;
}
return rv[finish - 1];
}
int Ranker::getFilled(){
int filled = 0;
for(int i = 0; i <= rv.size(); i++){
if(rv[i] != NULL){
filled++;
}
}
return filled;
}
//olympic.h
#ifndef _Olympic_Lab__olympic__
#define _Olympic_Lab__olympic__
#include "ranker.h"
#endif
//olympic.cpp
#include "olympic.h"
int main(){
const int lanes = 4;
Ranker rank(lanes);
Competitor* starters[4];
starters[0] = new Competitor("EmmyLou Harris", 1);
starters[1] = new Competitor("Nanci Griffith", 2);
starters[2] = new Competitor("Bonnie Raitt", 3);
starters[3] = new Competitor("Joni Mitchell", 4);
starters[0]->setTime((float)12.0);
starters[1]->setTime((float)12.8);
starters[2]->setTime((float)11.0);
starters[3]->setTime((float)10.3);
for(int i = 0; i < lanes; i++){
rank.addList(starters[i]);
}
cout << "Competitors by lane are:" << endl;
for(int i = 1; i <= lanes; i++)
rank.getLane(i)->print();
cout << "Rankings by finish are:" << endl;
for(int i = 1; i <= lanes; i++)
rank.getFinish(i)->print();
for(int i = 0; i < lanes; i++){
delete starters[i];
}
}
It would be appreciated if someone could assist me in finding exactly what causes this error. Thanks!

If you declare a variable in a header it will be duplicated in every file that includes the header.
So int passed = 0; in ranker.h is going to give you a lot of grief. ranker and olympian both have allocated a different passed and the linker now has no clue which one is the real passed.
So what you probably want is
extern int passed;
in ranker.h to declare that passed will exist at some point, if it doesn't yet, so it doesn't need to be allocated. The compiler will happily carry on and allow you to use passed.
And then in ranker.cpp, declare
int passed = 0;
to allocate passed and satisfy the linker. Now you have only one passed and anyone who includes ranker.h can see and use it.
If you want more than one passed, you have to do something else so that they don't share the same name and scope, but this doesn't look like your goal.
Off topic: resist the urge to put using namespace std;in a header file. It can lead to future problems that can be very hard to debug. More here: Why is "using namespace std" considered bad practice?

Related

Calling two Queue class function in a loop

I have problem with this code of mine. Whenever i call two function of the class, and in those class, there is if-else statement, and print the output on screen, it will only run the if clause of the two functions and not the else. How can i fix this?
For example:
This is my Queue.h file:
#ifndef QUEUE_H
#define QUEUE_H
class Queue {
private:
//private variables
int arr_size;
char *arr;
int head;
int tail;
int count;
public:
Queue(int); //constructor
//functions
int enqueue(char);
int dequeue(char&);
};
#endif
This is my Queue.cpp file:
#include <iostream>
#include "Queue.h"
using namespace std;
Queue::Queue(int size) {
//initializing
arr_size = size;
arr = new char[size];
for (int i = 0; i < arr_size; i++) {
arr[i] = NULL;
}
head = 0;
tail = 0;
count = 0;
}
int Queue::enqueue(char value) {
if (count<arr_size) //if array is not full, execute below
{
arr[tail++] = value; //pass value of first-to-last element in array
count++; //counting the input value
cout << "\nEnqueue Value: "<< arr[tail-1];
return 0;
}
else {
tail = 0;
cout << "\nArray is full. Value cannot be write: " << value;
return -1;
}
}
int Queue::dequeue(char &read_val) {
if (count !=0) { //if array has elements, execute below
read_val = arr[head]; //pass-by-reference the value of first-to-last element in array to parameter of function
cout <<"\nDequeue Value: "<<read_val;
arr[head] = NULL;
count--;
if (head++ == arr_size) {
head = 0;
}
return 0;
}
else if (count ==0) {
cout << "\nArray is empty. Cannot be dequeue";
return -1;
}
}
And this is what my Source file:
#include "Queue.h"
#include <iostream>
using namespace std;
int main() {
int n;
cout << "Please enter the desired size of the array: ";
cin >> n;
char read_val = NULL;
Queue myqueue(n);
char arr[] = "Hello World, this is ELEC3150";
int size = sizeof(arr)-1;
int count = 0;
for (int i = 0; i < 5; i++) {
myqueue.enqueue(arr[count]);
count++;
myqueue.dequeue(read_val);
}
If i enter the size of the array to be less than 5, it must print the error message saying the array is full in the enqueue function and the array is empty in the dequeue function but did not.

C++ Reading From a .txt File + Binary Search + Sorting; Trouble with Classes

So I need to read 10,000 numbers from an input.txt file, and then search to see if it is in the array, and if it isn't there, insert it and increment the frequency value in the frequency array. Then I need to sort the arrays in decreasing order by the frequency array. I know I am missing alot still... but my main question is found in main.cpp. When I reference TermTable.BinarySearch and TermTable.Sort, I get "Error: expected an identifier". Here is my main.cpp file. SO my biggest question is: Why can't I access the methods in the class TermTable??
#include <cstdlib>
#include <iostream>
#include <fstream>
#include "TermTable.h"
using namespace std;
int main(){
const int size = 10000;
int termArray[size];
int frequencyArray[size];
char * charArray = new char[size];
int position = 0;
ifstream fin("input.txt");
if (fin.is_open())
{
cout << "Open" << endl;
while (!fin.eof() && position < size){
fin.get(charArray[position]);
position++;
}
charArray[position - 1] = '\0';
for (int i = 0; charArray[i] != '\0'; i++)
{
termArray[i] = charArray[i];
}
for (int i = 0; termArray[i] != '\0'; i++){
int searchValue = termArray[i];
TermTable.BinarySearch(int termArray, int size, int searchValue);
if (position != -1){ frequencyArray[i] += 1; }
else if (position == -1){
frequencyArray[i] = 0;
}
}
TermTable.Sort(int termArray, int size);
}
else
{
cout << "couldn't open" << endl;
}
return 0;
}
And Here's my specification .cpp file.
#include <iostream>
#include <cstdlib>
#include "TermTable.h"
using namespace std;
int TermTable::BinarySearch(int array[], int size, int searchValue){
int first, last, middle, position; bool found; first = 0; last = size - 1; found = false; position = -1;
while (!found && first <=last)
{
middle = (first + last) / 2;
if (array[middle] == searchValue)
{
found = true;
position = middle;
}
else if (array[middle] > searchValue)
last = middle - 1;
else
first = middle + 1;
}
return position;
}
void TermTable::Sort(int array[], int size){
int temp; bool swapOccurred;
do{
swapOccurred = false;
for (int count = (size-1); count > 0; count--)
{
if (array[count] < array[count - 1])
{
temp = array[count];
array[count] = array[count - 1];
array[count - 1] = temp;
swapOccurred = true;
}
}
} while (swapOccurred);
}
And here is my class file.
#include <cstdlib>
#include <iostream>
using namespace std;
//class specification
class TermTable {
public:
//constructor
TermTable();
//member functions
int BinarySearch(int array[],int size, int searchValue);
void Insert(int value);
void Sort(int array[],int size);
//destructor
~TermTable();
private:
//data
int currentAmount;
};
There are 2 things I found:
The methods BinarySearch() and Sort() are member functions of class TermTable, and not static methods. Hence, you need to instantiate TermTable and then use that object to call these methods.
In main():
TermTable termTableObj;
termTableObj.BinarySearch(...);
...
termTableObj.Sort(...);
When calling a method, you just need to pass the variable name only, and not their types, like:
TermTable termTableObj;
termTableObj.BinarySearch(termArray, size, searchValue);
termTableObj.Sort(termArray, size);
TermTable.BinarySearch(int termArray, int size, int searchValue);
if (position != -1){ frequencyArray[i] += 1; }
else if (position == -1){
frequencyArray[i] = 0;
}
}
TermTable.Sort(int termArray, int size);
I don't think you want the "int" when calling a function. When you define the function you need to define the parameter type but when calling a function I don't think you need it.
The compiler is expecting an identifier as opposed to a reserved word.

Hi, I very confused on why I am getting a compilation error mainly: "Library.cc:(.text+0x27): undefined reference to `PatronArray::PatronArray()'"

this my Library.h file, before the Library used to do All the dirty work: in term of manipulating the arrays and stuff, but now I am trying to make the Library the middle man that just invoke the call that has to do with any array manipulations. My problem is I am trying to have one instance of Patron array, that would hold all the patrons in the Library.
#ifndef LIBRARY_H
#define LIBRARY_H
#include <string>
#include "types.h"
#include "Book.h"
#include "Patron.h"
#include "PatronArray.h"
//class PatronArray
class Library
{
public:
Library();
~Library();
void init();
int addBook(Book*);
int addPatron(Patron*);
int remPatron(int);
int findBook(int, Book**, int*);
int findPatron(string, string, Patron**, int*);
int getMaxCollIndex();
int getMaxPatronsIndex();
Book* getBook(int);
Patron* getPatron(int);
private:
Book* collection[MAX_COLL_SIZE];
PatronArray* patrons;
int maxCollIndex;
int maxPatronsIndex;
};
#endif
This is my Library.cc file
#include "Library.h"
Library::Library()
: maxCollIndex(0)
{
patrons = new PatronArray;
for (int i=0; i<MAX_COLL_SIZE; ++i) {
collection[i] = 0;
}
}
Library::~Library()
{
delete patrons;
for (int i=0; i<maxCollIndex; ++i)
delete collection[i];
}
int Library::getMaxCollIndex() { return maxCollIndex; }
int Library::getMaxPatronsIndex()
{
return patrons->getMaxPatronsIndex();
}
Book* Library::getBook(int index)
{
if (index < 0 || index >= maxCollIndex)
return 0;
return collection[index];
}
Patron* Library::getPatron(int index)
{
return patrons->getPatron(index);
}
void Library::init()
{
Book* newBook;
Patron* newPatron;
newBook = new Book("Ender's Game", "Orson Scott Card", 1985);
addBook(newBook);
newBook = new Book("Dune", "Frank Herbert", 1965);
newBook->setStatus(LOST);
addBook(newBook);
newBook = new Book("Foundation", "Isaac Asimov", 1951);
addBook(newBook);
newBook = new Book("Hitch Hiker's Guide to the Galaxy", "Douglas Adams", 1979);
addBook(newBook);
newPatron = new Patron("Jack", "Shephard");
addPatron(newPatron);
}
int Library::addBook(Book* book)
{
if (maxCollIndex >= MAX_COLL_SIZE - 1) {
return C_NOK;
}
collection[maxCollIndex++] = book;
return C_OK;
}
int Library::addPatron(Patron* patron)
{
// the lbrary is the middle ma that invokesthe calls
//return patronArray->addPatron(patron);
return patrons->addPatron(patron);
}
int Library::remPatron(int index)
{
return patrons->remPatron(index);
}
int Library::findPatron(string fn, string ln, Patron** patron, int* index)
{
return patrons->findPatron(fn,ln,patron,index);
}
int Library::findBook(int id, Book** book, int* index)
{
for (int i=0; i<maxCollIndex; ++i) {
if (collection[i] == 0)
continue;
if (collection[i]->getId() == id) {
*book = collection[i];
*index = i;
return C_OK;
}
}
*book = 0;
*index = -1;
return C_NOK;
}
This is my PatronArray.h that holds all the Patrons registered within the Library.
#ifndef PATRONARRAY_H
#define PATRONARRAY_H
#include "Patron.h"
#include "Book.h"
#include "types.h"
//class Patron;
class PatronArray
{
public:
PatronArray();
~PatronArray();
int addPatron(Patron*);
int remPatron(int);
int findPatron(string, string, Patron**, int*);
int getMaxPatronsIndex();
Patron* getPatron(int);
private:
Patron* patrons[MAX_COLL_SIZE];
int maxPatronsIndex;
};
#endif
and this is the PatronArray.cc file and please, I know there is better way of doing this by doing templating which I currently dont understand yet plus this way helps me understand the whole object oriented style.
#include<iostream>
#include<string>
#include "PatronArray.h"
/*
* Default constructor: recheck this later
*/
PatronArray::PatronArray()
:maxPatronsIndex(0)
{
for (int i = 0; i < MAX_COLL_SIZE; ++i) {
patrons[i] = 0;
}
}
/*
* Destructor: recheck this later
*/
PatronArray::~PatronArray()
{
for (int i = 0; i < maxPatronsIndex; ++i)
delete patrons[i];
}
//get the maxindex
int PatronArray::getMaxPatronsIndex() { return maxPatronsIndex; }
/*
* Adds the given Patron to the given patrons Array
*/
int PatronArray::addPatron(Patron* patron)
{
if (maxPatronsIndex >= MAX_COLL_SIZE - 1) {
return C_NOK;
}
patrons[maxPatronsIndex++] = patron;
return C_OK;
}
/*
* Used for removing a patron in the patrons array
*/
int PatronArray::remPatron(int index)
{
if (index < 0 || index >= maxPatronsIndex)
return C_NOK;
delete patrons[index];
patrons[index] = 0;
return C_OK;
}
/*
* Searches for the patron; if found, sets the contents of the second
* parameter to that patron pointer, sets the contents of the third parameter to
* its index in the collection, and returns C_OK; if not found, sets the
* contents of the second parameter to zero, the theird to -1, and returns C_NOK
*/
int PatronArray::findPatron( string fn, string ln, Patron** patron, int* index)
{
for (int i = 0; i < maxPatronsIndex; ++i) {
if (patrons[i] == 0)
continue;
if (patrons[i]->getFname() == fn && patrons[i]->getLname() == ln) {
*patron = patrons[i];
*index = i;
return C_OK;
}
}
*patron = 0;
*index = -1;
return C_NOK;
}
Patron* PatronArray::getPatron(int index)
{
if (index < 0 || index >= maxPatronsIndex)
return 0;
return patrons[index];
}
I forgot to link my PatronArray.cc to Library.cc in my makefile, thank you Jack!

Reference array from class in an other class

I'm writing a program that converts decimal numbers into binary, octal and hexadecimal. I'm doing each conversion in different class, but i want to use the binary form of the number which is stored in an array(bin[31]) inside the 1st class. Is there a way to use that array in my other classes? My teacher said i should use references, but i don't know how to do it. My files are:
Binary.h
#ifndef BINARY_H
#define BINARY_H
class Binary{
public:
int num_;
static int bin[31];
int i;
int x;
Binary();
void Set(int temp);
int Get();
void ChangeToBinary();
void ChangeToBinaryComplement();
void TwoComplement();
void PrintBinary();
~Binary();
};
# endif
Binary.cpp
#include <stdio.h>
#include <iostream>
#include "Binary.h"
#include "Octal.h"
using namespace std;
Binary::Binary(){
}
void Binary::Set(int temp){
num_ = temp;
}
int Binary::Get(){
return num_;
}
void Binary::ChangeToBinary(){
x = 1;
for (i=0;i<30;i++){
x*=2;
}
for (i = 0; i<31;i++){
if (num_ -x >= 0){
bin[i] = 1;
num_ = num_ -x;
}
else{
kettes[i] = 0;
} x=x/2;
}
}
void Binary::ChangeToBinaryComplement(){
for (i=0;i<31;i++){
if (bin[i] ==0){
bin[i] = 1;
}
else {
bin[i] = 0;
}
}
}
void Binary::TwoComplement(){
for(i=30;i>0;i--){
if(bin[i] == 0){
bin[i] = 1;
break;
} else{
bin[i] = 0;
}
}
}
void Binary::PrintBinary(){
for (i=0;i<31;i++){
cout << bin[i];
}
cout << " " << endl;
}
Binary::~Binary()
{
}
Octal.h
#ifndef OCTAL_H
#define OCTAL_H
class Octal{
private:
int* oct_ = new int[10];
int i;
public:
Octal();
void ConvertToOctal();
void PrintOctal();
~Octal();
};
#endif
Octal.cpp
#include <stdio.h>
#include <iostream>
#include "Binary.h"
#include "Octal.h"
using namespace std;
Octal::Octal()
{
}
void Octal::ConvertToOctal(){
int k = 0;
int z = 0;
int o = 0;
for(i=0;i<31;i++){
if((help[i] ==1) && (k==0)){
z = z + 4;
k = k + 1;
}
else if((help[i] ==1) && (k==1)){
z = z + 2;
k = k + 1;
}
else if((help[i] ==1) && (k==2)){
z = z + 1;
k = k + 1;
}
else{
k = k + 1;
}
if(k==3){
oct_[o]=z;
z=0;
k=0;
o = o + 1;
}
}
}
void Octal::PrintOctal(){
for(i=0;i<10;i++){
cout << oct_[i];
}
}
Octal::~Octal()
{
}
If you have to use your own classes
You can add a method inside the Binary class that lets you get access to the pointer to the array containing the data. The method would probably look like this:
int getData(){
return bin;
}
You can also access the array directly using Binary::bin, which will also give you a pointer to the first element of the array.
It would be much better tho if you changed the array type from int to bool or char. If you want to do it even better - use the vector< bool > template class. It's basically an array of bools. You can read about it in the C++ Reference
If you just need the funcionality
You should really just use the standard manipulators. There is no real reason to reinvent the wheel. The easiest way to do this is by inputting a number into a stream, and outputing it into a string. Like this:
#include<string> // string
#include<sstream> // stringstream
#include<iostream> // cin, cout
#include<iomanip> // setbase
using namespace std;
int main(){
int number;
cin >> number;
stringstream parser;
parser << setbase(16) << number;
string convertedNumber;
parser >> convertedNumber;
cout << endl << convertedNumber << endl;
return 0;
}
Of course you can change the base inside the setbase manipulator.

Crashing when objects are deleted

It's crashing at the very end of the main() function where it needs to delete the starters objects. The error message that pops up when I run the program says: Debug assertion failed! Expression: _BLOCK_IS_VALID(pHead->nBlockUse). How do i fix it from crashing when deleting the starters objects?
#include <iostream>
#include <fstream>
#include "olympic.h"
using namespace std;
ofstream csis;
int main() {
const int lanes = 4;
Ranker rank(lanes);
csis.open("csis.txt");
// First make a list of names and lane assignments.
Competitor* starters[lanes];
starters[0] = new Competitor("EmmyLou Harris", 1);
starters[1] = new Competitor("Nanci Griffith", 2);
starters[2] = new Competitor("Bonnie Raitt", 3);
starters[3] = new Competitor("Joni Mitchell", 4);
// The race is run; now assign a time to each person.
starters[0]->setTime((float)12.0);
starters[1]->setTime((float)12.8);
starters[2]->setTime((float)11.0);
starters[3]->setTime((float)10.3);
// Put everyone into the ranker.
for (int i = 0; i < lanes; i++)
rank.addList(starters[i]);
// Now print out the list to make sure its right.
cout << "Competitors by lane are:" << endl;
csis << "Competitors by lane are:" << endl;
for (int i = 1; i <= lanes; i++)
rank.getLane(i)->print();
// Finally, show how they finished.
cout << "Rankings by finish are:" << endl;
csis << "Rankings by finish are:" << endl;
for (int i = 1; i <= lanes; i++)
rank.getFinish(i)->print();
for (int i = 0; i < lanes; i++)
delete starters[i];
csis.close();
}
ranker.cpp:
#include "ranker.h"
#include "competitor.h"
#include <stdlib.h>
Ranker::Ranker(int lanes) {
athlete = new Competitor*[lanes];
numAthletes = 0;
maxAthletes = lanes;
}
int Ranker::addList(Competitor* starter) {
if (numAthletes < maxAthletes && starter != NULL) {
athlete[numAthletes] = starter;
numAthletes++;
return numAthletes;
}
else
return 0;
}
Competitor* Ranker::getLane(int lane) {
for (int i = 0; i < numAthletes; i++) {
if (athlete[i]->getLane() == lane) {
return athlete[i];
}
}
return NULL;
}
Competitor* Ranker::getFinish(int position) {
switch(position) {
case 1:
return athlete[3];
break;
case 2:
return athlete[2];
break;
case 3:
return athlete[1];
break;
case 4:
return athlete[0];
break;
}
return NULL;
}
int Ranker::getFilled() {
return numAthletes;
}
Ranker::~Ranker() {
delete [] athlete;
}
competitor.h:
#ifndef _COMPETITOR_H
#define _COMPETITOR_H
class Competitor {
private:
char* name;
int lane;
double time;
public:
Competitor(char* inputName, int inputLane);
Competitor();
void setTime(double inputTime);
char* getName();
int Competitor::getLane();
double getTime();
void print();
~Competitor();
};
#endif
competitor.cpp:
#include "competitor.h"
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;
Competitor::Competitor(char* inputName, int inputLane) {
name = inputName;
lane = inputLane;
}
Competitor::Competitor() {
name = 0;
lane = 0;
time = 0;
}
void Competitor::setTime(double inputTime) {
time = inputTime;
}
char* Competitor::getName() {
return name;
}
int Competitor::getLane() {
return lane;
}
double Competitor::getTime() {
return time;
}
void Competitor::print() {
cout << setw(20) << name << setw(20) << lane << setw(20) << setprecision(4) << time << endl;
}
Competitor::~Competitor() {
delete [] name;
}
Call stack:
before crash: http://i.imgur.com/d4sKbKV.png
after crash: http://i.imgur.com/C5cXth9.png
After you've added Competitor class, it seems the problem is that you delete its name in Competitor's destructor. But you assign it from string literal which can't really be deleted. I'm sure the stack trace leading to assertion will prove that.
One way of solving the problem would be using std::string to store the name.
Problem is when deleting the char* value on destructor, which is assigned with const char instead new char. So i have slightly changed the constructor to copy the const char to new char.
Competitor::Competitor(char* inputName, int charlen, int inputLane)
{
name = new char[charlen + 1];
memcpy(name , inputName, charlen );
name [charlen] = '\0';
lane = inputLane;
}