1

I am somewhat new to C++ and and when I try to run the following code

main.cpp:

#include <iomanip>
#include <string>
#include <limits>
#include "console.h"

using namespace std;

double calculate_future_value(double monthly_investment, double yearly_interest_rate, int years);

int main()
{
    cout << "The Future Value Calculator\n\n";

    char choice = 'y';
    while (tolower(choice) == 'y')
    {
        cout << "INPUT\n";
        double monthly_investment =
            console::get_double("Monthly Investment:   ", 0, 10000);
        double yearly_rate =
            console::get_double("Yearly Interest Rate: ", 0, 30);
        int years =
            console::get_int("Years                 ", 0, 100);
        cout << endl;

        double future_value = calculate_future_value(monthly_investment,
            yearly_rate, years);

        cout << "OUTPUT\n"
             << fixed << setprecision(2)
             << "Monthly Investment:   " << monthly_investment << "\n"
             << fixed << setprecision(1)
             << "Yearly Interest Rate: " << yearly_rate << "\n"
             << "Years:                " << future_value << "\n\n"
             << "Future Value:         " << future_value << "\n\n";

        choice = console::get_char("Continue? (y/n): ");
    }
    cout << "Bye!\n\n";
}

double calculate_future_value(double monthly_investment, double yearly_interest_rate, int years)
{
    double monthly_rate = yearly_interest_rate / 12 / 100;
    int months = years * 12;

    double future_value = 0;
    for (int i = 0; i < months; ++i)
    {
        future_value = (future_value + monthly_investment) *
            (i + monthly_rate);
    }
    return future_value;
}

and

console.h:

#define PANDA_CONSOLE_H

#include <string>
#include <limits>

namespace console
{
    double get_double(std::string prompt,
            double min = std::numeric_limits<double>::min(),
            double max = std::numeric_limits<double>::max());
    int get_int(std::string prompt,
        int min = std::numeric_limits<int>::min(),
        int max = std::numeric_limits<int>::max());
    char get_char(std::string prompt, 
        bool add_blank_line = true);
}
#endif

I would get the following error

Undefined symbols for architecture x86_64:
  "console::get_double(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, double, double)", referenced from:
      _main in main-f6ee4e.o
  "console::get_int(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, int, int)", referenced from:
      _main in main-f6ee4e.o
  "console::get_char(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool)", referenced from:
      _main in main-f6ee4e.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I've tried moving the definition of calculate_future_value() after using namespace std; and before double calculate_future_value(double monthly_investment, double yearly_interest_rate, int years); and because that didn't work, I am now confused to what I need to do. Please help. Thank You!

  • This might help: https://stackoverflow.com/q/12573816/9254539. Looks like your linker can't find the definition of the `console` classes. – eesiraed Apr 04 '20 at 04:45
  • Are you failing to compile `console.cpp` or include it's object file in your compile string? Your linker is telling you is sees a symbol, e.g. `console::get_double(...` **declared**, but that symbol isn't **defined**. Do you have a `console.cpp` or a `libconsole.so` library somewhere? – David C. Rankin Apr 04 '20 at 04:45
  • Actually no. I did not create a console.cpp file. Let me try it... – Panda Gaming23 Apr 04 '20 at 04:54
  • @DavidC.Rankin, I created a console.cpp file and it did not seem to work. – Panda Gaming23 Apr 04 '20 at 05:53
  • You have to actually define the member function, e.g. `console::get_double (std::string prompt, double min, double max) { /* does something with prompt, min & max */ }` so that the function is **defined**. A **declaration** simply tells the compiler that the symbol will be defined elsewhere. A **definition** actually reserves space for and provides the functionality for what that symbol means. So you have the member-function **declaration** in your class. What's missing is the **definition** of the function (i.e. the guts of the function) – David C. Rankin Apr 04 '20 at 06:15

1 Answers1

0

Where you are confused is in the difference between the function declaration and the function definition. In your file console.h you define the namespace console and you declare the functions:

