mardi 1 novembre 2016

c++ Undefined reference to function, unless .cpp included instead of .h [duplicate]

This question already has an answer here:

This is for a programming assignment for my Data Structures class, and the program is not complete. I have been testing it in pieces while implementing though and up until now everything was working. I have researched this quite a bit, and all of the answers I have found don't seem to be the problem with my specific situation. My exact errors are: "Undefined reference to 'void Sorter::bubbleSort(int*, int)" "Undefined reference to 'void Sorter::mergeSort(int*, int, int)"

The weird thing is, I originally had included "Sorter.cpp" instead of "Sorter.h" in my PA04.cpp file. At that point things worked fine. I then added the report() function to log some things while sorting, once I tried to compile with that I would get the following: "multiple definition of 'Sorter::report(std::__cxx11::basic_string, std::allocator >, long, long)'"

Researching that I found out that I should be including Sorter.h instead of Sorter.cpp in my PA04.cpp file, However once I change that I get the undefined reference errors above...

Not sure what to do to fix either of the errors. Any help or insight will be greatly appreciated, in addition to any criticism of my code since I know I'm probably not coding in the best way to begin with.

PA04.cpp

#include <iostream>
#include <random>
#include <fstream>
#include "Sorter.cpp"

void createUnsortedData(int size);
std::string getFileName(int size, int i);
void readFileIntoArray(std::string file);
void printSorted(int * array, std::string file, int q);
int *values;    
const int MIN_SIZE = 10;
const int MAX_SIZE = 1000;

int main()
{
    std::string fileName;
    createUnsortedData(MIN_SIZE);
    Sorter sort;

    // Do this outside loop 3 times, used to load quantity value helping to specify which file should be sorted
    for (int n = MIN_SIZE; n <= MAX_SIZE; n*=10)
    {
        sort.MAX_SIZE = n;

        // Do this inside loop 10 times since there are 10 different files within each quantity category to be sorted
        for (int j = 0; j < 10; j++)
        {
            fileName = "./UNSORTED/" + getFileName(n, j);   // Specify the file to be sorted
            values = new int[n];
            readFileIntoArray(fileName);            // Read the randomized file into values array
            sort.bubbleSort(values, n);             // Sort with bubble sort
            readFileIntoArray(fileName);            // Reset array to unsorted state
            sort.mergeSort(values, 0, n - 1);       // Sort with merge sort
            //readFileIntoArray(fileName);          // Reset array to unsorted state
            //Sorter::radixSort(values, quantity);  // Sort with radix sort
            fileName = "./SORTED/" + getFileName(n, j);
            printSorted(values, fileName, n);
            delete [] values;
        }
    }
}

/**
  * @brief Creates 30 files of random integers in the range of 1 - 1000000
  *
  * @pre A pre defined size is passed to the function
  *
  * @post 30 files of randomized integers are created
  */
void createUnsortedData(int size)
{
    std::random_device randNum;
    std::mt19937 gen(randNum());
    std::uniform_int_distribution<> dis(1, 1000001);

    std::string fileName;
    for (int i = 0; i < 10; i++)
    {
        fileName = "./UNSORTED/" + getFileName(size, i);
        std::ofstream fout(fileName.c_str());

        for(int j = 0; j < size; j++)
        {
            unsigned long x;
            x = dis(gen);
            fout << x <<std::endl;
        }

        fout.close();
    }

    if(size < MAX_SIZE)
        createUnsortedData((size * 10));
}

/**
  * @brief Gets a filename
  *
  * @pre A size and file number i are passed to the function
  *
  * @post The file name of the ith file containing the number of integers specified by size is returned
  */
std::string getFileName(int size, int i)
{
    std::string file;
    std::string fileNumber = std::to_string(i+1);
    if(i<9)
        fileNumber = "0" + fileNumber;
    file = std::to_string(size) + "RandomNumbers_" + fileNumber + ".txt";
    return file;
}

void readFileIntoArray(std::string file)
{
    int i = 0;
    std::string line;
    std::ifstream fin(file.c_str());
    if (fin.is_open())
    {
        while (getline(fin, line))
        {
            if (line != "")
            {
                values[i] = std::stoi(line);
                i++;
            }
        }
    }
    fin.close();
}

void printSorted(int * array, std::string file, int q)
{
    std::ofstream fout(file);

    for(int i = 0; i < q; i++)
    {
        fout << array[i] << std::endl;
    }

    fout.close();
}

Sorter.cpp

#include <string>
#include <ctime>
#include <iomanip>
#include "Sorter.h"

template <class ItemType>
void Sorter::bubbleSort(ItemType valueArray[], int n)
{
    time(&startTime);
    bool sorted = false;
    int pass = 1;
    while (!sorted && (pass < n))
    {
        // At this point, valueArray[n+1-pass...n-1] is sorted
        // and all of its entries are > the entries in valueArray[0...n-pass]
        sorted = true;  // Assume sorted
        for (int index = 0; index < n - pass; index++)
        {
            // At this point, all entries in valueArray[0...index-1]
            // are <= valueArray[index]
            int nextIndex = index + 1;
            if (valueArray[index] > valueArray[nextIndex])
            {
                // Exchange entries
                std::swap(valueArray[index], valueArray[nextIndex]);
                sorted = false; // Signal exchange
            }   // end if
        }   // end for
        // Assertion: valueArray[0...n-pass-1] < valueArray[n-pass]

        pass++;
    }   // end while
    time(&finishTime);
    //report("Bubble sort", startTime, finishTime);
}   // end bubbleSort

