0

First of all, I've made this program working under one cpp file just fine, but the problem is to divide this program by each functions and header file - As my lab instructor told in class, I tried to include struct definition into header file, but I keep getting various error messages. My current code for header file is the following:

extern void threeLargest(Country countries[], Country fastGrowing[]);
extern void readData(Country countries[]);
extern void negGrowth(Country countries[]);

const int MAXCOUNTRIES = 229;
const int THREE = 3;
struct Country {
    string name;
    double pop1950;
    double pop1970;
    double pop1990;
    double pop2010;
    double pop2015;
    double growthRate;
    };
struct World {
    int numCountries;
    Country countries[MAXCOUNTRIES];
    Country fastGrowing[THREE];
    } myWorld;

For now, it gives me an error says the following ( I only brought some of them and you will see why):

In file included from lab10_0.cpp:1:0:
lab10.h:6:2: error: ‘string’ does not name a type
  string name;
  ^
lab10_0.cpp: In function ‘void readData(Country*)’:
lab10_0.cpp:17:37: error: ‘struct Country’ has no member named ‘name’
  getline(ifstr,myWorld.countries[i].name);

It seemed to me that the header file is not recognizing the string type, so does other cpp files using the header. So, I tried including

#include <string>
using namespace std;

at the beginning of the header file, but I get a whole different error message, saying