#ifndef PANDA_CONSOLE_H

#include <string>
#include <limits>

namespace console
{
    double get_double(std::string prompt,
            double min = std::numeric_limits<double>::min(),
            double max = std::numeric_limits<double>::max());
    int get_int(std::string prompt,
        int min = std::numeric_limits<int>::min(),
        int max = std::numeric_limits<int>::max());
    char get_char(std::string prompt, 
        bool add_blank_line = true);
}
#endif

(note: your header-guard should be #ifndef PANDA_CONSOLE_H so that if PANDA_CONSOLE_H is NOT yet defined, the following information is included. [but good job on thinking to include a header-guard to prevent multiple inclusions of the function declarations if you include console.h in more than one source file])

For every function Declaration -- there must be a corresponding function Definition

When you declare a function, you are simply telling the compile that a function with this name (symbol) will be defined later -- but you make that function available from the point of the declaration forward in that source file.

When you define the function, the compiler reserves space for it and provides the address for where the compiled code for that function be found. During linking, any time that function is used in your source files, it will resolve to the address where the compiled code for that function actually resides.

If you declare the function, but fail to define the function, then when the linker attempts to locate the code that goes with the declaration, it can't find it and will issue the error similar to:

Undefined symbols for (insert missing function name here)

In your case you need to write a console.cpp that contains the definition for each of the functions you declare in consile.h. For example (and this is only an example with no effort made to have the functions exactly match what you do with them in main()), you could write the following console.cpp to define each of the function, e.g.

#include "console.h"
#include <iostream>

double console::get_double(std::string prompt, double min, double max)
{
    double value = 0;

    std::cout << prompt;

    if (!(std::cin >> value)) {
        std::cerr << "error: invalid double value or EOF.\n";
        return 0;
    }
    if (value < min || max < value) {
        std::cerr << "error: value out of range.\n";
        return 0;
    }

    return value;
}

int console::get_int(std::string prompt, int min, int max)
{
    int value = 0;

    std::cout << prompt;

    if (!(std::cin >> value)) {
        std::cerr << "error: invalid integer value or EOF.\n";
        return 0;
    }
    if (value < min || max < value) {
        std::cerr << "error: value out of range.\n";
        return 0;
    }

    return value;
}

char console::get_char(std::string prompt, bool add_blank_line)
{
    char value = 0;

    std::cout << prompt;

    if (!(std::cin >> value)) {
        std::cerr << "error: EOF or unrecoverable error\n";
        return 0;
    }

    if (add_blank_line)
        std::cout.put('\n');

    return value;
}

(note: I #include <iostream> in console.cpp just for the std::cin, std::cout and std::cerr calls)

Compile

You can then compile your project with:

$ g++ -Wall -Wextra -pedantic -Wshadow -std=c++11 -Ofast console.cpp -o main main.cpp

or

$ clang++ -Wall -Wextra -pedantic -Wshadow -std=c++11 -Ofast console.cpp -o main main.cpp

Then your can run your ./main program (which produces very wrong output based on my made-up function definitions)

Example Use/Output

$ ./main
The Future Value Calculator

INPUT
Monthly Investment:   123.45
Yearly Interest Rate: 12.4
Years                 4

OUTPUT
Monthly Investment:   123.45
Yearly Interest Rate: 12.4
Years:                90457540156111170020897362009600300274844235338297210119913472.0

Future Value:         90457540156111170020897362009600300274844235338297210119913472.0

Continue? (y/n): n

Bye!

Note: I suggestion you change the yearly_rate to years in OUTPUT so the years are shown correctly:

         << "Years:                " << years << "\n\n"

The point being, that for every function declaration there must be a corresponding function definition to allow the linker to match the symbol used in your code with the actual code for that function. Let me know if that fills in the missing pieces, and if not, I'm happy to help further.

(if you stand behind the payout calculated by your program, I have $123.45 to invest)

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85