template <class ItemType>
void Sorter::merge(ItemType valueArray[], int first, int mid, int last)
{
    ItemType tempArray[MAX_SIZE];   // Temporary array

    // Initialize local indices to indicate the subarrays
    int first1 = first;     // Beginning of first subarray
    int last1 = mid;        // End of first subarray
    int first2 = mid + 1;   // Beginning of second subarray
    int last2 = last;       // End of second subarray

    // While both subarrays are not empty, copy the
    // smaller item into the temporary array
    int index = first1;
    while ((first1 <= last1) && (first2 <= last2))
    {
        // At this point, tempArray[first...index-1] is in order
        if (valueArray[first1] <= valueArray[first2])
        {
            tempArray[index] = valueArray[first1];
            first1++;
        }
        else
        {
            tempArray[index] = valueArray[first2];
            first2++;
        }   // end if
        index++;
    }   // end while
    // Finish off first subarray if necessary
    while (first1 <= last1)
    {
        // At this point, tempArray[first...index-1] is in order
        tempArray[index] = valueArray[first1];
        first1++;
        index++;
    }   // end while
    // Finish off the second subarray if necessary
    while (first2 <= last2)
    {
        // At this point, tempArray[first...index-1] is in order
        tempArray[index] = valueArray[first2];
        first2++;
        index++;
    }   // end while

    // Copy the result back into the original array
    for (index = first; index <= last; index++)
        valueArray[index] = tempArray[index];
}   // end merge

template <class ItemType>
void Sorter::mergeSort(ItemType valueArray[], int first, int last)
{
    time(&startTime);
    if (first < last)
    {
        // Sort each half
        int mid = first + (last - first) / 2;   // index of midpoint

        // Sort left half valueArray[first...mid]
        mergeSort(valueArray, first, mid);

        // Sort right half valueArray[mid+1...last];
        mergeSort(valueArray, mid + 1, last);

        // Merge the two halves
        merge(valueArray, first, mid, last);
    }   // end if
    time(&finishTime);
    //report("Merge sort", startTime, finishTime);
}   // end mergeSort

template <class ItemType>
void Sorter::radixSort(ItemType valueArray[], int n)
{
}

void Sorter::report(std::string sortName, time_t start, time_t finish)
{ 
  struct tm * begin;
  struct tm * end;
  std::string completionTime = std::to_string(difftime(finish, start)) + " seconds";
  char buffer [80];

  begin = localtime (&start);
  end = localtime (&finish);

    logOutput.open("sort.log.txt", std::ofstream::app);
    logOutput << std::setw(25) << sortName;
    strftime (buffer,80,"%X",begin);
    logOutput << std::setw(25) << buffer;
    strftime (buffer,80,"%X",end);
    logOutput << std::setw(25) << buffer;
    logOutput << std::setw(25) << completionTime;
    logOutput << std::setw(25) << swapCount;
    logOutput << std::setw(25) << comparisonCount << std::endl;
    logOutput.close();

    // Reset swap and comparison counters for next use
    swapCount = 0;
    comparisonCount = 0;
}

Sorter.h

#include <fstream>

/**
  * @file Sorter.h
  *
  * @brief Specification file for Sorter
  *
  * @author Adrian Davis 
  *
  * @details Specifies all member functions of the Sorter class
  * 
  * @version 1.00
  *
  * @note All member functions are declared static and therefore can be called without instantiating an object of this class
  */
class Sorter
{
public:
    int comparisonCount = 0;
    int swapCount = 0;
    int MAX_SIZE = 0;
    time_t startTime;
    time_t finishTime;
    std::ofstream logOutput;

    /**
      * @brief Bubble sort
      *
      * @pre An unsorted file of integers is passed to the function
      *
      * @post The integers in the file are sorted and output to a sorted file
      */
    template <class ItemType>
    void bubbleSort(ItemType valueArray[], int n);

    /**
      * @brief Merges two halves of an array
      *
      * @pre An unsorted file of integers is passed to the function
      *
      * @post The integers in the file are sorted and output to a sorted file
      */
    template <class ItemType>
    void merge(ItemType valueArray[], int first, int mid, int last);

    /**
      * @brief Merge sort
      *
      * @pre An unsorted file of integers is passed to the function
      *
      * @post The integers in the file are sorted and output to a sorted file
      */
    template <class ItemType>
    void mergeSort(ItemType valueArray[], int first, int last);

    /**
      * @brief Radix sort
      *
      * @pre An unsorted file of integers is passed to the function
      *
      * @post The integers in the file are sorted and output to a sorted file
      */
    template <class ItemType>
    void radixSort(ItemType valueArray[], int n);

    void report(std::string sortName, time_t start, time_t finish);

};

and my makefile looks like this:

CC = g++
DEBUG = -g
CFLAGS = -Wall -c $(DEBUG) -g
LFLAGS = -Wall $(DEBUG)


SortTest : Sorter.o PA04.o 
    $(CC) $(LFLAGS) -std=c++11 -o SortTest Sorter.o PA04.o

Sorter.o : Sorter.cpp Sorter.h
    $(CC) $(CFLAGS) -std=c++11 Sorter.cpp

PA04.o : PA04.cpp Sorter.h
    $(CC) $(CFLAGS) -std=c++11 PA04.cpp

clean :
    rm *.o SortTest
    rm -rf UNSORTED/* 
    rm -rf SORTED/*

Aucun commentaire:

Enregistrer un commentaire