Age Generating Console Program

Everything todo with programming goes HERE.
Post Reply
User avatar
Ratchet
Match Winner
Posts: 779
Joined: Sat Mar 15, 2008 5:55 am

Age Generating Console Program

Post by Ratchet »

The reasoning behind posting this is to gather constructive criticism on my form, and see what you experts have to say about how I went about what I was trying to accomplish.

Before I spam the code in my post: This program is designed to request your date of birth information (seperately, I didn't know how to do it in one single MM/DD/YYYY input..)

Then, request the current date info (again, didn't know how to gather 3 values in one input)
and then calculate the age and verify no flaws in the calculation.

In some questions, please do forgive my lack of better wording... :D

Edit: For the sake of syntax highlighting and ease of reading, I took the code [previously posted below] and posted it on codepad (similar to pastebin but for coding)

http://codepad.org/UCOUJZUF
Image
"Dream as if you'll live forever,
Live as if you'll die today." -James Dean
User avatar
Ratchet
Match Winner
Posts: 779
Joined: Sat Mar 15, 2008 5:55 am

Re: Age Generating Console Program

Post by Ratchet »

Just an update, I've been using a pretty largely populated Programming forum for my needs, as the day progressed today I've received lots of pointers and criticism, and I figured I'd share with you guys (if any are interested) how much it has changed :D

http://codepad.org/pWCQcrX8

Discussion thread here.
Image
"Dream as if you'll live forever,
Live as if you'll die today." -James Dean
User avatar
Jonathan
A Brave Victim
Posts: 3391
Joined: Thu Feb 03, 2005 12:50 am
Location: Not really lurking anymore

Re: Age Generating Console Program

Post by Jonathan »

It's cool you're getting somewhere. Did you try using functions yet? Maybe try the date comparison in one:

Code: Select all

int compare_dates(int year1, int month1, int day1, int year2, int month2, int day2)
{
    if (year1 != year2)
        return year1 > year2 ? 1 : -1;
        // a common trick is to return year1 - year2 instead of the ternary expression, if you can tolerate the possibility of overflow, and don't need exactly -1/1 (just positive/negative without a specific value)
    if (month1 != month2)
        return month1 > month2 ? 1 : -1;
    if (day1 != day2)
        return day1 > day2 ? 1 : -1;
    return 0;
}

// some code
int cmp = compare_dates(...);
if (cmp < 0) {
    // first is less
} else if (cmp > 0) {
    // first is greater
} else { // cmp == 0
    // equal
}
That's how you usually compare multi-valued things: you start at the most significant value, returning whether it is larger or smaller if it's different, or you move on to the next value.

If you're wondering about ?:, that's the ternary operator. a ? b : c means, if a evaluates to true, evaluate b, otherwise evaluate c (and pass the resulting value). A sort of slightly different compact if-else. Handy in cases like the above, but don't clutter your code with it just because you can.

Note that standard C++ comparators (like used in STL containers and such) just return one boolean, usually less-than. But that isn't important to get the concept.
ˌɑrməˈɡɛˌtrɑn
User avatar
Ratchet
Match Winner
Posts: 779
Joined: Sat Mar 15, 2008 5:55 am

Re: Age Generating Console Program

Post by Ratchet »

Yes, I understand what you are getting at.

Compare one variable at a time, got it.
as for the ?:, I recently read about , I don't remember the exact page though. I understand it.
EDIT: Found it; Here is how I interpreted it.

Code: Select all

condition ? result1 : result2


If condition is true the expression will return result1, if it is not it will return result2.

One thing I've yet to get to in a tutorial is defining other (functions? I think)

int main()

but I want to also make another block of code that I can refer to at some point in time:

example

Code: Select all

int main()
{
   if(sky == blue)
        {
               secondarycodeblock();
        }

}
secondarycodeblock()
{
     cout << "Hi, the Sky is Blue.\n";
}
I don't really completely understand that.




Another thing I need help with (This I cannot find really anywheres)

Converting string formats. Let's say in that program I'm trying to ask the user for a "yes" or "no" answer.

What if the user says "Yes"? The program will take if(answ == "yes") as false, and go to the next block

Alternatively, I know I can include every possibility of "yes" by separating them by the || operator, but it is a bit simpler to convert the string to lowercase and just test for "yes" or "no"

So far; this is the only method I know.

Code: Select all

#include <algorithm>

(...)

transform ( answ.begin(), answ.end(), answ.begin(), ptr_fun(::tolower) );

What is required to do it in a more simplistic manner? If there are no common C++ codes to achieve this, how hard(and what do I need to do) would it be to set up a .h file(or whatever) to #include, and be able to "create" a command so-to-speak?

example

Code: Select all

#include <"strconvert.h"> //use the complicated way to create "function" or "command" to simply refer to for use during programs

(...)

strlower(variablenamehere); //created command
Image
"Dream as if you'll live forever,
Live as if you'll die today." -James Dean
User avatar
Jonathan
A Brave Victim
Posts: 3391
Joined: Thu Feb 03, 2005 12:50 am
Location: Not really lurking anymore

Re: Age Generating Console Program

Post by Jonathan »

Those other blocks of code you're talking about are functions. You can have them in the same file or another, whatever works best. E.g, same file:

Code: Select all

#include <iostream>

using namespace std;

double square(double x)
{
    return x * x;
}

int main(int argc, char **argv)
{
    double x;
    cout << "Please enter a number: ";
    cin >> x;
    cout << x << " squared is " << square(x);
    return 0;
}

Code: Select all

#include <iostream>

using namespace std;

double square(double x); // just a declaration allows you to use it; definition comes later

int main(int argc, char **argv)
{
    double x;
    cout << "Please enter a number: ";
    cin >> x;
    cout << x << " squared is " << square(x);
    return 0;
}

double square(double x) // the definition itself also works as declaration as you saw in the previous example, but it would have to appear before every place it's used
{
    return x * x;
}
Separate file:

main.cpp:

Code: Select all

#include <iostream>
#include "square.h" // you could just declare the function directly instead of including, but that becomes impossible to maintain when you have many files

// the definition generally lives in one file, and since that file is square.cpp here, it won't appear in any way in main.cpp
// prepare for some of that to change and get messy with templates and inline code

using namespace std;

int main(int argc, char **argv)
{
    double x;
    cout << "Please enter a number: ";
    cin >> x;
    cout << x << " squared is " << square(x);
    return 0;
}
square.h:

Code: Select all

#ifndef SQUARE_H // if not defined, parse until the matching #endif, else skip
#define SQUARE_H // define so next time around we won't parse
// the above is a basic include guard (prevents the header from being parsed 3000 times when headers include headers that include headers...)
// you'll want to make sure the name you use is likely to be unique, such as by including the project name, file name, etc. (SQUARE_H alone is pretty bad)

double square(double x);

#endif
square.cpp:

Code: Select all

#include "square.h" // although it isn't necessary in this case, usually files include their 'own' headers
// it's how implementation files know about their own classes (which often appear in headers) and some more

double square(double x)
{
    return x * x;
}
You can have varying numbers of arguments of varying types:

Code: Select all

#include <iostream>
#include <string>

using namespace std;

void multiply(float x, float y) // void means no return value
{
    cout << x << " times " << y << " equals " << x * y << endl;
}

string repeat(string str, int times)
{
    string ret; // classes can self-initialize, as will string
    // int x; would have an undefined value
    // string x; becomes the empty string

    // filler code: string concatenation using exponentiation algorithm
    // you don't have to figure this out
    while (times > 0) {
        if (times % 2 != 0) // if it's odd
            ret += str;
        str += str; // you can do this since functions get their own copy of arguments (if you don't use references or such)
        times /= 2; // positive integers will round downwards
    }
    return ret;
}

int main(int argc, char **argv)
{
    multiply(2, 5);
    cout << repeat("hi ", 23) << endl;
    return 0;
}
All untested, but I hope you get the idea. If it's too chaotic, see if you can grasp one thing at a time.
ˌɑrməˈɡɛˌtrɑn
User avatar
Ratchet
Match Winner
Posts: 779
Joined: Sat Mar 15, 2008 5:55 am

Re: Age Generating Console Program

Post by Ratchet »

Oh, I've been learning rapidly, Jonathan. I should've updated the thread... I now understand functions (for the most part), and the current issue is Pointers and Arrays. I, again, for the most part understand the arrays, but pointers are completely over my head. The whole referencing the address of variables and pointing to addresses is very overwhelming.

As for the string conversion, a fella from the cplusplus.com forums helped me make a mystringconv.h file, which includes a function for uppercasing strings and lowercasing them.

It works as follows:

Code: Select all

#include "mystringconv.h"

[...]

strlwr(stringnamehere);
strupr(stringnamehere);
The mystringconv.h file is :

Code: Select all

#ifndef MYSTRINGCONV_H_INCLUDED

#define MYSTRINGCONV_H_INCLUDED



#include <algorithm>
#include <cctype>
#include <functional>
#include <string>

//lowercase command below strlower(string);
inline std::string& strlwr( std::string& s )
  {
  std::transform( s.begin(), s.end(), s.begin(), std::ptr_fun <int, int> ( std::tolower ) );
  return s;
  }

inline std::string strlower( const std::string& s )
  {
  std::string result( s );
  return strlwr( result );
  }
//uppercase command below strupper(string);
inline std::string& strupr( std::string& s )
  {
  std::transform( s.begin(), s.end(), s.begin(), std::ptr_fun <int, int> ( std::toupper ) );
  return s;
  }

inline std::string strupper( const std::string& s )
  {
  std::string result( s );
  return strupr( result );
  }



#endif // MYSTRINGCONV_H_INCLUDED

Image
"Dream as if you'll live forever,
Live as if you'll die today." -James Dean
User avatar
Jonathan
A Brave Victim
Posts: 3391
Joined: Thu Feb 03, 2005 12:50 am
Location: Not really lurking anymore

Re: Age Generating Console Program

Post by Jonathan »

You'd better fall in love with pointers. Because that much hate wouldn't be healthy!

The main thing to keep in mind with pointer is that they point at something else, so you'd better make sure that something else still exists when you use it.

Code: Select all

int *p;
{
    int x = 42;
    p = &x; // Assign the address of x to the pointer.
    *p += 10; // *p is equivalent to x.
    {
        int x;
        *p /= 2; // Very clever, but I meant *p is equivalent to the original variable. Not some other variable that happens to override its name in a new scope. p still points at the physical variable you originally took the address from.
    }
    // x is now 26
}
// Don't do this, as x is gone: *p = 0xFA1L;
int y;
p = &y; // The pointer itself is reusable; just don't dereference it when it points at something invalid.
*p = 123;

Code: Select all

int *f()
{
    int x = 'x';
    return &x; // Don't do this either. x will be gone when the caller gets the pointer.
    // A friend who tried C blamed this mistake on the strtok of his C library until I showed him what he did. :-)
    // C/C++ is the designated toolset to shoot yourself in the foot and stab yourself in the back at the same time. The fact that the code can be very fast just means you'll hurt yourself faster.
}
Dynamic memory allocation will be more fun.
ˌɑrməˈɡɛˌtrɑn
User avatar
Ratchet
Match Winner
Posts: 779
Joined: Sat Mar 15, 2008 5:55 am

Re: Age Generating Console Program

Post by Ratchet »

:'( Even with your professional commentary of the code operation, I still cannot make much sense of its use.

I understand as follows:

p = &x; // meaning p takes the memory location of x ( 0xbab380ba ) <-- random example

I don't understand why you declare *p as a pointer, and randomly in and out use the asterisk... Some times you do some times you don't

to me, it would be *p = &x;

I just as an overall thing cannot grasp the usefulness or meaning of pointing and referencing.
Image
"Dream as if you'll live forever,
Live as if you'll die today." -James Dean
User avatar
Jonathan
A Brave Victim
Posts: 3391
Joined: Thu Feb 03, 2005 12:50 am
Location: Not really lurking anymore

Re: Age Generating Console Program

Post by Jonathan »

Ah, yeah.

Without the asterisk, you're accessing the pointer itself. With the asterisk, you've dereferenced the pointer and are accessing the value it points at. So, without the asterisk you can assign a new address to the pointer, add something to it (which will advance its position in an array), to change what it points at, or pass it around. With the asterisk, anything you do will leave the pointer alone and instead access the value it points at.

Something that might be confusing is when you initialize a pointer in its definition. Although there's an asterisk, that asterisk just designates its type, and the assignment is like one without asterisks. E.g.

Code: Select all

int x;
int *p = &x;
int *q;
q = &x; // same thing
Good uses of pointers are to support data structures, to have something you can pass around instead of an array, as iterators, to pass a variable to a function that can be written to or so it won't have to be copied, and some more. In C++ abstracted iterators and references can replace lots of that, but it's still the same concept.

Code: Select all

// cheap way to return two values
void sincos(double *sin_return, double *cos_return, double x)
{
    *sin_return = sin(x);
    *cos_return = cos(x);
    // can reuse other function like this: sincos(*sin_return, *cos_return, x);
}

// how it looks to use this:
double sin_return, cos_return;
sincos(&sin_return, &cos_return, 1.23);

// C++ way
// references are similar to implicitly-dereferenced pointers
void sincos(double &sin_return, double &cos_return, double x)
{
    sin_return = sin(x);
    cos_return = cos(x);
    // can reuse other function like this: sincos(&sin_return, &cos_return, x);
}

// how it looks to use this:
double sin_return, cos_return;
sincos(sin_return, cos_return, 1.23);

// array points to the first value
// count is the number of values in the array (or however many you want to add up)
// don't worry too much about const if you didn't arrive there yet
int count_ints_in_array(const int *array, int count)
{
    int sum = 0;
    while (count-- > 0)
        sum += *array++; // precedence: *(array++), aka postincrement the pointer, and dereference that (so you dereference the pointer as it was before the increment)
    return sum;
// alternate version:
    int sum = 0;
    for (int i=0; i<count; ++i)
        sum += array[i];
    return sum;
}

// how it looks to use this:
int array[100];
for (int i=0; i<100; ++i)
    array[i] = i;
int sum = count_of_ints_in_array(array, 100);
I recommend that you look at linked lists as your first data structure.

Also try some dynamic memory allocation, as you can use it to have variable amounts of data not limited by stack space, and you need pointers to use it.

P.S. Professional? I sound like an amateur at best! At least to myself it sounds like a poorly explained incoherent mess of too many new concepts at once. :)
ˌɑrməˈɡɛˌtrɑn
Post Reply