/tmp/cclU6znx.o:(.bss+0x0): multiple definition of `myWorld'
/tmp/ccQ69Fio.o:(.bss+0x0): first defined here
/tmp/cckXoPSG.o:(.bss+0x0): multiple definition of `myWorld'
/tmp/ccQ69Fio.o:(.bss+0x0): first defined here
/tmp/cctaCWNQ.o:(.bss+0x0): multiple definition of `myWorld'
/tmp/ccQ69Fio.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status

I've done this separating files previously, but this time I have to include structure definition in header file and I got stuck here without a clue. Please advise. I actually tried many, many things while googling, separating header files into two, structure definition in one header file, and the functions in the other file, but still no luck.

Please advise.

p.s. I can post full program if needed.

====================================================================== ADDED SECTION AFTER MANY CONVERSATIONS AND HELPS FROM FOLKS I'm uploading code of the original cpp file I made at the beginning, wondering this might be easier for readers to observe what is my problem.

#include <string>
#include <iomanip>
#include <iostream>
#include <fstream>


using namespace std;

const int MAXCOUNTRIES = 229;
const int THREE = 3;

struct Country{
    string name;
    double pop1950;
    double pop1970;
    double pop1990;
    double pop2010;
    double pop2015;
    double growthRate;
    };
struct World{
    int numCountries;
    Country countries[MAXCOUNTRIES];
    Country fastGrowing[THREE];
    } myWorld;
    
void threeLargest(Country countries[], Country fastGrowing[]);
void readData(Country countries[]);
void negGrowth(Country countries[]);
int main() {

readData(myWorld.countries);
threeLargest(myWorld.countries,myWorld.fastGrowing);
negGrowth(myWorld.countries);

return 0;
}

void readData(Country countries[])
{

    fstream ifstr;
    ifstr.open("population.csv");
    
    for (int i=0; !(ifstr.eof()) && i < MAXCOUNTRIES; i++) {
    ifstr >> myWorld.countries[i].pop1950 >> myWorld.countries[i].pop1970
                >> myWorld.countries[i].pop1990 >> myWorld.countries[i].pop2010
                >> myWorld.countries[i].pop2015;
    getline(ifstr,myWorld.countries[i].name);
    myWorld.countries[i].growthRate = ((myWorld.countries[i].pop2015-myWorld.countries[i].pop1950)/myWorld.countries[i].pop1950)*100;}
    
    ifstr.close();
}

void threeLargest(Country countries[], Country fastGrowing[])
{
    myWorld.fastGrowing[THREE].growthRate = { };
    for (int i=0; i < MAXCOUNTRIES; i++) {
        if (myWorld.countries[i].growthRate > myWorld.fastGrowing[0].growthRate) {
    
            myWorld.fastGrowing[2].growthRate = myWorld.fastGrowing[1].growthRate;
            myWorld.fastGrowing[2].name = myWorld.fastGrowing[1].name;
        
            myWorld.fastGrowing[1].growthRate = myWorld.fastGrowing[0].growthRate;
            myWorld.fastGrowing[1].name = myWorld.fastGrowing[0].name;      
        
            myWorld.fastGrowing[0].growthRate = myWorld.countries[i].growthRate;
            myWorld.fastGrowing[0].name = myWorld.countries[i].name;}
        
        else if (myWorld.countries[i].growthRate > myWorld.fastGrowing[1].growthRate) {
            myWorld.fastGrowing[2].growthRate = myWorld.fastGrowing[1].growthRate;
            myWorld.fastGrowing[2].name = myWorld.fastGrowing[1].name;
        
            myWorld.fastGrowing[1].growthRate = myWorld.countries[i].growthRate;
            myWorld.fastGrowing[1].name = myWorld.countries[i].name;}

        else if (myWorld.countries[i].growthRate > myWorld.fastGrowing[2].growthRate) {
            myWorld.fastGrowing[2].growthRate = myWorld.countries[i].growthRate;
            myWorld.fastGrowing[2].name = myWorld.countries[i].name;}
    }
    

    cout << "The fastest growing country is " << myWorld.fastGrowing[0].name << ", which grew by "
         << fixed << setprecision(2) << myWorld.fastGrowing[0].growthRate << "% between 1950 and 2015.\n"
         
         << "The 2nd fastest growing country is " << myWorld.fastGrowing[1].name << " which grew by "
         << fixed << setprecision(2) << myWorld.fastGrowing[1].growthRate << "% between 1950 and 2015.\n"
         
         << "The 3rd fastest growing country is " << myWorld.fastGrowing[2].name << " which grew by "
         << fixed << setprecision(2) << myWorld.fastGrowing[2].growthRate << "% between 1950 and 2015.\n";
}

void negGrowth(Country countries[])
{
    cout << "The following countries' population shrunk between 1950 and 2015:" << endl;
    for (int i=0; i < MAXCOUNTRIES; i++) {
        if (myWorld.countries[i].growthRate < 0)
        cout << myWorld.countries[i].name << " shrunk by " << fixed << setprecision(2) << myWorld.countries[i].growthRate << "%." << endl;}
}

======================================================== 2ND TIME EDITING / MY HEADER FILE LOOKS LIKE THE FOLLOWING:

#ifndef LAB10_H
#define LAB10_H

#include <string>

const int MAXCOUNTRIES = 229;
const int THREE = 3;

struct Country {
  std::string name;
  double pop1950;
  double pop1970;
  double pop1990;
  double pop2010;
  double pop2015;
  double growthRate;
  };

struct World {
  int numCountries;
  Country countries[MAXCOUNTRIES];
  Country fastGrowing[THREE];
};
extern World myWorld;

extern void threeLargest(Country countries[], Country fastGrowing[]);
extern void readData(Country countries[]);
extern void negGrowth(Country countries[]);

#endif

As I mentioned in some of you guy's comment, with extern World myWorld in header file, I could see the structure definition on header file started working, but it gets me few lines of errors saying undefined reference to 'myWorld'. So, I tried including World myWorld in all cpp files (mostly each cpp file contains a function) and finally I could compile the program.

HOWEVER, the program is not working correctly - variables are not stored correctly, and none of the calculation is right.

I mean, I didn't expect this process would be this much painful, giving me tons of headaches.

Please advise :(

mjay
  • 5
  • 4
  • 1
    Whoever told you to "use namespace std;" [doesn't know what he's talking about](http://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice). Use `std::string`, etc... – Sam Varshavchik Nov 25 '16 at 02:53
  • @SamVarshavchik Oh, that would be me, but still no luck. I just tried. Thanks anyway :) – mjay Nov 25 '16 at 02:54
  • Well, you didn't exactly think of it all by yourself. Someone told you about this directive, or taught you that, and that's how you know about it. Whoever it was, they were wrong. As explained in the link, this is a bad programming practice. – Sam Varshavchik Nov 25 '16 at 02:57
  • As far as your error goes, your header file defines the object "myworld". Hence, with multiple files, the same object gets defined in multiple translation units, hence your link error. – Sam Varshavchik Nov 25 '16 at 02:59
  • @SamVarshavchik 'myWorld' has been declared only in the header file. And yes, this header file thing has not even covered in lecture.. I have no idea why I have to do this header file thing right now. – mjay Nov 25 '16 at 03:04
  • 1
    Not just declared, but also defined. To correctly declare it, it must be declared using the `extern` keyword, and then defined in exactly one of the translation units. – Sam Varshavchik Nov 25 '16 at 03:09
  • @SamVarshavchik I've tried adding 'extern' before both 'struct' in header file, still no luck. – mjay Nov 25 '16 at 03:17

3 Answers3

1

The problem is, as the compiler noted, variable multiple declaration. In the header files you only have to define types and macros, never variables (with the exception of external declarations).

In your case, you defined the myWorld global variable of struct World type.

struct World {
    int numCountries;
    Country countries[MAXCOUNTRIES];
    Country fastGrowing[THREE];
} myWorld;

And I imagine that in your implementation files (.cpp) you have something like:

#include "myheader.h"
...
World myWorld;

What happened is that the cpp preprocessor reads each cpp file, and replace the text #include "myheader.h" with the complete content of that file before the real compilation. That means that the cpp compiler see, for each .cpp, something like:

struct World {
    int numCountries;
    Country countries[MAXCOUNTRIES];
    Country fastGrowing[THREE];
} myWorld;
...
World myWorld;

Now you can see the two declarations of the same variable too, just like de cpp compiler.

You need to delete one of these declarations, normally the header's one.

This is worst when there's many files .cpp including the same file myheader.h, all of them will define a global variable with the same name.

When you need use the same global variable in several .cpp files, you can include a definition of that variable in your header file, but with the modifier extern, like:

struct World {
    int numCountries;
    Country countries[MAXCOUNTRIES];
    Country fastGrowing[THREE];
};
extern World myWorld;

This will allow all of .cpp files know the existence of a variable myworld. And the real definition of the variable has to be in only one .cpp file, or else you will have a error in the linking phase.

Wilfredo Pomier
  • 1,091
  • 9
  • 12
  • Wow..this is very, very clear explanation of header file. Let me fix something and will come back asap – mjay Nov 25 '16 at 04:18
  • WOW ALL THAT ERRORS ARE GONE! Thinking that header comes in front of each cpp file it couldn't be easier than this. – mjay Nov 25 '16 at 04:23
  • Now I have a few errors saying 'myWorld' was not declared in this scope from each cpp files. FYI, as you've advised, I already put `extern World myWorld;` which just reduced the tons of errors. – mjay Nov 25 '16 at 04:25
  • It seems like if you didn't declare the variable `myWorld` in that place, but you did, then maybe the variable is with a typo or with different case letters, ex. `myworld` instead of `myWorld`. Don't forget that C++ is case sensitive. – Wilfredo Pomier Nov 25 '16 at 10:00
  • I still couldn't figure this out. I checked all the typos, but I've found none. Tried `extern World myWorld` in header file and removed `World myWorld` from all the cpp files, and now I get `undefined reference to 'myWorld'` from each of cpp files that has used the variable, `myWorld`. – mjay Nov 25 '16 at 20:28
  • The only case that I can compile without an error is where I put `extern World myWorld` in header, and include `World myWorld` in each cpp files (all cpp files that use the variable `myWorld`). However, something must have went wrong - all the calculation is wrong all of the variables are not stored in place. – mjay Nov 25 '16 at 20:31
  • You have to define `extern World myWorld;` in header file, and define one `World myWorld;` in only one cpp file. Please write here the exact error with this approach in order to help you, or else I'm blind. – Wilfredo Pomier Nov 25 '16 at 21:19
  • Better than this, only if you can save your entire project files in a public repository (like github) in order to check the code directly. – Wilfredo Pomier Nov 25 '16 at 21:23
0

Do you have an include guard on your header file? It would look something like this:

#ifndef LAB10_H
#define LAB10_H

// everything else goes in here

#endif /* LAB10_H */

"LAB10_H" can be any arbitrary text that's unique to your project, so by convention it's often the filename in uppercase with an underscore replacing the dot.

#ifndef LAB10_H
#define LAB10_H

#include <string>

extern void threeLargest(Country countries[], Country fastGrowing[]);
extern void readData(Country countries[]);
extern void negGrowth(Country countries[]);

const int MAXCOUNTRIES = 229;
const int THREE = 3;
struct Country {
  std::string name; // avoiding "using namespace std;"
  double pop1950;
  double pop1970;
  double pop1990;
  double pop2010;
  double pop2015;
  double growthRate;
};

struct World {
  int numCountries;
  Country countries[MAXCOUNTRIES];
  Country fastGrowing[THREE];
} myWorld;    

#endif /* LAB10_H *
Jack Deeth
  • 3,062
  • 3
  • 24
  • 39
  • With/Without the guard, I still get same kind of error though – mjay Nov 25 '16 at 04:17
  • OK, you definitely want the guard on every header file anyway. The other answer, about removing "myWorld" from the end of the World struct, replacing it with "extern World myWorld;" in lab10.h and "World myWorld;" in one .cpp file (probably the one with the "main" function), should do it then… – Jack Deeth Nov 25 '16 at 04:20
  • I added `World myWorld` to each of the cpp files and made the program compile without an error, but the program is not running as it meant to be.. – mjay Nov 25 '16 at 04:56
  • This is so painful I got stuck right here for half day and still can't figure it out.. – mjay Nov 25 '16 at 04:56
  • I've edited/uploaded the original cpp file to my original post fyi. – mjay Nov 25 '16 at 05:01
  • OK you're close! You can only have `World myWorld;` in *one* place in your program. (And `struct World {…} myWorld;` means the same thing as `struct World {…}; World myWorld;`.) So you need to change all but one of the `World myWorld;` to `extern World myWorld;` and you should be good! – Jack Deeth Nov 25 '16 at 08:48
  • Still no luck I've tried everything. Maybe I should post my header file by now. – mjay Nov 25 '16 at 20:34
0

Along with the first answer of removing the "myWorld" from end of the struct and adding "extern World myWorld", you need to create myWorld object in "one" of your cpp files with "World myWorld".

Here is the flow:

  1. Struct definition in .h
  2. object declaration in .cpp
  3. extern the object in .h
Mohan Kumar P
  • 3,122
  • 1
  • 14
  • 17
  • Somehow, even with the `extern World myWorld` in header, I have to include `World myWorld` in every cpp files in order to not get an error. Even worse when I put `World myWorld` in every cpp files for the program to be compiled, program runs with errors - none of the variables are storing correct values, and none of the calculation is right. – mjay Nov 25 '16 at 20:33
  • No, don't put "World myWorld" in every cpp, but just put in one cpp file. – Mohan Kumar P Nov 28 '16 at 05:27