php기초



Lesson 1: The basics of C++

This tutorial series is designed for everyone: even if you've never programmed before or if you have extensive experience programming in other languages and want to expand into C++! It is for everyone who wants the feeling of accomplishment from a working program. 

What do I mean? C++ is a programming language--it will allow you to control your computer, making it do what you want it to do. This programming tutorial series is all about helping you take advantage of C++.
The very first thing you need to do, before starting out in C++, is to make sure that you have a compiler. What is a compiler, you ask? A compiler turns the program that you write into an executable that your computer can actually understand and run. If you're taking a course, you probably have one provided through your school. If you're starting out on your own, your best bet is to use Code::Blocks. Our page on setting up Code::Blocks will take you through setting up the Code::Blocks compiler in great detail.

Advanced Compiler Details

If you've got some prior experience, or just want a menu of choices, you should know that there are several common compilers. If you're new to programming, just skip this section! 

Some common compilers include Borland C++Microsoft C++, and GNU C++

There are also many front-end environments for the different compilers--the most common is Dev-C++ around GNU's G++ compiler. Some, such as G++, are free, while others are not. Please see the compiler listing for more information on how to get a compiler and set it up. 

Each of these compilers is slightly different. Each one should support the ANSI/ISO standard C++ functions, but each compiler will also have nonstandard functions (these functions are similar to slang spoken in different parts of a country). Sometimes the use of nonstandard functions will cause problems when you attempt to compile source code (the actual C++ written by a programmer and saved as a text file) with a different compiler. These tutorials use ANSI/ISO standard C++ and should not suffer from this problem (with sufficiently modern compilers). Note that if you are using an older compiler, such as TCLite, you should read check out some compatibility issues

Intro to the C++ Language

A C++ program is a collection of commands, which tell the computer to do "something". This collection of commands is usually called C++ source codesource code or just code. Commands are either "functions" or "keywords". Keywords are a basic building block of the language, while functions are, in fact, usually written in terms of simpler functions--you'll see this in our very first program, below. (Confused? Think of it a bit like an outline for a book; the outline might show every chapter in the book; each chapter might have its own outline, composed of sections. Each section might have its own outline, or it might have all of the details written up.) Thankfully, C++ provides a great many common functions and keywords that you can use. 

But how does a program actually start? Every program in C++ has one function, always named main, that is always called when your program first executes. From main, you can also call other functions whether they are written by us or, as mentioned earlier, provided by the compiler. 

So how do you get access to those prewritten functions? To access those standard functions that comes with the compiler, you include a header with the #include directive. What this does is effectively take everything in the header and paste it into your program. Let's look at a working program:
 
#include <iostream>

using namespace std;

int main()
{
  cout<<"HEY, you, I'm alive! Oh, and Hello World!\n";
  cin.get();
}
Let's look at the elements of the program. The #include is a "preprocessor" directive that tells the compiler to put code from the header called iostream into our program before actually creating the executable. By including header files, you gain access to many different functions. For example, the cout function requires iostream. Following the include is the statement, "using namespace std;". This line tells the compiler to use a group of functions that are part of the standard library (std). By including this line at the top of a file, you allow the program to use functions such as cout. The semicolon is part of the syntax of C++. It tells the compiler that you're at the end of a command. You will see later that the semicolon is used to end most commands in C++. 

The next important line is int main(). This line tells the compiler that there is a function named main, and that the function returns an integer, hence int. The "curly braces" ({ and }) signal the beginning and end of functions and other code blocks. You can think of them as meaning BEGIN and END. 

