finding a range between period dates in an enum

UPDATE:

SOLVED.


I had problems trying to figure out the correct for loop math, but I figured it out! If anyone else needs help you can review the code below.

Thanks for everyone's help!


The instructions are:

"You are taking a geology class, and the professor wants you to write a program to help students learn the periods of geologic time. The program should let the user enter a range of prehistoric dates (in millions of years), and then output the periods that are included in that range. Each time this output is done, the user is asked if he or she wants to continue. The goal of the exercise is for the student to try to figure out when each period began, so that he or she can make a chart of geologic time.
Within the program, represent the periods with an enumeration type made up of their names."

My main problem seems to be finding the right computation for having the enums match with the char arrays.

Update number 4, October 19th at 4:57PM



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <iostream>	
#include <string>


using namespace std;



enum period { Neogene, Paleogene, Cretaceous, Jurassic, Triassic, Permian,
	     Carboniferous, Devonian, Silurian, Ordovician, Cambrian, Precambrian } ;


char* periodNames[12] = { "Neogene", "Paleogene", "Cretaceous", "Jurassic", "Triassic", "Permian",
	                            "Carboniferous", "Devonian", "Silurian", "Ordovician", "Cambrian", "Precambrian" } ;


/* function that returns the string
* corresponding to each identifier in the enumeration. 
*/
period getPeriod(int year) {

	if (year <=23) {return Neogene;}
	 if (year <= 65) {return Paleogene;}
	 if (year <= 136) {return Cretaceous;}
	 if (year <= 192) {return Jurassic;}
	 if (year <= 225) {return Triassic;}
	 if (year <= 280) {return Permian;}
	 if (year <= 345) {return Carboniferous;}
	 if (year <= 395) {return Devonian;}
	 if (year <= 435) {return Silurian;}
	 if (year <= 500) {return Ordovician;}
	 if (year <= 570) {return Cambrian;}
	 if (year <= 4500) {return Precambrian;}

	
} // end of period getPeriod function

period lastPeriod(int endDate) {

	if (endDate <=23) {return Neogene;}
	if (endDate <= 65) {return Paleogene;}
	if (endDate <= 136) {return Cretaceous;}
	 if (endDate <= 192) {return Jurassic;}
	 if (endDate <= 225) {return Triassic;}
	 if (endDate <= 280) {return Permian;}
	 if (endDate <= 345) {return Carboniferous;}
	 if (endDate <= 395) {return Devonian;}
	 if (endDate <= 435) {return Silurian;}
	 if (endDate <= 500) {return Ordovician;}
	 if (endDate <= 570) {return Cambrian;}
	 if (endDate <= 4500) {return Precambrian;}

	
} // end of period getPeriod function



int main ()
{
	
	
	// Asks the user if they want to try another ticket or quit in a loop
	bool running = true;
		while ( running ) // Runs in case user wants to loop this part of the program
  {
	 

	//  Declare year and endYear
	int year = 0;
	int periodYear = 0; 
	int endDate = 0;
	
	// description of program
	cout << "This program will ask a user to input a time in millions of years\nthen outputing the period within that year number." << endl;
	cout << "Please enter a starting date (For example if you type '23'\nthat means '23,000,000' or 23 million years." << endl;
	cout << " " << endl;

	// asks user to enter start date
	cout << "Enter start period date:" << endl;
	cin >> year; 
	cout << "\n";

	// asks user to enter end date
	cout << "Enter end period date:" << endl;
	cin >> endDate;
	cout << "\n";

	int beginPeriod = getPeriod(year);
	int endPeriod = lastPeriod(endDate);
	


	//For loop to output the series of periods in the range
		cout << "The Period Names include: " << endl;
		cout << "\n";

	for (year; beginPeriod <= endPeriod; beginPeriod++) 
			std::cout << periodNames[beginPeriod] << "\n" << std::endl; // prints out the corresponding name


	// continous loop of input cont.
	bool loop = true;
    while ( loop )
    {
      // Here we ask if they want to keep going:
      char choice; // Use a char.

      // Options
      std::cout << "Enter 1 to try continue" << std::endl;
      std::cout << "Or Enter 2 to quit" << std::endl;
      std::cout << "Your choice? "; std::cin >> choice;

      // Now we do some if statement checking
      if (choice == '1')
        loop = false; // Gets you out of the {} of the smaller while loop
      else if (choice == '2'){
        running = false, loop = false; // end both loops
		cout << "End of program. Please exit." << endl;
	  }
      else
        std::cout << "\nI'm confused! Pick the right thing please." << std::endl << std::endl;
		system("PAUSE"); 
		cin.get(); 
        // repeat smaller loop
    } // end of while (loop)
  } // end of while (running) loop

	
	


	cin.get();
	system ("PAUSE");

	return 0;
} // end of main function 
Last edited on
You have an (uninitialized) array of characters, but what you really want is an (properly initialized) array of strings.

