CodeBlocks Compiler Giving "Undefined Reference" Error Over Usage of a Function Declared in My Header File

178 Views Asked by At

I'm getting the following error when trying to build and run my C++ Project:

||=== Build: Debug in CS II (compiler: GNU GCC Compiler) ===|

obj\Debug\main.o||In function 'main':|
|30|undefined reference to '(anonymous namespace)::deleteRepeats(char*)'||

|error: ld returned 1 exit status|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

My code is as follows for each file (I wouldn't be surprised if a lot is buggy or just plain wrong, as I haven't been able to test it at all and my focus has been on remedying that):

main.cpp:

#include <iostream>
#include "implementation.hpp"

int main()
{
    char originalArray[SIZE];
    originalArray[0] = 'a';
    originalArray[1] = 'b';
    originalArray[2] = 'b';
    originalArray[3] = 'c';
    originalArray[4] = 'a';
    originalArray[5] = 'c';
    originalArray[6] = 'a';
    originalArray[7] = 'c';
    originalArray[8] = 'b';
    originalArray[9] = 'c';
    char *noRepeats;
    noRepeats = deleteRepeats(&(originalArray[0]));
    std::cout << noRepeats;
    return 0;

}

implementation.hpp:

#ifndef IMPLEMENTATION_HPP
#define IMPLEMENTATION_HPP
namespace
{
    const int SIZE = 10;
    char* deleteRepeats(char*);
}
#endif

implementation.cpp:

#include "implementation.hpp"

char* deleteRepeats(char* array_to_edit)
{
    char new_array[SIZE];
    int num_of_unique_letters_seen = 0;
    for (int letter = 0; letter < SIZE; letter++)
    {
        bool already_exists = false;
        for (int letter_seen = 0; letter_seen < num_of_unique_letters_seen; letter_seen++)
        {
            if (array_to_edit[letter] == new_array[letter_seen])
            {
                already_exists = true;
            }
        }
        if (!already_exists)
        {
            new_array[num_of_unique_letters_seen] = array_to_edit[letter];
            num_of_unique_letters_seen++;
        }
    }
    return &new_array[0];
}

I was prompted to ask this question in the comments of the answer to this question, which is very similar, but the accepted answer was already completed in my project when the issue arose.

Code where the namespace is given a name:

main.cpp:

#include <iostream>
#include "implementation.hpp"

int main()
{
    char originalArray[dts::SIZE];
    originalArray[0] = 'a';
    originalArray[1] = 'b';
    originalArray[2] = 'b';
    originalArray[3] = 'c';
    originalArray[4] = 'a';
    originalArray[5] = 'c';
    originalArray[6] = 'a';
    originalArray[7] = 'c';
    originalArray[8] = 'b';
    originalArray[9] = 'c';
    char *noRepeats;
    noRepeats = dts::deleteRepeats(&(originalArray[0]));
    std::cout << noRepeats;
    return 0;

}

implementation.cpp:

#include "implementation.hpp"

char* deleteRepeats(char* array_to_edit)
{
    char new_array[dts::SIZE];
    int num_of_unique_letters_seen = 0;
    for (int letter = 0; letter < dts::SIZE; letter++)
    {
        bool already_exists = false;
        for (int letter_seen = 0; letter_seen < num_of_unique_letters_seen; letter_seen++)
        {
            if (array_to_edit[letter] == new_array[letter_seen])
            {
                already_exists = true;
            }
        }
        if (!already_exists)
        {
            new_array[num_of_unique_letters_seen] = array_to_edit[letter];
            num_of_unique_letters_seen++;
        }
    }
    for (int letter = 0; letter < dts::SIZE; letter++)
    {
        array_to_edit[letter] = new_array[letter];
    }
    return array_to_edit;
}

implementation.hpp:

#ifndef IMPLEMENTATION_HPP
#define IMPLEMENTATION_HPP
namespace dts
{
    const int SIZE = 10;
    char* deleteRepeats(char*);
}
#endif
2

There are 2 best solutions below

0
infinitezero On BEST ANSWER

The idea of a namespace is to resolve conflicts if e.g. functions happen to have the same name. Kind of like surnames for people, to tell John Bakerson and John Miller apart from each other.

So one John lives in the namespace Bakerson and the other in namespace Miller.

If you use namespaces, always tell the compiler which namespace your function belongs to.

// .hpp

namespace Bakerson {
  void John();
}

namespace Miller {
  void John();
}

// .cpp

namespace Bakerson {
  void John(){
    std::cout << "I'm John Bakerson.\n";
  }
}

namespace Miller {
  void John(){
    std::cout << "I'm John Miller.\n";
  }
}
0
Vlad from Moscow On

A functon declared in an unnamed namespace has internal linkage. So you need to define it in each compilation unit.

Otherwise declare it in a named namespace.

From the C++17 Standard (6.5 Program and linkage)

4 An unnamed namespace or a namespace declared directly or indirectly within an unnamed namespace has internal linkage. All other namespaces have external linkage. A name having namespace scope that has not been given internal linkage above has the same linkage as the enclosing namespace if it is the name of

//... (4.2) — a function; or

Also pay attention to that you placed the function definition in the global namespace but declared in the enclosed unnamed namespace.

And one more remark. The first your function definition is invald.

char* deleteRepeats(char* array_to_edit)
{
    char new_array[SIZE];

    //...
    return &new_array[0];
}

You are returning a pointer to a local array that will not be alive after exiting the function. Dereferencing such a pointer invokes undefined behavior.

Alsp this statement

std::cout << noRepeats;

also invokes undefined behavior because the array does not comntain a string.

Your approach with an auxiliary array is ineffcent and even wrong. This for loop

for (int letter = 0; letter < dts::SIZE; letter++)
{
    array_to_edit[letter] = new_array[letter];
}

fills the array array_to_edit not only with unique letters due to the conditon of the loop letter < dts::SIZE.

The function should deal with strings.