2

I am new to C++ and am working on a question for class:

4. Annual Rainfall Report

Write a program that displays the name of each month in a year and its rainfall amount, sorted in order of rainfall from highest to lowest. The program should use an array of structures, where each structure holds the name of a month and its rainfall amount. Use a constructor to set the month names. Make the program modular by calling on different functions to input the rainfall amounts, to sort the data, and to display the data.

Here is the code I have so far:

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

using namespace std;

struct Month    //defining the structure
{
    string name;
    double rain;

Month(string name = "", double rain = 0){} //constructor
};

const int SIZE = 12; //12 months

//initializing each structure with the name
Month month[SIZE] = { Month("January", 0), Month("February",0), Month("March", 0),  
                      Month("April", 0), Month("May", 0), Month("June", 0),
                      Month("July", 0), Month("August", 0), Month("September", 0),
                      Month("October", 0), Month("November", 0), Month("December",0)};
void rainIn();

void sort();

void display();


int main() {

    rainIn();
    display();

    return 0;
}

void rainIn()
{
    for (int i = 0; i < SIZE; ++i)
    {
        cout << "Please enter the rainfall for " << month[i].name << ": ";
        cin >> month[i].rain;
    }
}

void sort() //will write later
{    }

void display()
{
    for (int i = 0; i < SIZE; ++i)
    {
        cout << month[i].name << month[i].rain << endl;
    }
}

The problem I am having is that the name of the month is not displayed when I try to call it. Am I initializing the array incorrectly?


After reading the comments and answers, I developed a "Minimal, Complete, Verifiable" example:

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

using namespace std;

struct Month
{
    string name;
    double rain;

    Month(string n = "", double r = 0) {}
};


Month month("January", 12);


int main() {
    cout << month.name << " had " << month.rain << " inches of rain. " << endl;
    return 0;
}

Which still gave me the same problem. I changed the constructor (and added the member initialization list) as shown:

Month(string n = "", double r = 0) : name{n}, rain{r} {}

and it worked.

Churro
  • 23
  • 5
  • The array is a red herring; even if you just created a single `Month` object it wouldn't be initialized. –  Oct 17 '15 at 17:44
  • 1
    You probably would have found that problem yourself while making a [mcve]. – Baum mit Augen Oct 17 '15 at 17:53
  • Surprisingly good code for a newcomer, with `std::string` and whatnot, and it's fairly well laid out. But, indeed, you did not reduce this problem to a minimal testcase, so you have not yet learned how to debug your code. – Lightness Races in Orbit Oct 17 '15 at 17:53
  • @LightnessRacesinOrbit: IMO reducing to minimal testcases and debugging are two orthogonal skills (both important, of course). – Christian Hackl Oct 17 '15 at 18:27
  • @ChristianHackl: I disagree! I consider reduction to be a critical skill in the set of skills known as "being able to debug" :) – Lightness Races in Orbit Oct 17 '15 at 18:44

1 Answers1

4

The problem is not the array, but that the constructor does not actually set the member variables to the input values. Try this instead:

Month(string name = "", double rain = 0) : name{name}, rain{rain} {} //constructor

This syntax is called "member initialization list". If it should look foreign to you, have a look at this.

Community
  • 1
  • 1
Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
  • 1
    There is no assignment here. – Lightness Races in Orbit Oct 17 '15 at 17:54
  • 1
    The point is that this is initialisation, not assignment. Beginners _think_ they observe assignment all the time, which is a common problem. Let's not add to it, eh? – Lightness Races in Orbit Oct 17 '15 at 17:59
  • Are you honestly asking me whether it _matters_ when we misteach people? – Lightness Races in Orbit Oct 17 '15 at 18:04
  • Teaching with the correct terminology, and teaching advanced topics before simple topics, are two completely different things. The beginner does not know the precise term because _you_ just taught him the wrong one!! – Lightness Races in Orbit Oct 17 '15 at 18:11
  • 1
    @BaummitAugen: Yes, it matters to the audience of the answer precisely because it is a beginner's question. C++ can be extremely confusing for a beginner. One of its confusing aspects is the difference between initialisation and assignment. A beginner will be confused even more when he or she tries to learn the difference and sees a +10k SO user use the words in a different way. – Christian Hackl Oct 17 '15 at 18:12
  • @BaummitAugen: A better analogy would be to talk about "the std::cout class" while explaining the program. – Christian Hackl Oct 17 '15 at 18:14
  • @ChristianHackl Ok, I agree with that. You and LRiO are right, I was wrong. Is the answer fine now or does it still need improvement? – Baum mit Augen Oct 17 '15 at 18:18
  • 1
    @BaummitAugen: Well, to be honest I'm still not entirely happy with the first sentence, because it still talks about assignment. It's technically correct because assignment would solve the OP's problem here, but for the sake of teaching clean concepts I'd rephrase that to *"(...) that the member variables are not actually initialised with the input values"*. – Christian Hackl Oct 17 '15 at 18:25
  • What amazes me is that it seems only a few instructors teach the initialization list, dooming their students to confusion when either A) the student sees one in use and has a WTF moment or B) goes nuts trying to unravel the compiler message when trying to extend a base class without a default constructor. – user4581301 Oct 17 '15 at 18:31
  • 2
    @user4581301: Regarding B, why should that be an error? `struct B { B(int) {} int x; }; struct D : B {};` compiles fine. I think better examples would be `const` or reference members, because those do always require initialisation. – Christian Hackl Oct 17 '15 at 18:35
  • @ChristianHackl Maybe I'm missing something here, but that only compiles up until you try to instantiate a D. – user4581301 Oct 17 '15 at 18:45
  • Though I will say the error message is nowhere near as arcane as I remember it being. – user4581301 Oct 17 '15 at 18:47
  • @user4581301: Yes, with an instantiation this will fail if `D` does not have a constructor that calls one of `B`'s constructors.. But I'm still somewhat puzzled as to how this relates to the initialisation issue. You would receive almost the same error message if you tried to instantiate `B`. I would think a beginner would figure out how to instantiate classes without default constructors before trying inheritance... – Christian Hackl Oct 17 '15 at 20:29
  • The point: Here is an important bit of information vital to extending a base class with requirements, and no one seems to cover it outside of the better breed of book. The error messages are nowhere near as cryptic as I remember them being, but will still leave the uninitiated thinking, "Duh. Of course I need to call the base constructor with it's arguments. HOW?!?" You can't just call `B(10);` in the body of the constructor as you were taught to do with all the other member variables. You need to know to call it in the initializer list and that the initializer list exists. – user4581301 Oct 18 '15 at 01:05