Ideally, if you are allowed to, you should use this:

std::map<period, std::string> g;

A map is an associative container that will let you assign values (strings in this case) to keys (your period enum type in this case).
http://www.cplusplus.com/reference/map/map/
http://en.cppreference.com/w/cpp/container/map

I see though that you're using c-style strings, which are much harder to deal with than C++'s std::string type. You should learn how to use std::string to ease your life:
http://www.cplusplus.com/reference/string/string/
http://en.cppreference.com/w/cpp/string/basic_string
Last edited on
Line 43 is an uninitialized pointer (points to random memory).

Lines 44-46: You're try to set character elements of the char array g (which points to nonsense) to the address of C-strings. This is a type mismatch. You can't assign a char pointer to a char.

Line 49: You output whatever garbage g points to.

What is functionString suppoed to do? You don't pass it any arguments.

Line 70-71: Why are these here? They are not used.

Line 78: Is ArrayCombine supposed to be a struct declaration, or is this an empty struct definition? This statement doesn't do anything.

Line 81: You can't reference g here. g is a local within functionString().
Thanks for the replies, all.

@LB thanks, but I don't think I'm supposed to use map. I'm going to get rid of g since the instructor wants me to do something else. I also didn't know I was using c-style. I'm in a C++ class but all I see are strings labeled the way I have it.


@ AbstractionAnon

Thanks for the quick error checks. I'll reply to them:

responses:


Line 43 is an uninitialized pointer (points to random memory).
Lines 44-46: You're try to set character elements of the char array g (which points to nonsense) to the address of C-strings. This is a type mismatch. You can't assign a char pointer to a char.
Line 49: You output whatever garbage g points to.


Ok the instructor told me I was doing it wrong so I'm getting rid of all g variables.


What is functionString suppoed to do? You don't pass it any arguments.



I wanted to make the function, put the char array and int periodDates inside it then call it in the main string but I guess I didn't do that right.



Line 70-71: Why are these here? They are not used.



I'll get rid of these. (But I think I need periodYear declared in my main function so I'm keeping that.)




Line 78: Is ArrayCombine supposed to be a struct declaration, or is this an empty struct definition? This statement doesn't do anything.


Oops that was something I wasn't supposed to do and forgot to erase. Sorry.



Line 81: You can't reference g here. g is a local within functionString().

I need to look at function calling again...


Ok the instructor updated me on what my computations should be.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
period getPeriod(int year) {

	if (year <=23) {return Neogene;}
	else if (year <= 65) {return Paleogene;}
	else if (year <= 136) {return Cretaceous;}
	else if (year <= 192) {return Jurassic;}
	else if (year <= 225) {return Triassic;}
	else if (year <= 280) {return Permian;}
	else if (year <= 345) {return Carboniferous;}
	else if (year <= 395) {return Devonian;}
	else if (year <= 435) {return Silurian;}
	else if (year <= 500) {return Ordovician;}
	else if (year <= 570) {return Cambrian;}
	else if (year <= 4500) {return Precambrian;}
	

} // end of period getPeriod function


But I still have a problem properly calling them to my main function. I tried having year set my already declared periodYear variable but since I set the getPeriod(year) function before main it says it's undefined.

I instead try to have the function called in my main function by putting:

1
2
3
4
5
6
7
8
9
10
11
// function call to period getPeriod function
	
period getPeriod(year);

// declare year

int year;

// compute the begin period
	period beginPeriod = year;


but it says for year inside getPeriod: ERROR: a value type of "int" cannot be used to initialize an entity type of "period"

I tried making year a int, char, and float but I get the same error.
I'll edited my first post with the updated code.
Last edited on
tamirat wrote:
I also didn't know I was using c-style. I'm in a C++ class but all I see are strings labeled the way I have it.
I feel your pain. I learned C++ years ago but recently took a C++ class, and the amount of C that was being taught as though it were C++ was staggering.
What you want is something like this:

1
2
3
4
5
6
  period  beginPeriod; 
  int year; 

  //  Initialize year somehow
  beginPeriod = getPeriod(year);
  cout << periodnames[beginPeriod] << endl;


