Defining function with arrays in different files - c++

I want to define a function in a separate C++ file. The function takes in array as an argument.
These are my files.
selectionsort.cpp
#include "selectionsort.hpp"
int selectionsort(int a[]){
int length{};
length = std::size(a);
for(int i{0}; i < length; ++i){
int smallestIndex{i};
for(int j{i+1}; j < length; ++j){
if(a[j] < a[smallestIndex]){
smallestIndex = j;
};
};
std::swap(a[smallestIndex], a[i]);
};
return 0;
};
selectionsort.hpp
#ifndef selectionsort_hpp
#define selectionsort_hpp
int selectionsort(int []);
#endif /* selectionsort_hpp */
main.cpp
#include "io.hpp"
#include "monsters.hpp"
#include "selectionsort.hpp"
#include <iostream>
#include <iterator>
int main(){
int a[]{ -1, -100, 0, 10, 100, -2, 2, 10000, 45, -10000};
selectionsort(a);
std::cout << a[0] << '\n';
std::cout << a[1] << '\n';
return 0;
};
Xcode shows the following error when I run the program.
Undefined symbols for architecture x86_64:
"selectionsort(int*)", referenced from:
_main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Undefined symbol: selectionsort(int*)
However if I put the function definition of selectionsort.cpp inside the main.cpp file, everything works perfectly. I dont understand what is the problem here.