The next line of the program may seem strange. If you have programmed in another language, you might expect that print would be the function used to display text. In C++, however, the cout object is used to display text (pronounced "C out"). It uses the << symbols, known as "insertion operators", to indicate what to output. cout<< results in a function call with the ensuing text as an argument to the function. The quotes tell the compiler that you want to output the literal string as-is. The '\n' sequence is actually treated as a single character that stands for a newline (we'll talk about this later in more detail). It moves the cursor on your screen to the next line. Again, notice the semicolon: it is added onto the end of most lines, such as function calls, in C++. 

The next command is cin.get(). This is another function call: it reads in input and expects the user to hit the return key. Many compiler environments will open a new console window, run the program, and then close the window. This command keeps that window from closing because the program is not done yet because it waits for you to hit enter. Including that line gives you time to see the program run. 

Upon reaching the end of main, the closing brace, our program will return the value of 0 (and integer, hence why we told main to return an int) to the operating system. This return value is important as it can be used to tell the OS whether our program succeeded or not. A return value of 0 means success and is returned automatically (but only for main, other functions require you to manually return a value), but if we wanted to return something else, such as 1, we would have to do it with a return statement:
 
#include <iostream>

using namespace std;

int main()
{
  cout<<"HEY, you, I'm alive! Oh, and Hello World!\n";
  cin.get();

  return 1;
}
The final brace closes off the function. You should try compiling this program and running it. You can cut and paste the code into a file, save it as a .cpp file. Our Code::Blocks tutorial actually takes you through creating a simple program, so check it out if you're confused. 

If you are not using Code::Blocks, you should read the compiler instructions for information on how to compile. 
Once you've got your first program running, why don't you try playing around with the cout function to get used to writing C++?

An Aside on Commenting Your Programs

As you are learning to program, you should also start to learn how to explain your programs (for yourself, if no one else). You do this by adding comments to code; I'll use them frequently to help explain code examples. 

When you tell the compiler a section of text is a comment, it will ignore it when running the code, allowing you to use any text you want to describe the real code. To create a comment use either //, which tells the compiler that the rest of the line is a comment, or /* and then */ to block off everything between as a comment. Certain compiler environments will change the color of a commented area, but some will not. Be certain not to accidentally comment out code (that is, to tell the compiler part of your code is a comment) you need for the program. When you are learning to program, it is useful to be able to comment out sections of code in order to see how the output is affected. 

User interaction and Saving Information with Variables

So far you've learned how to write a simple program to display information typed in by you, the programmer, and how to describe your program with comments. That's great, but what about interacting with your user? Fortunately, it is also possible for your program to accept input. The function you use is known as cin, and is followed by the insertion operator >>. 

Of course, before you try to receive input, you must have a place to store that input. In programming, input and data are stored in variables. There are several different types of variables which store different kinds of information (e.g. numbers versus letters); when you tell the compiler you are declaring a variable, you must include the data type along with the name of the variable. Several basic types include char, int, and float. 

A variable of type char stores a single character, variables of type int store integers (numbers without decimal places), and variables of type float store numbers with decimal places. Each of these variable types - char, int, and float - is each a keyword that you use when you declare a variable.

What's with all these variable types?

Sometimes it can be confusing to have multiple variable types when it seems like some variable types are redundant (why have integer numbers when you have floats?). Using the right variable type can be important for making your code readable and for efficiency--some variables require more memory than others. Moreover, because of the way the numbers are actually stored in memory, a float is "inexact", and should not be used when you need to store an "exact" integer value. 

Declaring Variables in C++

To declare a variable you use the syntax "type <name>;". Here are some variable declaration examples:
 
int x;
char letter;
float the_float;
It is permissible to declare multiple variables of the same type on the same line; each one should be separated by a comma.
int a, b, c, d;
If you were watching closely, you might have seen that declaration of a variable is always followed by a semicolon (note that this is the same procedure used when you call a function).

Common Errors when Declaring Variables in C++

If you attempt to use a variable that you have not declared, your program will not be compiled or run, and you will receive an error message informing you that you have made a mistake. Usually, this is called an undeclared variable.

Case Sensitivity

Now is a good time to talk about an important concept that can easily throw you off: case sensitivity. Basically, in C++, whether you use uppercase or lowercase letters matters. The words Cat and cat mean different things to the compiler. In C++, all language keywords, all functions and all variables are case sensitive. A difference in case between your variable declaration and the use of the variable is one reason you might get an undeclared variable error.

Using Variables

Ok, so you now know how to tell the compiler about variables, but what about using them? 

Here is a sample program demonstrating the use of a variable:
 
#include <iostream>

using namespace std;

int main()
{
  int thisisanumber;

  cout<<"Please enter a number: ";
  cin>> thisisanumber;
  cin.ignore();
  cout<<"You entered: "<< thisisanumber <<"\n";
  cin.get();
}
Let's break apart this program and examine it line by line. The keyword int declares thisisanumber to be an integer. The function cin>> reads a value into thisisanumber; the user must press enter before the number is read by the program. cin.ignore() is another function that reads and discards a character. Remember that when you type input into a program, it takes the enter key too. We don't need this, so we throw it away. Keep in mind that the variable was declared an integer; if the user attempts to type in a decimal number, it will be truncated (that is, the decimal component of the number will be ignored). Try typing in a sequence of characters or a decimal number when you run the example program; the response will vary from input to input, but in no case is it particularly pretty. Notice that when printing out a variable quotation marks are not used. Were there quotation marks, the output would be "You Entered: thisisanumber." The lack of quotation marks informs the compiler that there is a variable, and therefore that the program should check the value of the variable in order to replace the variable name with the variable when executing the output function. Do not be confused by the inclusion of two separate insertion operators on one line. Including multiple insertion operators on one line is perfectly acceptable and all of the output will go to the same place. In fact, you must separate string literals (strings enclosed in quotation marks) and variables by giving each its own insertion operators (<<). Trying to put two variables together with only one << will give you an error message, do not try it. Do not forget to end functions and declarations with a semicolon. If you forget the semicolon, the compiler will give you an error message when you attempt to compile the program.

Changing and Comparing Variables

Of course, no matter what type you use, variables are uninteresting without the ability to modify them. Several operators used with variables include the following: *, -, +, /, =, ==, >, <. The * multiplies, the - subtracts, and the + adds. It is of course important to realize that to modify the value of a variable inside the program it is rather important to use the equal sign. In some languages, the equal sign compares the value of the left and right values, but in C++ == is used for that task. The equal sign is still extremely useful. It sets the left input to the equal sign, which must be one, and only one, variable equal to the value on the right side of the equal sign. The operators that perform mathematical functions should be used on the right side of an equal sign in order to assign the result to a variable on the left side. 

Here are a few examples:
 
a = 4 * 6; // (Note use of comments and of semicolon) a is 24
a = a + 5; // a equals the original value of a with five added to it
a == 5     // Does NOT assign five to a. Rather, it checks to see if a equals 5.
The other form of equal, ==, is not a way to assign a value to a variable. Rather, it checks to see if the variables are equal. It is useful in other areas of C++; for example, you will often use == in such constructions as conditional statements and loops. You can probably guess how < and > function. They are greater than and less than operators. 

For example:
 
a < 5  // Checks to see if a is less than five
a > 5  // Checks to see if a is greater than five
a == 5 // Checks to see if a equals five, for good measure 
Comparing variables isn't really useful until you have some way of using the results--that's what lesson 2, on if statements is all about. 

'프로그래밍 > C, C++' 카테고리의 다른 글

구구단 출력 소스 C  (0) 2011.06.07
8진수, 16진수의 이해  (0) 2011.06.07
2진 트리 검색  (0) 2011.06.07
The C Preprocessor  (0) 2011.06.07
The C++ Modulus Operator  (0) 2011.06.07
** CTable. Version 1.0.
*/
/*NOTE: Minor Changes have been made to enable this program to run under TClite
Credit goes to David van Leerdam
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <conio.h>

#define NAMELEN 11
#define MAX 10
#define MIN 1

char name[NAMELEN];
short int number,wrong;
int table,answer,ch;
int checktable(int table);

int checktable(int table);
void cap(char *ptr2name);


int main(void)
{
printf("\nCTable by David van Leerdam\n");
printf("Please enter your name (max. %d): ",NAMELEN-1);
gets(name);
cap(name);
printf("\nDo you want to practise some tables? (Y/N) ",name);
ch = toupper((int)getch());

if (ch == 'N') {
printf("\nOkidoki %s, but you'll have to do extra tomorrow!\n",name);
exit(EXIT_SUCCESS); }

else

do {
wrong=0;
printf("\nWhich table? ");
scanf("%d",&table);
checktable(table);
  number = MIN;

// hier worden de tafelsommen gemaakt
// en gecontroleerd.

do {
printf("%d x %d = ",number,table);
scanf("%d",&answer);
if (answer != (number*table))
{
printf("WRONG! %d x %d = %d!\n",number,table,number*table);
wrong++;
}

// beoordeling.

} while (number++ != (MAX));
switch(wrong) {
case 0: printf("\n%s: I'm proud of you! No wrong answer found practising table of %d!",name,table); break;
case 1:
case 2: printf("\n%s: Good work! You gave only %d wrong answers doing table of %d.",name,wrong,table); break;
case 3:
case 4: printf("\n%s: Can't you do a lot better? %d wrong anwers found doing table of %d.",name,wrong,table); break;
default : printf("\n%s: Practise a little more. You gave %d wrong answers doing table %d.",name,wrong,table); }
printf("\nDo you want to practice again? (Y/N) ");
ch = toupper((int)getch());
printf("\n");
} while (ch != 'N');
printf("\nCTable version 1.0. Copyright by David van Leerdam.\n");
}

// hier wordt gecontroleerd of het tafelnr. een heel getal is.
int checktable(int table)
{
if ((table < 0) || (table == '\n')) {
fprintf(stderr,"\nERROR: Input has to be a valid positive integer.\n");
exit(EXIT_FAILURE); }
   return 1;
      }

// verander de eerste letter van de naam in een hoofdletter.

void cap(char *ptr2name)
{
if(ptr2name[0])
*ptr2name = toupper((int)*ptr2name);
}

'프로그래밍 > C, C++' 카테고리의 다른 글

레슨 1: The basics of C++ ( C++ 의 기본 )  (0) 2011.06.07
8진수, 16진수의 이해  (0) 2011.06.07
2진 트리 검색  (0) 2011.06.07
The C Preprocessor  (0) 2011.06.07
The C++ Modulus Operator  (0) 2011.06.07

Understanding Different Base Systems

This essay is targeted at new students of computer programming or computer science who want to understand how base two (binary), base eight (octal), and base sixteen (hexadecimal) work. 

First of all, it's important to realize that each of these base systems is just another way of writing down the same number. When you convert a number between different bases, it should still have the same value. In this essay, when I want to refer to the actual value of a number (regardless of its base), I'll do it in base 10 because that's what most people are used to. 

It's generally easiest to understand the concept of different bases by looking at base 10. When we have a number in base 10, each digit can be referred to as the ones digit, tens digit, the hundreds digit, the thousands digit, or so forth. For instance, in the number 432, 4 is the hundreds digit, 3 is the tens digit, and 2 is the ones digit. 

Another way to think about this is to rewrite 432 as
  4 x 102 + 3 x 101+ 2 x 100
Each digit is multiplied by the next power of ten. Numbers in other bases, such as base 16, are merely numbers where the base is not ten! For instance, we could interpret 432 as though it were in base 16 by evaluating it as
  4 x 162 + 3 x 161+ 2 x 100
This would be the same as the number 1074 in base 10. 

So to convert a number from a given base into base 10, all we need to do is treat each place as a power of the given base times the value of the digit in that place. Note that customarily for a given base, only digits from 0 to the base minus one are used. For instance, in decimal, we only use the digits 0 through 9. That's because we don't need any more digits to express every possible number. (But we do need at least that many; if we only had 8 digits, how would we ever express the value 9?) 

Now, bases greater than 10 will require more than 10 possible digits. For intsance, the number 11 in base ten can be expressed in base 16 with only a single digit because the ones place in base 16 can range from 0 to 15. Since we only have 10 digits, the letters A through F are used to stand for the "digits" 10 through 15. So, for instance, the hexadecimal number B stands for the decimal number 11. 

Bases less than ten will require fewer digits--for instance, binary, which works using powers of two, only needs two digits: one and zero. The binary number 1001, for instance, is the same as writing
 1 * 231 * 221 * 211 * 20
which comes out to the decimal value 9. 

Numbers written in octal use a base of 8 instead of 2 or 16. See if you can figure out what the number 20 written in octal would be in base ten. 

Because octal, hexadecimal, and decimal numbers can often share the same digits, there needs to be some way of distinguishing between them. Traditionally, octal numbers are written with a leading 0; for instance, 020 is the same thing as the number 20 in base 8. Hexadecimal numbers are written with the prefix of "0x". So 0x20 would be the number 20 in base 16; we'd interpret it the same as the decimal number 32.

Converting from decimal to octal or hexadecimal

It turns out that when you wish to convert from decimal to octal or hexadecimal, there is a very easy formula that you can use. I'll give you the one for octal, and let you puzzle out the hexadecimal version (which may come quite naturally to some of you). 

To convert from octal to hexadecimal, all you need to do is group the binary digits into pairs of three and convert each one into the corresponding octal number. For instance, given the binary number 010011110, you would group 011 and 110 together. 010 is 2, 011 is 3 and 110 is 6. So the octal number is 0236. 

So why exactly does this work? Well, let's take a look at what 011110 looks like:
   0 * 28  1 * 27  0 * 26  0 * 25+ 1 * 24+ 1 * 23+ 1 * 22+ 1 * 21+ 0 * 20
That's actually the same as
   0 * 22 * 26+ 1 * 21 * 26+ 0 * 20 * 26+ 0 * 22 * 23+ 1 * 21 * 23+ 1 * 20 * 23+ 1 * 22 * 20+ 1 * 21 * 20+ 0 * 20 * 20
Whoa! First, notice that the far right column is actually turning into powers of 8! 23 is 8, and 26 is 64! So this means for each group of three digits, we have the base increasing by a factor of 8. Moreover, look at the right hand column. It can sum up to at most 7 (since 20 + 21 + 22 = 1 + 2 + 4 and the binary digit just decides whether each power of two is included into the sum or not). That's exactly the same as having eight digits, 0 through 7, and once we sum them all together, we multiply the sum by a power of eight. That's just the same as making each group of three binary digits an octal digit! 

Knowing this, can you come up with the way to do the same thing for hexadecimal numbers? 

'프로그래밍 > C, C++' 카테고리의 다른 글

레슨 1: The basics of C++ ( C++ 의 기본 )  (0) 2011.06.07
구구단 출력 소스 C  (0) 2011.06.07
2진 트리 검색  (0) 2011.06.07
The C Preprocessor  (0) 2011.06.07
The C++ Modulus Operator  (0) 2011.06.07

Binary Search Trees
Binary search trees (also known as just binary trees) are ordered trees in which all nodes have no more than two children. The parent node is always greater than all of the data in the left sub-tree that extends from the left child node, and the parent node is less than all of the data in the right sub-tree that extends from the right child node.

Here is the basic framwork for the binary search tree:

class binTree {
  public:
    binTree(void);         // Constructor
    ~binTree(void);        // Destructor

    void add(int item);    // Add function
    void remove(int item); // Remove function
    bool search(int item); // Search function
    void print(void);      // Print function
  
  private:
    binTreeNode *root;     // Root pointer

    // ...
    // The extra functions needed for implementation are put here
};

class binTreeNode {
  public:
    int data;                 // Actual data
    binTreeNode *left_child;  // Left child pointer
    binTreeNode *right_child; // Right child pointer
};

This code is very similar to the code of the linked list, but the node here is differs from the node to the linked list in that thisbinTreeNode points to two other nodes instead of just one.

Since the left child is always less than the parent and the right child is greater than the parent, the tree can easily print an ordered list of all of the elements with the following algorithm, also known as in-order traversal:

void printTree(binTreeNode *node) {
  printTree(node->left_child);  // Left child first
  cout << node->data << endl;   // Then this node
  printTree(node->right_child); // Then right child
}

To print the tree, you would call the function with the value of root. Each time, the function would keep calling itself (recursion!) until it reaches the leftmost node, which is the least value in the entire tree. Then, it would cycle through the entire tree, and then the right children, until it reaches the rightmost, or greatest, value in the tree.

Other traversals of trees are pre-order and post-order traversals. In pre-order, the root is processed first, then the left children, and then the right children. In post-order, the left children and right children are processed before the root.

Try writing the code for the binary tree as an exercise. It's a little tricky this time, especially with the remove() function. (HINT: Most of the functions require helper, or auxiliary, functions. Some, but definitely not all, of the functions may be recursive.)

'프로그래밍 > C, C++' 카테고리의 다른 글

구구단 출력 소스 C  (0) 2011.06.07
8진수, 16진수의 이해  (0) 2011.06.07
The C Preprocessor  (0) 2011.06.07
The C++ Modulus Operator  (0) 2011.06.07
Getting Random Values in C and C++ with Rand  (0) 2011.06.07




The C Preprocessor

The C preprocessor modifies a source code file before handing it over to the compiler. You're most likely used to using the preprocessor to include files directly into other files, or #define constants, but the preprocessor can also be used to create "inlined" code using macros expanded at compile time and to prevent code from being compiled twice. 

There are essentially three uses of the preprocessor--directives, constants, and macros. Directives are commands that tell the preprocessor to skip part of a file, include another file, or define a constant or macro. Directives always begin with a sharp sign (#) and for readability should be placed flush to the left of the page. All other uses of the preprocessor involve processing #define'd constants or macros. Typically, constants and macros are written in ALL CAPS to indicate they are special (as we will see).

Header Files

The #include directive tells the preprocessor to grab the text of a file and place it directly into the current file. Typically, such statements are placed at the top of a program--hence the name "header file" for files thus included.

Constants

If we write
#define [identifier name] [value]
whenever [identifier name] shows up in the file, it will be replaced by [value]. 

If you are defining a constant in terms of a mathematical expression, it is wise to surround the entire value in parentheses:
#define PI_PLUS_ONE (3.14 + 1)
By doing so, you avoid the possibility that an order of operations issue will destroy the meaning of your constant:
x = PI_PLUS_ONE * 5;
Without parentheses, the above would be converted to
x = 3.14 + 1 * 5;
which would result in 1 * 5 being evaluated before the addition, not after. Oops! 

It is also possible to write simply
#define [identifier name]
which defines [identifier name] without giving it a value. This can be useful in conjunction with another set of directives that allow conditional compilation.

Conditional Compilation

There are a whole set of options that can be used to determine whether the preprocessor will remove lines of code before handing the file to the compiler. They include #if, #elif, #else, #ifdef, and #ifndef. An #if or #if/#elif/#else block or a #ifdef or #ifndef block must be terminated with a closing #endif. 

The #if directive takes a numerical argument that evaluates to true if it's non-zero. If its argument is false, then code until the closing #else, #elif, of #endif will be excluded.

Commenting out Code

Conditional compilation is a particularly useful way to comment out a block of code that contains multi-line comments (which cannot be nested).
#if 0
/* comment ...
*/

// code

/* comment */
#endif

Avoiding Including Files Multiple Times (idempotency)

Another common problem is that a header file is required in multiple other header files that are later included into a source code file, with the result often being that variables, structs, classes or functions appear to be defined multiple times (once for each time the header file is included). This can result in a lot of compile-time headaches. Fortunately, the preprocessor provides an easy technique for ensuring that any given file is included once and only once. 

By using the #ifndef directive, you can include a block of text only if a particular expression is undefined; then, within the header file, you can define the expression. This ensures that the code in the #ifndef is included only the first time the file is loaded.
#ifndef _FILE_NAME_H_
#define _FILE_NAME_H_

/* code */

#endif // #ifndef _FILE_NAME_H_
Notice that it's not necessary to actually give a value to the expression _FILE_NAME_H_. It's sufficient to include the line "#define _FILE_NAME_H_" to make it "defined". (Note that there is an n in #ifndef--it stands for "if not defined"). 

A similar tactic can be used for defining specific constants, such as NULL:
#ifndef NULL
#define NULL (void *)0
#endif // #ifndef NULL
Notice that it's useful to comment which conditional statement a particular #endif terminates. This is particularly true because preprocessor directives are rarely indented, so it can be hard to follow the flow of execution.

Macros

The other major use of the preprocessor is to define macros. The advantage of a macro is that it can be type-neutral (this can also be a disadvantage, of course), and it's inlined directly into the code, so there isn't any function call overhead. (Note that in C++, it's possible to get around both of these issues with templated functions and the inline keyword.) 

A macro definition is usually of the following form:
#define MACRO_NAME(arg1, arg2, ...) [code to expand to]
For instance, a simple increment macro might look like this:
#define INCREMENT(x) x++
They look a lot like function calls, but they're not so simple. There are actually a couple of tricky points when it comes to working with macros. First, remember that the exact text of the macro argument is "pasted in" to the macro. For instance, if you wrote something like this:
#define MULT(x, y) x * y
and then wrote
int z = MULT(3 + 2, 4 + 2);
what value do you expect z to end up with? The obvious answer, 30, is wrong! That's because what happens when the macro MULT expands is that it looks like this:
int z = 3 + 2 * 4 + 2;    // 2 * 4 will be evaluated first!
So z would end up with the value 13! This is almost certainly not what you want to happen. The way to avoid it is to force the arguments themselves to be evaluated before the rest of the macro body. You can do this by surrounding them by parentheses in the macro definition:
#define MULT(x, y) (x) * (y)
// now MULT(3 + 2, 4 + 2) will expand to (3 + 2) * (4 + 2)
But this isn't the only gotcha! It is also generally a good idea to surround the macro's code in parentheses if you expect it to return a value. Otherwise, you can get similar problems as when you define a constant. For instance, the following macro, which adds 5 to a given argument, has problems when embedded within a larger statement:
#define ADD_FIVE(a) (a) + 5

int x = ADD_FIVE(3) * 3;
// this expands to (3) + 5 * 3, so 5 * 3 is evaluated first
// Now x is 18, not 24!
To fix this, you generally want to surround the whole macro body with parentheses to prevent the surrounding context from affecting the macro body.
#define ADD_FIVE(a) ((a) + 5)

int x = ADD_FIVE(3) * 3;
On the other hand, if you have a multiline macro that you are using for its side effects, rather than to compute a value, you probably want to wrap it within curly braces so you don't have problems when using it following an if statement.
// We use a trick involving exclusive-or to swap two variables
#define SWAP(a, b)  a ^= b; b ^= a; a ^= b; 

int x = 10;
int y = 5;

// works OK
SWAP(x, y);

// What happens now?
if(x < 0)
    SWAP(x, y);
When SWAP is expanded in the second example, only the first statement, a ^= b, is governed by the conditional; the other two statements will always execute. What we really meant was that all of the statements should be grouped together, which we can enforce using curly braces:
#define SWAP(a, b)  {a ^= b; b ^= a; a ^= b;} 
Now, there is still a bit more to our story! What if you write code like so:
#define SWAP(a, b)  { a ^= b; b ^= a; a ^= b; }

int x = 10;
int y = 5;
int z = 4;

// What happens now?
if(x < 0)
    SWAP(x, y);
else
    SWAP(x, z); 
Then it will not compile because semicolon after the closing curly brace will break the flow between if and else. The solution? Use a do-while loop:
#define SWAP(a, b)  do { a ^= b; b ^= a; a ^= b; } while ( 0 )

int x = 10;
int y = 5;
int z = 4;

// What happens now?
if(x < 0)
    SWAP(x, y);
else
    SWAP(x, z); 
Now the semi-colon doesn't break anything because it is part of the expression. (By the way, note that we didn't surround the arguments in parentheses because we don't expect anyone to pass an expression into swap!)

More Gotchas

By now, you've probably realized why people don't really like using macros. They're dangerous, they're picky, and they're just not that safe. Perhaps the most irritating problem with macros is that you don't want to pass arguments with "side effects" to macros. By side effects, I mean any expression that does something besides evaluate to a value. For instance, ++x evaluates to x+1, but it also increments x. This increment operation is a side effect. 

The problem with side effects is that macros don't evaluate their arguments; they just paste them into the macro text when performing the substitution. So something like
#define MAX(a, b) ((a) < (b) ? (b) : (a))
int x = 5, y = 10;
int z = MAX(x++, y++);
will end up looking like this:
int x = (x++ < y++ ? y++ : x++)
The problem here is that y++ ends up being evaluated twice! The nasty consequence is that after this expression, y will have a value of 12 rather than the expected 11. This can be a real pain to debug!

Multiline macros

Until now, we've seen only short, one line macros (possibly taking advantage of the semicolon to put multiple statements on one line.) It turns out that by using a the "\" to indicate a line continuation, we can write our macros across multiple lines to make them a bit more readable. 

For instance, we could rewrite swap as
#define SWAP(a, b)  {                   \
                        a ^= b;         \
                        b ^= a;         \ 
                        a ^= b;         \
                    } 
Notice that you do not need a slash at the end of the last line! The slash tells the preprocessor that the macro continues to the next line, not that the line is a continuation from a previous line. 

Aside from readability, writing multi-line macros may make it more obvious that you need to use curly braces to surround the body because it's more clear that multiple effects are happening at once.

Advanced Macro Tricks

In addition to simple substitution, the preprocessor can also perform a bit of extra work on macro arguments, such as turning them into strings or pasting them together.

Pasting Tokens

Each argument passed to a macro is a token, and sometimes it might be expedient to paste arguments together to form a new token. This could come in handy if you have a complicated structure and you'd like to debug your program by printing out different fields. Instead of writing out the whole structure each time, you might use a macro to pass in the field of the structure to print. 

To paste tokens in a macro, use ## between the two things to paste together. 

For instance
#define BUILD_FIELD(field) my_struct.inner_struct.union_a.##field
Now, when used with a particular field name, it will expand to something like
my_struct.inner_struct.union_a.field1
The tokens are literally pasted together.

String-izing Tokens

Another potentially useful macro option is to turn a token into a string containing the literal text of the token. This might be useful for printing out the token. The syntax is simple--simply prefix the token with a pound sign (#).
#define PRINT_TOKEN(token) printf(#token " is %d", token)
For instance, PRINT_TOKEN(foo) would expand to
printf("<foo>" " is %d" <foo>)
(Note that in C, string literals next to each other are concatenated, so something like "token" " is " " this " will effectively become "token is this". This can be useful for formatting printf statements.) 

For instance, you might use it to print the value of an expression as well as the expression itself (for debugging purposes).
PRINT_TOKEN(x + y);

Avoiding Macros in C++

In C++, you should generally avoid macros when possible. You won't be able to avoid them entirely if you need the ability to paste tokens together, but with templated classes and type inference for templated functions, you shouldn't need to use macros to create type-neutral code. Inline functions should also get rid of the need for macros for efficiency reasons. (Though you aren't guaranteed that the compiler will inline your code.) 

Moreover, you should use const to declare typed constants rather than #define to create untyped (and therefore less safe) constants. Const should work in pretty much all contexts where you would want to use a #define, including declaring static sized arrays or as template parameters.

'프로그래밍 > C, C++' 카테고리의 다른 글

8진수, 16진수의 이해  (0) 2011.06.07
2진 트리 검색  (0) 2011.06.07
The C++ Modulus Operator  (0) 2011.06.07
Getting Random Values in C and C++ with Rand  (0) 2011.06.07
Formatting Cout Output in C++ using iomanip  (0) 2011.06.07

The C++ Modulus Operator

Take a simple arithmetic problem: what's left over when you divide 11 by 3? The answer is easy to compute: divide 11 by 3 and take the remainder: 2. But how would you compute this in a programming language like C or C++? It's not hard to come up with a formula, but the language provides a built-in mechanism, the modulus operator ('%'), that computes the remainder that results from performing integer division.
The modulus operator is useful in a variety of circumstances. It is commonly used to take a randomly generated number and reduce that number to a random number on a smaller range, and it can also quickly tell you if one number is a factor of another. 

If you wanted to know if a number was odd or even, you could use modulus to quickly tell you by asking for the remainder of the number when divided by 2.
#include <iostream>

using namespace std;

int main()
{
    int num;
    cin >> num;
    // num % 2 computes the remainder when num is divided by 2
    if ( num % 2 == 0 )
    {
        cout << num << " is even ";
    }

    return 0;
}
The key line is the one that performs the modulus operation: "num % 2 == 0". A number is even if and only if it is divisible by two, and a number is divisible by another only if there is no remainder. 

How could you use modulus to write a program that checks if a number is prime?

'프로그래밍 > C, C++' 카테고리의 다른 글

2진 트리 검색  (0) 2011.06.07
The C Preprocessor  (0) 2011.06.07
Getting Random Values in C and C++ with Rand  (0) 2011.06.07
Formatting Cout Output in C++ using iomanip  (0) 2011.06.07
Enumerated Types - enums  (1) 2011.06.07

Getting Random Values in C and C++ with Rand



Written by RoD

At some point in any programmer's life, he or she must learn how to get a random value, or values, in their program. To some this seems involved, difficult, or even beyond their personal ability. This, however, is simply not the case.

Randomizing of values is, at its most basic form, one of the easier things a programmer can do with the C++ language. I have created this short tutorial for Cprogramming.com to aid you in learning, constructing, and using the functions available to you to randomize values.

I will first start with an introduction to the idea of randomizing values, followed by a simple example program that will output three random values. Once a secure understanding of these concepts is in place (hopefully it will be), I will include a short program that uses a range of values from which the random values can be taken.

Ok, now that you know why this tutorial was written, and what it includes, you are ready to learn how to randomize values! So without further ado, let's get started, shall we?

Many programs that you will write require the use of random numbers. For example, a game such as backgammon requires a roll of two dice on each move. Since there are 6 numbers on each die, you could calculate each roll by finding a random number from 1 to 6 for each die.

To make this task a little easier, C++ provides us with a library function, called rand that returns an integer between 0 and RAND_MAX. Let's take a break to explain what RAND_MAX is. RAND_MAX is a compiler-dependent constant, and it is inclusive. Inclusive means that the value of RAND_MAX is included in the range of values. The function, rand, and the constant, RAND_MAX, are included in the library header file stdlib.h.

The number returned by function rand is dependent on the initial value, called a seed that remains the same for each run of a program. This means that the sequence of random numbers that is generated by the program will be exactly the same on each run of the program.

How do you solve this problem you ask? Well I'll tell you! To help us combat this problem we will use another function, srand(seed), which is also declared in the stdlib.h header file. This function allows an application to specify the initial value used by rand at program startup.

Using this method of randomization, the program will use a different seed value on every run, causing a different set of random values every run, which is what we want in this case. The problem posed to us now, of course, is how to get an arbitrary seed value. Forcing the user or programmer to enter this value every time the program was run wouldn't be very efficient at all, so we need another way to do it.

So we turn to the perfect source for our always-changing value, the system clock. The C++ data type time_t and the function time, both declared in time.h, can be used to easily retrieve the time on the computers clock.

When converted to an unsigned integer, a positive whole number, the program time (at execution of program) can make a very nice seed value. This works nicely because no two program executions will occur at the same instant of the computers clock.

As promised, here is a very basic example program. The following code was written in Visual C++ 6.0, but should compile fine on most computers (given u have a compiler, which if your reading this I assume you do). The program outputs three random values.

/*Steven Billington
January 17, 2003
Ranexample.cpp
Program displays three random integers.
*/
/*
Header: iostream
Reason: Input/Output stream
Header: cstdlib
Reason: For functions rand and srand
Header: time.h
Reason: For function time, and for data type time_t
*/
#include <iostream>
#include <cstdlib>
#include <time.h>

using namespace std;

int main()
{
/*
Declare variable to hold seconds on clock.
*/
time_t seconds;
/*
Get value from system clock and
place in seconds variable.
*/
time(&seconds);
/*
Convert seconds to a unsigned
integer.
*/
srand((unsigned int) seconds);
/*
Output random values.
*/
cout<< rand() << endl;
cout<< rand() << endl;
cout<< rand() << endl;
return 0;
}

Users of a random number generator might wish to have a narrower or a wider range of numbers than provided by the rand function. Ideally, to solve this problem a user would specify the range with integer values representing the lower and the upper bounds. To understand how we might accomplish this with the rand function, consider how to generate a number between 0 and an arbitrary upper bound, referred to as high, inclusive.

For any two integers, say a and b, a % b is between 0 and b - 1, inclusive. With this in mind, the expression rand() % high + 1 would generate a number between 1 and high, inclusive, where high is less than or equal to RAND_MAX, a constant defined by the compiler. To place a lower bound in replacement of 1 on that result, we can have the program generate a random number between 0 and (high - low + 1) + low.

I realize how confused you might be right now, so take a look at the next sample program I promised, run it, toy with it, and alternate it to give you different values. It has been a pleasure to teach you another chapter in the world of C++, and you may feel free to email me at Silent_Death17@hotmail.com or to contact me on the message boards of this fine website, where I use the name RoD.

Enjoy, and happy programming!
/*
Steven Billington
January 17, 2003
exDice.cpp
Program rolls two dice with random
results.
*/
/*
Header: iostream
Reason: Input/Output stream
Header: stdlib
Reason: For functions rand and srand
Header: time.h
Reason: For function time, and for data type time_t
*/
#include <iostream>
#include <cstdlib>
#include <time.h>
/*
These constants define our upper
and our lower bounds. The random numbers
will always be between 1 and 6, inclusive.
*/
const int LOW = 1;
const int HIGH = 6;

using namespace std;

int main()
{
/*
Variables to hold random values
for the first and the second die on
each roll.
*/
int first_die, sec_die;
/*
Declare variable to hold seconds on clock.
*/
time_t seconds;
/*
Get value from system clock and
place in seconds variable.
*/
time(&seconds);
/*
Convert seconds to a unsigned
integer.
*/
srand((unsigned int) seconds);
/*
Get first and second random numbers.
*/
first_die = rand() % (HIGH - LOW + 1) + LOW;
sec_die = rand() % (HIGH - LOW + 1) + LOW;
/*
Output first roll results.
*/
cout<< "Your roll is (" << first_die << ", "
<< sec_die << "}" << endl << endl;
/*
Get two new random values.
*/
first_die = rand() % (HIGH - LOW + 1) + LOW;
sec_die = rand() % (HIGH - LOW + 1) + LOW;
/*
Output second roll results.
*/
cout<< "My roll is (" << first_die << ", "
<< sec_die << "}" << endl << endl;
return 0;
}


'프로그래밍 > C, C++' 카테고리의 다른 글

The C Preprocessor  (0) 2011.06.07
The C++ Modulus Operator  (0) 2011.06.07
Formatting Cout Output in C++ using iomanip  (0) 2011.06.07
Enumerated Types - enums  (1) 2011.06.07
Class Design in C++ : Understanding Interfaces  (0) 2011.06.07

+ Recent posts