separating interface and implemention with normal functions - c++

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;
}

Related

Defining function with arrays in different files

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.

Using static const string[] as a member instead of a global, initialized in the .cpp file

Related to this. I'd like to avoid using global variables so I resorted to using structs with enum and std::string[] (see link) in order to build menus for a small application. I would also like to have these enums in a separate header file. The selected answer in the link implies using --std=c++17, which I'd like to avoid, at least for now, and decided to use a static const std::string[] -- no need to include extra array or vector since this is initialized once, never modified, only called, ALL is always known.
As other answers on this have made it clear, I need to either initialize A::names outside the struct, or use a static const std::string& setter (see this, for example). But all the answers so far dealt with a std::string, not an array, std::string[].
This is a simple example of what I tried. It simply tries to print the contents of A::names using a for() loop iterating through the enum in struct A:
a.h:
#ifndef A_H_INCLUDED
#define A_H_INCLUDED
#include <string>
struct A
{
enum E { ONE, TWO, ALL };
static const std::string names[ALL];
};
#endif // A_H_INCLUDED
a.cpp:
#include "a.h"
static const std::string A::names[A::ALL] { "one", "two" };
main.cpp:
#include "a.h"
#include <iostream>
int main()
{
for(int i=A::ONE; i<A::ALL; ++i)
std::cout << A::names[i] << '\n';
return 0;
}
The error after g++ main.cpp is:
main.cpp:(.text+0x24): undefined reference to `A::names[abi:cxx11]'
collect2: error: ld returned 1 exit status
Seeing the cxx11, I thought g++ --std=c++11 main.cpp would solve it, but it doesn't.
So, what am I doing wrong, or, how could I adapt the version with the setter to return an array, std::string[]? My goal is to have an alternative to a global variable, that has only one instance in memory no matter how many calls.
Here's an adapted code, from a small program, on how I would build a menu using struct with enum and string (menu_design = new QMenu... and menuDesignAction() is the function that updates):
for(unsigned char i=0; i<A::ALL; ++i) // needs initializing
{
QAction *tmpAction {new QAction(tr(A::names[i].c_str()))};
tmpAction->setObjectName(QString("%1").arg(i));
connect(tmpAction, SIGNAL(triggered(bool)), this, SLOT(menuDesignAction()));
menu_design->addAction(tmpAction);
}
As a side-note, in the snippet above, I have to use .c_str(), but I am using a std::string in the enum. If I could make it *char[] instead of std::string[], would I avoid extra calls? If I am not wrong, how could the answers to my problem (assuming there are) be adapted so as to be able to fit somehow in the Qt snippet?

How to make a variable available to multiple .cpp files using a class?

This question has derived from this one.
I have a working program which must be split into multiple parts. In this program is needed to use a variable (now it's a GTK+ one :P) many times in parts of the program that will end up in separated .cpp files.
So, I made a simple example to understand how to make variables available to the program parts. A modified version of the previous code would be:
#include <iostream>
using namespace std;
int entero = 10;
void function()
{
cout<<entero<<endl;
//action1...;
}
void separated_function()
{
cout<<entero<<endl;
//action2...;
}
int main( int argc, char *argv[] )
{
function();
separated_function();
cout<<entero<<endl;
//something else with the mentioned variables...;
return 0;
}
It is needed to split the code correctly, to have function(), another_function() and main() in separated .cpp files,and make entero avaliable to all of them... BUT:
In the previous question #NeilKirk commented:Do not use global variables. Put the required state into a struct or class, and pass it to functions as necessary as a parameter (And I also have found many web pages pointing that is not recommended to use global variables).
And, as far I can understand, in the answer provided by #PaulH., he is describing how to make variables avaliable by making them global.
This answer was very useful, it worked fine not only with char arrays, but also with ints, strings and GTK+ variables (or pointers to variables :P).
But since this method is not recommended, I would thank anyone who could show what would be the correct way to split the code passing the variables as a function parameter or some other method more recommended than the - working - global variables one.
I researched about parameters and classes, but I'm a newbie, and I messed the code up with no good result.
You need to give the parameter as a reference if you want the same comportement as a global variable
#include <iostream>
using namespace std;
// renamed the parameter to avoid confusion ('entero' is valid though)
void function(int &ent)
{
cout<<ent<<endl;
++ent; // modify its value
//action1...;
}
void separated_function(int &ent)
{
cout<<ent<<endl;
++ent; // modify its value again
//action2...;
}
int main( int argc, char *argv[] )
{
int entero = 10; // initializing the variable
// give the parameter by reference => the functions will be able to modify its value
function(entero);
separated_function(entero);
cout<<entero<<endl;
//something else with the mentioned variables...;
return 0;
}
output:
10
11
12
Defining a class or struct in a header file is the way to go, then include the header file in all source files that needs the classes or structures. You can also place function prototypes or preprocessor macros in header files if they are needed by multiple source files, as well as variable declarations (e.g. extern int some_int_var;) and namespace declarations.
You will not get multiple definition errors from defining the classes, because classes is a concept for the compiler to handle, classes themselves are never passed on for the linker where multiple definition errors occurs.
Lets take a simple example, with one header file and two source files.
First the header file, e.g. myheader.h:
#ifndef MYHEADER_H
#define MYHEADER_H
// The above is called include guards (https://en.wikipedia.org/wiki/Include_guard)
// and are used to protect the header file from being included
// by the same source file twice
// Define a namespace
namespace foo
{
// Define a class
class my_class
{
public:
my_class(int val)
: value_(val)
{}
int get_value() const
{
return value_;
}
void set_value(const int val)
{
value_ = val;
}
private:
int value_;
};
// Declare a function prototype
void bar(my_class& v);
}
#endif // MYHEADER_H
The above header file defines a namespace foo and in the namespace a class my_class and a function bar.
(The namespace is strictly not necessary for a simple program like this, but for larger projects it becomes more needed.)
Then the first source file, e.g. main.cpp:
#include <iostream>
#include "myheader.h" // Include our own header file
int main()
{
using namespace foo;
my_class my_object(123); // Create an instance of the class
bar(my_object); // Call the function
std::cout << "In main(), value is " << my_object.get_value() << '\n';
// All done
}
And finally the second source file, e.g. bar.cpp:
#include <iostream>
#include "myheader.h"
void foo::bar(foo::my_class& val)
{
std::cout << "In foo::bar(), value is " << val.get_value() << '\n';
val.set_value(456);
}
Put all three files in the same project, and build. You should now get an executable program that outputs
In foo::bar(), value is 123
In main(), value is 456
I prefer to provide a functional interface to global data.
.h file:
extern int get_entero();
extern void set_entero(int v);
.cpp file:
static int entero = 10;
int get_entero()
{
return entero;
}
void set_entero(int v)
{
entero = v;
}
Then, everywhere else, use those functions.
#include "the_h_file"
void function()
{
cout << get_entero() << endl;
//action1...;
}
void separated_function()
{
cout << get_entero() << endl;
//action2...;
}
int main( int argc, char *argv[] )
{
function();
separated_function();
cout<< get_entero() <<endl;
//something else with the mentioned variables...;
return 0;
}
If you do not plan to modify the variable, it is generally ok to make it global. However, it is best to declare it with the const keyword to signal the compiler that it should not be modified, like so:
const int ENTERO = 10;
If you are using multiple cpp files, also consider using a header file for your structures and function declarations.
If you are planning on modifying the variable, just pass it around in function parameters.

Why is variable array-length in a function-call possible in C but not in C++?

I would like to treat an flat 1D Array inside a function as it was a 3D array. I know I can use a macro to translate coordinates like that:
#define f3d(x,y,z,nx,ny) ( (z)*(nx)*(ny) + (y)*(nx) + (x))
But my teacher told me there is a way to simply cast them in the function call.
So the following test program is working perfectly good with compiler call: gcc -std=c99 -o test.exe main.c
main.c:
#include <stdlib.h>
#include <stdio.h>
static void init(int n, double a[n][n][n]){
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
for(int k=0; k<n; k++)
a[i][j][k] = i;
}
int main(int argc, char **argv){
int n = 5;
double *a = malloc(n*n*n*sizeof(*a));
init(n, (double (*)[n][n])a);
for(int i=0; i<n*n*n; i++)printf("%lf ",a[i]);
return 0;
}
But now I have to use C++ and I can't compile it with: g++ -o test.exe main.c
Compiler says error: array bound is not an integer constant
I can imagine why compilers struggle with variable arraylengths, but why is it working in C ?
Can somebody tell me why?
And is there a workaround for this problem?
Thanks in advance!
UPDATE:
Thanks a lot for the Answers, but now I'm confused. I use g++ (SUSE Linux) 4.4.1 [gcc-4_4-branch revision 150839] which should be capable of VLAs. Why is it not compiling and throws "error: array bound is not an integer constant" ?
From GCC:
http://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
Variable-length automatic arrays are allowed in ISO C99, and as an
extension GCC accepts them in C90 mode and in C++. These arrays are
declared like any other automatic arrays, but with a length that is
not a constant expression. The storage is allocated at the point of
declaration and deallocated when the brace-level is exited.
...
You can also use variable-length arrays as arguments to functions:
struct entry
tester (int len, char data[len][len])
{
/* ... */
}

C++ undefined reference to defined function

I cannot figure out why this is not working. I will put up all three of my files and possibly someone can tell me why it is throwing this error. I am using g++ to compile the program.
Program:
#include <iostream>
#include "h8.h"
using namespace std;
int main()
{
char sentence[MAX_SENTENCE_LENGTH];
char writeTo[] = "output.txt";
int distanceTo,likePosition, length, numWords;
cout << "ENTER A SENTENCE! ";
cin.getline(sentence, 299);
length = strlen(sentence);
numWords = wordCount(sentence, length);
for(int x = 0; x < 3; ++x)
{
likePosition = likePos(numWords);
distanceTo = lengthTo(sentence, likePosition, length);
insertLike(sentence, distanceTo, length, writeTo);
}
return 0;
}
Function file:
void insertLike(const char sentence[], const int lengthTo, const int length, char writeTo[])
{
char part1[MAX_SENTENCE_LENGTH], part2[MAX_SENTENCE_LENGTH];
char like[] = " like ";
for(int y = 0; y < lengthTo; ++y)
part1[y] = sentence[y];
for(int z = lengthTo+1; z < length - lengthTo; ++z)
part2[z] = sentence[z];
strcat(part1, like);
strcat(part1, part2);
writeToFile(sentence, writeTo);
return;
}
Header file:
void insertLike(const char sentence[], const int lengthTo, const int length, const char writeTo[]);
The error exactly is:
undefined reference to 'insertLike(char const*, int, int, char const*)'
collect2: ld returned 1 exit status
The declaration and definition of insertLike are different
In your header file:
void insertLike(const char sentence[], const int lengthTo, const int length, const char writeTo[]);
In your 'function file':
void insertLike(const char sentence[], const int lengthTo, const int length,char writeTo[]);
C++ allows function overloading, where you can have multiple functions/methods with the same name, as long as they have different arguments. The argument types are part of the function's signature.
In this case, insertLike which takes const char* as its fourth parameter and insertLike which takes char * as its fourth parameter are different functions.
Though previous posters covered your particular error, you can get 'Undefined reference' linker errors when attempting to compile C code with g++, if you don't tell the compiler to use C linkage.
For example you should do this in your C header files:
extern "C" {
...
void myfunc(int param);
...
}
To make 'myfunc' available in C++ programs.
If you still also want to use this from C, wrap the extern "C" { and } in #ifdef __cplusplus preprocessor conditionals, like
#ifdef __cplusplus
extern "C" {
#endif
This way, the extern block will just be “skipped” when using a C compiler.
You need to compile and link all your source files together:
g++ main.c function_file.c
This could also happen if you are using CMake. If you have created a new class and you want to instantiate it, at the constructor call you will receive this error -even when the header and the cpp files are correct- if you have not modified CMakeLists.txt accordingly.
With CMake, every time you create a new class, before using it the header, the cpp files and any other compilable files (like Qt ui files) must be added to CMakeLists.txt and then re-run cmake . where CMakeLists.txt is stored.
For example, in this CMakeLists.txt file:
cmake_minimum_required(VERSION 2.8.11)
project(yourProject)
file(GLOB ImageFeatureDetector_SRC *.h *.cpp)
### Add your new files here ###
add_executable(yourProject YourNewClass.h YourNewClass.cpp otherNewFile.ui})
target_link_libraries(imagefeaturedetector ${SomeLibs})
If you are using the command file(GLOB yourProject_SRC *.h *.cpp) then you just need to re-run cmake . without modifying CMakeLists.txt.
If you are including a library which depends on another library, then the order of inclusion is also important:
g++ -o MyApp MyMain.o -lMyLib1 -lMyLib2
In this case, it is okay if MyLib1 depends on MyLib2.
However, if there reverse is true, you will get undefined references.
As Paul said, this can be a linker complaint, rather than a compiler error. If you read your build output/logs carefully (may need to look in a separate IDE window to see the full details) you can dell if the problem is from the compiler (needs to be fixed in code) or from the linker (and need to be fixed in the make/cmake/project level to include a missing lib).