Lines 84 and 85 are still useless.

I would suggest changing funtionString as follows:
1
2
3
4
5
6
 
void displayPeriod (period per)
{  const char* periodNames [12] = {    "Neogene", "Paleogene", "Cretaceous", "Jurassic", "Triassic","Permian","Carboniferous","Devonian", "Silurian","Ordovician", "Cambrian","Precambrian"};

  cout << periodNames[per]; 
}



Thanks for the help!

Hm...Even adding these lines of code I still have the error:

error C2065: 'periodNames' : undeclared identifier

in my
1
2
for (year = 0; year <= 23; year = period(year+1))
			std::cout << periodNames[beginPeriod] << std::endl; // prints out the corresponding name 


Did I function call to display period wrong? I wrote:

1
2
// functioncall to display period
	displayPeriod (period);


Inside my main but it makes an error saying: error C2275: 'period' : illegal use of this type as an expression

Hm...Looking online it seems like a problem with my program? I'm using Visual C++ 2010 basic.

I could also move it. I'll try that (although the instructor wanted me to have a function that stores the strings.

Also why did you put

 
cout << periodNames[per];


In the begin period function? The output's should only be in the main I think.

Updating main file again. >_< Thanks again for the help guys I appreciate it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>

enum epoch { Neogene = 23, Paleogene = 65, Cretaceous = 136, Jurassic = 192, Triassic = 225, Permian = 280,
	     Carboniferous = 345, Devonian = 395, Silurian = 435, Ordovician = 500, Cambrian = 570, Precambrian = 4500 } ;

const int epoch_end[] = { Neogene, Paleogene, Cretaceous, Jurassic, Triassic, Permian,
                          Carboniferous, Devonian, Silurian, Ordovician, Cambrian, Precambrian } ;

const int N = sizeof(epoch_end) / sizeof( epoch_end[0] ) ;

const char* const epoch_name[N] = { "Neogene", "Paleogene", "Cretaceous", "Jurassic", "Triassic", "Permian",
	                            "Carboniferous", "Devonian", "Silurian", "Ordovician", "Cambrian", "Precambrian" } ;

int main ()
{
        std::cout << "This program will ask a user to input a time in millions of years\n"
                     "then outputing the period within that year number.\n\n"
	             "Please enter a starting date\n"
	             "(For example if you type '23' that means '23,000,000' or 23 million years.\n" ;

	int year ;
	std::cin >> year ;

	int i = 0 ;
	while( year > epoch_end[i] ) ++i ; // get to the epoch of the date 'year'

	if( i < N ) std::cout << epoch_name[i] << '\n' ;
	else std::cout << "before Precambrian\n" ;

	// this program accepts one date (in millions of years) and prints out
	// the epoch in which that date falls

	// TODO: extend this to
	// a. let the user enter a range of prehistoric dates (in millions of years)
	// b. output the epochs that are included in that range.
	// c. put a, b in a loop to allow the user to enter another range
}
Line 40: This line serves no purpose in displayPeriod. The purpose of this line has been replaced by the function getPeriod.

Line 82: year is uninitialized.

Line 91: period is a type, not a value. You set beginPeriod at line 86. Now you want to display it.

 
  displayPeriod (beginPeriod);


Line 116: You're using year as your loop variable. This is going to change the value entered by the user at line 110. Also, why is your loop limit 23?

Line 118: Of course periodNames is undefined. periodNames is local within displayPeriod. Change line to call displayPeriod.


9 / 20
Ok thanks for the help AbstractionAnon, I'll make changes.