Your .cpp file contains an error that should not compile. As such, I suspect you are not building it in your current setup at all. That would explain why the object code is not being linked into your application, and the linker is unsatisfied.
If you do separate compilation, i.e.
g++ a.cpp -c
g++ b.cpp -c
Now you have two object files, a.o and b.o. To produce a binary, you must link them together:
g++ a.o b.o -o myprogram
In your code you are trying to pass an array:
int selectionsort(int a[]){
int length{};
length = std::size(a);
...
And you simply can't do that. The array decays to a pointer when passed to a function, and you can't call std::size on a pointer. This won't compile, because it has lost array information about the argument (which was encoded in its array type) and cannot determine its size when it is just a pointer. It has NO IDEA how big your array is when inside the function. The only way you could make this work is to change the code and pass in the size of the array along with your array. This is a common need, so there are span classes out there, and one was added to c++20, which basically bundles a pointer and a size together and you might consider using one of those.
If you fix your build system to build all of your code, then you fix the c++ error above (including changing your header declaration to match), then you link all your object code together, that may fix the issue you're seeing.

Related

Separate header file and its logic in c++ [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 5 years ago.
Please make me understand how header files works in C++. I am using osx and g++ compiler. I have
main.cpp
#include<iostream>
#include "myfunc.hpp"
using namespace std;
int main() {
square(10);
return 0;
}
myfunc.hpp
#ifndef MYFUNC_HPP_
#define MYFUNC_HPP_
/*
void square(int x) {
std::cout << x * x << std::endl;
};
*/
void square(int);
#endif // MYFUNC_HPP_
myfunc.cpp
#include<iostream>
#include "myfunc.hpp"
using namespace std;
void square(int x) {
cout << x * x << endl;
}
Now when I am trying to compile using g++ main.cpp , its giving
Undefined symbols for architecture x86_64:
"square(int)", referenced from:
_main in main-088331.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Because it is not able to find the function definition of square that is defined in myfunc.cpp.
But, if I defined square function in header file, it works because now it finds the function definition.
I want to use the function defined in myfunc.cpp in main.cpp, so I am using the header file myfunc.hpp. How can I achieve this? Am I doing something wrong here? Maybe my concept is not that clear about headers since I am new to C++ programming.
When you call g++ main.cpp, the compiler will try to compile and link the program, yet for linking, it lacks the source- or object file containing the definition of square. So it could compile main.cpp based on the function prototype given in the header file, yet it cannot link then.
To just compile main.cpp write
g++ -c main.cpp
To compile and link the complete program write:
g++ main.cpp myfunc.cpp
For more details concerning programs comprising several translation units confer, for example, this link.

CodeBlocks not building my project

Every time I click the 'run' or 'build and run' options in CodeBlocks for Mac OSX I get this dialogue:
I've checked Project > Properties > Build targets, which is what some forum posts said I should do, and all the files are checked but I keep getting the same popup.
This is my build log:
-------------- Build: Release in printarray (compiler: GNU GCC Compiler)---------------
g++ -o bin/Release/printarray obj/Release/arrays.o obj/Release/main.o -s
ld: warning: option -s is obsolete and being ignored
ld: duplicate symbol _anMyArray in obj/Release/main.o and obj/Release/arrays.o for architecture x86_64
collect2: ld returned 1 exit status
and these are my build messages:
These are the files, though I'm not sure if the content has anything to do with the problem (I made sure both Debug and Release were checked when I created the header and function definitions):
main.cpp
#include <iostream>
#include "arrays.h"
int main()
{
using namespace std;
PrintArray(anMyArray);
return 0;
}
arrays.cpp
#include <iostream>
#include "arrays.h"
void PrintArray(int anArray[])
{
using namespace std;
int nElements = sizeof(anArray) / sizeof(anArray[0]);
for (int nIndex=0; nIndex < nElements; nIndex++)
cout << anArray[nIndex] << endl;
}
arrays.h
#ifndef ARRAYS_H
#define ARRAYS_H
int anMyArray[9] = { 4, 6, 7, 3, 8, 2, 1, 9, 5 };
void PrintArray(int anArray[]);
#endif // ARRAYS_H
Any help?
It's because you define the variable anArray in the header file. When its included in two translation units it's defined twice, giving you the duplicate symbol error.
Just declare it in the header file
extern int anMyArray[9];
and define it in one (and only one) source file.
You declare anMyArray in your header file and then include it in both your cpp files, which means your variable is getting declared twice because of header expansion.
Move it to your main.cpp file.
I solved this question by the way below
Settings->Complier...->Toolchain executables
and click the button "Auto-detect"
click "ok"
the problem solved

How to compile a C++ program via Terminal Mac

I have a question on how to compile a C++ program in Terminal Mac. My program has a header file and a main file. I know that I can't compile both the header file and the main file. and just to compile the main file. I also know that I need to create a name for storing the compiled file. Here is my compile command that I used g++ -o execute1 main.cpp and I get this:
Undefined symbols for architecture x86_64:
"add(int, int)", referenced from:
_main in main-f2nZvj.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
How can I fix this? Any help will be greatly appreciated. If it helps, below is my code for the two files:
add.h:
int add(int x, int y);
main.cpp:
#include <iostream>
#include "add.h"
int main(){
using namespace std;
cout << "The sum of 9 and 9 is " << add(9, 9) << endl;
return 0;
}
You need an add.cpp file that implements your add() function, then you can compile the whole thing as:
$ g++ -Wall main.cpp add.cpp -o execute1
This line:
int add(int x, int y);
in your add.h just tells the compiler that somewhere, there's a function called add that takes two integers and returns an integer. Having this and this alone will let the compiler leave you alone when you use this add function in files that #include "add.h". The compiler doesn't have to know exactly what the function does, it just needs to know what parameters it accepts and what the function returns. It doesn't bother looking for the function body until it actually goes to compile the function.
In order for this to properly compile, you need to include a function body for your add function in add.cpp. Even just this will work:
int add(int x, int y) {
return 1;
}
This will allow the program to compile because now the compiler know what code it's supposed to execute when it gets to your call to the add function within main.
This will work, as a minimum, as a placeholder until you're ready to actually write the exact logic you want this function to contain. But until this function body exists, you won't be able to compile (unless you remove all the other references to the function).

Undefined symbols for architecture i386:

I've recently moved over to a mac, and am struggling using the command line compilers. I'm using g++ to compile, and this builds a single source file fine. if I try to add a custom header file, when I try to compile using g++ I get undefined symbols for architecture i386. The programs compile fine in xCode however. Am I missing something obvious?
tried using g++ -m32 main.cpp... didn't know what else to try.
Okay, The old code compiled... Have narrowed it down to my constructors.
class Matrix{
public:
int a;
int deter;
Matrix();
int det();
};
#include "matrix.h"
Matrix::Matrix(){
a = 0;
deter = 0;
}
int Matrix::det(){
return 0;
}
my error is
Undefined symbols for architecture x86_64:
"Matrix::Matrix()", referenced from:
_main in ccBWK2wB.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
my main code has
#include "matrix.h"
int main(){
Matrix m;
return 0;
}
along with the usual
It looks like you’ve got three files:
matrix.h, a header file that declares the Matrix class;
matrix.cpp, a source file that implements Matrix methods;
main.cpp, a source file that defines main() and uses the Matrix class.
In order to produce an executable with all symbols, you need to compile both .cpp files and link them together.
An easy way to do this is to specify them both in your g++ or clang++ invocation. For instance:
clang++ matrix.cpp main.cpp -o programName
or, if you prefer to use g++ — which Apple haven’t updated in a while, and it looks like they won’t in the foreseeable future:
g++ matrix.cpp main.cpp -o programName
is not the case here, but it may happen to be the you forget to put the class name with ::
for example:
a good format:
foo.h
class Foo{
public:
Foo();
void say();
private:
int x;
};
foo.cpp
Foo::Foo(){
this->x = 1;
}
void Foo::say(){
printf("I said!\n");
}
a bad format
foo.h
class Foo{
public:
Foo();
void say();
private:
int x;
}
foo.cpp
Foo::Foo(){
this->x = 1;
}
//I always mistake here because I forget to put the class name with :: and the xcode don't show this error.
void say(){
printf("I said!\n");
}
Did you actually define the Box constructor somewhere? (like Line.cpp)

separating interface and implemention with normal functions

this seems like it should be pretty simple, I'm probably leaving something simple out.
this is the code I'm trying to run. it is 3 files, 2*cpp and 1*header.
this wont run on code blocks, I'm trying to see what I'm missing!
these are the errors given:
obj\Debug\main.o||In function `main':|
|9|undefined reference to `generateArray(int*, int)'|
|11|undefined reference to `reverseOrder(int*, int*, int)'|
|13|undefined reference to `displayArray(int*, int*, int)'|
// lab6.h
#ifndef LAB6_H_INCLUDED
#define LAB6_H_INCLUDED
int const arraySize = 10;
int array1[arraySize];
int array2[arraySize];
void generateArray(int[], int );
void displayArray(int[], int[], int );
void reverseOrder(int [],int [], int);
#endif // LAB6_H_INCLUDED
// lab6.cpp
#include "lab6.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <iomanip>
using std::cout; using std::endl;
using std::rand; using std::srand;
using std::time;
using std::setw;
void generateArray(int array1[], int arraySize)
{
srand(time(0));
for (int i=0; i<10; i++)
{
array1[i]=(rand()%10);
}
}
void displayArray(int array1[], int array2[], int arraySize)
{
cout<<endl<<"Array 1"<<endl;
for (int i=0; i<arraySize; i++)
{
cout<<array1[i]<<", ";
}
cout<<endl<<"Array 2"<<endl;
for (int i=0; i<arraySize; i++)
{
cout<<array2[i]<<", ";
}
}
void reverseOrder(int array1[],int array2[], int arraySize)
{
for (int i=0, j=arraySize-1; i<arraySize;j--, i++)
{
array2[j] = array1[i];
}
}
// and finally main.cpp
#include "lab6.h"
int main()
{
generateArray(array1, arraySize);
reverseOrder(array1, array2, arraySize);
displayArray(array1, array2, arraySize);
return 0;
}
Concluding from the linker's error messages, it seems that you haven't given the linker both object files, and it cannot find what you defined in lab6.cpp. I don't know CodeBlocks, so I don't know how you would have to setup your project so that the linker gets passed all the object files.
Most compilers, however, would invoke the linker with all the object files they generate, so manually invoking the compiler
cc lab6.cpp main.cpp
(substituting your compiler for "cc") might do.
Anyway, once you managed that, you will still have linker errors, because your arrays are defined in the header, which makes them end up in two translation units. The linker will complain about duplicate symbols then.
Other than that, I'd criticize that
you use global variables instead of local ones (once you fixed that, they are also not defined in two translation units anymore),
the code would blow up if you changed arraySize (because you haven't used it everywhere),
you use int to specify the size of the arrays instead of std::size_t and
you use C arrays instead of C++' containers (which might be required, as this is homework).
Oh, and I would remove all the using declarations and prefix identifiers with std::, where needed. In your case it would even save typing. Also, it makes the code clearer (some would argue against this) and it is less error prone (hard to argue against that).
No, you haven't.
You have two cpp files, that contain
int array1[arraySize];
int array2[arraySize];
lib6.cpp and main.cpp compile normally but duranig linking of course there is an error: "multiple definition of array1 ..."
Firstly, take the following snippet of code out of your header file:
int const arraySize = 10;
int array1[arraySize];
int array2[arraySize];
Move the code above inside your main function. If you put these in the header file, you are making them into global variables, which is a really bad idea. Moreover, since these are definitions, not declarations, they will be created multiple times (once for each compilation unit -- i.e., .cpp source file -- that includes the header), which will result in a multiple definition error if you were to link "lab6.o" and "main.o" together.
Secondly, it appears that you have compiled "main.cpp" to "main.o" but then you have forgotten to compile "lab6.cpp" to "lab6.o" and to link "lab6.o" with "main.o", together. I don't know how to do this with Code::Blocks, although I suspect it involves checking "lab6.cpp" so that it is included in the build. If you are willing to use the commandline to build and you have the g++ compiler, then you can use:
g++ main.cpp -c -o main.o
g++ lab6.cpp -c -o lab6.o
g++ main.o lab6.o -o lab6
With the above, you can then invoke ./lab6 to run your program. You may want to use a build system such as CMake or Make (I recommend CMake) to build your program instead of relying on Code::Blocks.
Also, assuming you are permitted to do so, it is highly advisable that you use std::vector instead of primitive arrays. Of course, your assignment might be requiring you to use regular arrays, in which case that wouldn't be possible. Also, it is generally better to use std::size_t instead of int as an indexing type, although int will work, and if you use std::size_t (which is unsigned) it might cause problems with some of your loops, so contrary to the suggestion of one of the other answerers, I'd advise you just stick with int at this point (though, in the future, you should probably use std::size_t as your array size/index type).
Don't use "using" directives when writing native C++ code as it pollutes the global namespace.
How do you tell the difference between constants with your naming convention? How about ARRAYSIZE instead of arraySize for constants and enums
Why are your arrays in the header file? your functions are for the "user" to use in main(). With this implementation the user cannot change ARRAYSIZE can he. In fact, is there even a need for ARRAYSIZE when the functions are designed to work with arrays of arbitrary size?
Pass arrays by pointer, passing by value is slower and more expensive
lab6.cpp
#include "lab6.h"
#include <iostream>
#include <cstdlib>
#include <ctime>
//#include <iomanip>
void generateArray(int* array1, int arraySize)
{
// make implicit type conversions explicit
std::srand((unsigned)std::time(0));
// why the magic number here?
for (int i=0; i<10; i++)
{
array1[i]=(std::rand()%10);
}
}
void displayArray(int* array1, int* array2, int arraySize)
{
std::cout << std::endl << "Array 1" << std::endl;
for (int i=0; i<arraySize; i++)
{
std::cout<<array1[i]<<", ";
}
std::cout << std::endl << "Array 2" << std::endl;
for (int i=0; i<arraySize; i++)
{
std::cout<<array2[i]<<", ";
}
}
void reverseOrder(int* array1, int* array2, int arraySize)
{
// This is hard to read, and why do you need another integer anyway
// for (int i=0, j=arraySize-1; i<arraySize;j--, i++)
// {
// array2[j] = array1[i];
// }
for(int i=0;i<arraySize;i++)
{
array2[arraySize - i - 1] = array1[i];
}
}
lab6.h
#ifndef LAB6_H_INCLUDED
#define LAB6_H_INCLUDED
void generateArray(int* array1, int arraySize);
void displayArray(int* array1, int* array2, int arraySize);
void reverseOrder(int* array1, int* array2, int arraySize);
#endif // LAB6_H_INCLUDED
main.cpp
#include "lab6.h"
int main()
{
int const arraySize = 10;
int array1[arraySize];
int array2[arraySize];
generateArray(array1, arraySize);
reverseOrder(array1, array2, arraySize);
displayArray(array1, array2, arraySize);
return 0;
}