0

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;
}
BenMorel
  • 34,448
  • 50
  • 182
  • 322
ace
  • 189
  • 1
  • 1
  • 9
  • 1
    And your question is...? – Roger Lipscombe Apr 27 '10 at 08:05
  • You can get code formatting by selecting the block and using the binary button (101010) in the editor. That will greatly help readability, and chances of getting answers. Another thing is providing the correct tags, like *homework* if it is such (which it does look like), or removing *functional-programming* and *user-interface* (unless I am missing something from the no-question) – David Rodríguez - dribeas Apr 27 '10 at 08:06
  • well, im missing something because it wont run on code blocks. have i done it right? – ace Apr 27 '10 at 08:07
  • Judging from the header's name, this seems to be homework. If so, please add the `homework` tag. Also, code doesn't "run" inside an IDE, so it cannot fail doing so. Either you have __compilation errors__, or __linker errors__, or __run-time errors__. Please specify what goes wrong and the exact error message (if any). If it's a _compiler error_, also indicate the _line_ the (first) compiler error points to. (We don't like counting line numbers.) And please formulate a question, preferably in the header. – sbi Apr 27 '10 at 08:11
  • @ace: I have done small corrections to the indentation and removed a great deal of white-space. I have tried to pack as much as possible while maintaining readability. Note that readability is an equilibrium between too much space and not enough. – David Rodríguez - dribeas Apr 27 '10 at 08:17
  • @david again thanx. I'll get the hang of this one day – ace Apr 27 '10 at 08:20
  • as above, it flags those 3 errors in main in code blocks... @sbi im not sure what type of error this is considered, it wont compile and writes out those 3 errors in main.cpp – ace Apr 27 '10 at 08:22
  • declare your arrays using 'extern in header, then define it in lab6.cpp otherwise it gets defined twice. But I think would be better off declaring the arrays in your main(){} function and then pass them to your the functions in lab6.cpp, code gets cleaner without globals. – AndersK Apr 27 '10 at 08:33
  • @ace: "undefined reference" is always a linker error. But we can conclude this from the error messages ourselves, now that you posted them. – sbi Apr 27 '10 at 08:39
  • I tried that (suggestion 2), it still doesnt work can you edit the code to show what you mean? – ace Apr 27 '10 at 08:40
  • @ace: 1. Please __attribute whom you're answering to__. 2. "Still doesn't work" doesn't tell us what's wrong. The __same error or a different one__? (See my answer for a guess.) 3. Please __don't change the original question__ so that all the answers become wrong. That would confuse others. – sbi Apr 27 '10 at 08:50
  • @sbi. 1. my answer "i tried that..." was directed at Anders. 2. same error. 3. i think everybody is trying to rack their brains for this intricate answer, stay simple, i just began programming as im sure you can see... im just not sure how one connects 3 files like these together and for which of the 3 one has to define things... – ace Apr 27 '10 at 08:58
  • @everyone. i assume there is something not right in my linker settings in code::blocks... thats the only problem i can see being possible. and i have been fiddling with it in the past. also, if i include lab6.cpp in main (manually), it works. anyone know what it should be? – ace Apr 27 '10 at 09:20

4 Answers4

1

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).

Community
  • 1
  • 1
sbi
  • 219,715
  • 46
  • 258
  • 445
0

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 ..."

Max
  • 4,792
  • 4
  • 29
  • 32
  • But i need to do that otherwise main.cpp has no array initialisation?? – ace Apr 27 '10 at 08:31
  • What does it mean? I need to do it. It is not permitted by c++, so C++ doesn't want you to need it. Don't use global variables. Think about some interface like that: void GenerateArray(int size, vector* array); void DisplayArray(const vector& array); void ReverseOrder(vector* array); – Max Apr 27 '10 at 08:34
  • So, you function can return generated arrays, not writing to the global ones. – Max Apr 27 '10 at 08:36
  • when i say i need to, i mean i dont understand another way of doing it. if i just define them inside of main, the same problem comes up – ace Apr 27 '10 at 08:49
  • @ace: No, it's a different problem, because the error messages are different. – sbi Apr 27 '10 at 09:00
  • Declare inside main() int array1[arraySize]; int array2[arraySize]; in your lab6.h declare these 3 functions: void GenerateArray(int size, int* array); void DisplayArray(int size, const int* array); void ReverseOrder(int size, int* array); in main() you run these funtions like that: GenerateArray(10, array1); GenerateArray(10, array2); ReverseOrder(10, array1); ReverseOrder(10, array2); DisplayArray(10, array1); DisplayArray(10, array2); int lab6.cpp file realize these funtions with prototypes as I wrote.It is better your function write to array, that you give by params. – Max Apr 27 '10 at 09:02
  • @Max: These functions are already using the parameters given. It just so happens that ace gave those parameters the same name as the global variables. – sbi Apr 27 '10 at 09:06
  • Pls, somebody, when I write comment how to make sentence come in new line? – Max Apr 27 '10 at 09:07
  • @Max: Comments are not meant for this kind of lengthy explanation. They are comments. You can however edit your answer and put it in there in pretty formatting. – Björn Pollex Apr 27 '10 at 09:11
0

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).

Michael Aaron Safyan
  • 93,612
  • 16
  • 138
  • 200
  • @Micheal: Since the loops are iterating over array indexes, too, I would rather suggest using `std::size_t` for the loop indexes as well. – sbi Apr 27 '10 at 09:08
0

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;
}
aCuria
  • 6,935
  • 14
  • 53
  • 89