And thanks for the code JLBorges, but I need to use a for loop for this assignment. (and when i tried to change it into a for loop I couldn't do it because the for loop for this assignment is wierd.)

Ok after messing with my file again I think I found my problem:

By setting up a breakpoint I found that my
 
period beginPeriod = getPeriod(year);

always equals 0, or Neogene in my enum.
I want my beginPeriod set as the entirety of enum so that the getPeriod function can do it's thing but it always ends up equalling Neogene.

I think it does this because I set int year and periodYear as 0. But when I don't se them any any numbers like:

1
2
int year;
int periodYear;


I get the error saying they are uninitialized.

How can I get beginPeriod to do what I want it to do? (set as my getPeriod function so when year is outputted as the right number I get the correct enum.)

I'll edit my first post again. I really would like to finish this today but if I can't I guess I have to submit what I have and hope I don't fail the assignment.
> I need to use a for loop for this assignment.
> (and when i tried to change it into a for loop I couldn't do it .. )

These two loops are equivalent:

1
2
int i = 0 ;
while( year > epoch_end[i] ) ++i ;


and
1
2
int i ;
for( i = 0 ; year > epoch_end[i] ; ++i ) ;

Ah I see. I can't do that in my program though, if I don't use operator overloading or whatever I just get an infinite loop of neogene.

And I really don't want to just copy your program because I need to have my enums set as {neogene = 0} (I don't know why, when i tried to set neogene to 23 like you did the teacher didn't want me to do that. :/)
> I really don't want to just copy your program because I need to have my enums set as {neogene = 0}

Even if you did not need to have your enums set differently, you really don't want to blindly copy any program. You can gain from reasoning about, analysing the code that someone else has written. To learn programming, in the end, you need to write your own code.
I understand. I have been trying to see your code and how I can use your techniques to get the same result on mine. It's not working out though. >_>

EDIT:
Oh man I'm an IDIOT. I was constantly getting 0 as neogene because I didn't move the

1
2
int beginPeriod = getPeriod(year);


until AFTER I declared year as a user input. Haha.

Ok now I need to do now is get the for loop so show a range of periods instead of just the one. I'll keep working on it but if anyone has a hint I'd welcome it.
This ought to give you a hint (a little more than a hint):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>

enum epoch { Neogene = 23, Paleogene = 65, Cretaceous = 136, Jurassic = 192, Triassic = 225, Permian = 280,
             Carboniferous = 345, Devonian = 395, Silurian = 435, Ordovician = 500, Cambrian = 570, Precambrian = 4500 } ;

const int epoch_end[] = { Neogene, Paleogene, Cretaceous, Jurassic, Triassic, Permian,
                          Carboniferous, Devonian, Silurian, Ordovician, Cambrian, Precambrian } ;

const int N = sizeof(epoch_end) / sizeof( epoch_end[0] ) ;

const char* const epoch_name[N] = { "Neogene", "Paleogene", "Cretaceous", "Jurassic", "Triassic", "Permian",
	                            "Carboniferous", "Devonian", "Silurian", "Ordovician", "Cambrian", "Precambrian" } ;

int main ()
{
	int start_year, end_year ; // these go backwards
	std::cin >> start_year >> end_year ;

	int i = 0 ;
	while( start_year > epoch_end[i] ) ++i ; // get to the epoch of the start year

	while( end_year > epoch_end[i] && i < N ) // keep going back through epochs till we reach end_year
        {
            std::cout << epoch_name[i] << ' ' ; // print the name of each epoch as we pass through it
            ++i ;
        }
        if( i < N ) std::cout << epoch_name[i] << '\n' ; // print the epoch of the end_year
	else std::cout << "before Precambrian\n" ;
}

http://coliru.stacked-crooked.com/a/def94109055063d8
It's a bit hard trying to see what you're doing since you call an int array instead of using a function like I did.

I tried to emulate what you did using for loops I mad this:

1
2
3
4
5
6
7
for (year = 0; year <= endDate; year = period(year+1)) 
		std::cout << periodNames[beginPeriod] << "\n" << std::endl; // prints out the corresponding name
		
	
	 for (endDate = 0; endDate > year; year && period(year+1)) 
		 std::cout << periodNames[endPeriod] << "\n" << std::endl; // prints out the corresponding name
		


But it only outputs Neogene like 20 times.

I'll keep working on it. I know it has something to do with that && operator but I'm not doing the actual math right.
Last edited on
If year is (say) 150, the epoch is Jurassic.
Increment year by one; and 151 is still Jurassic. 152 too is Jurassic

You need to increment year by durations of epochs: 1 to 24, 24 to 66, 66 to 137, 137 to 193 etc.
I understand. When I type year as 0 through 23 it does output Neogene like I want it to.

EDIT: whew I finally did it!

Yes, I had to use a for loop to get the beginPeriod and endPeriod to correspond to each other (by having beginPeriod be less than or equal endPeriod then increcemnt beginPeriod by ++.

I will update my first post with the correct code. Hopefully this helps someone else who has this problem.
Last edited on
What is the purpose of lastPeriod()? It is exactly the same as getPeriod().
If two functions are identical, then you only need one of them.
For some reason I thought I needed to make another function for the endDate variable but it wasn't necessary (I forgot to delete it though.)
Topic archived. No new replies allowed.