Other Sectors & Exams - Tutorials & Notes
Advertisement Partners
|
|
Written by Admin
|
|
Thursday, 19 February 2009 06:24 |
|
Arrays Arrays are useful critters that often show up when it would be convenient to have one name for a group of variables of the same type that can be accessed by a numerical index. For example, a tic-tac-toe board can be held in an array and each element of the tic-tac-toe board can easily be accessed by its position (the upper left might be position 0 and the lower right position 8). At heart, arrays are essentially a way to store many values under the same name. You can make an array out of any data-type including structures and classes.
One way to visualize an array is like this: [][][][][][] Each of the bracket pairs is a slot in the array, and you can store information in slot--the information stored in the array is called an element of the array. It is very much as though you have a group of variables lined up side by side. Let's look at the syntax for declaring an array.
int examplearray[100]; /* This declares an array */ This would make an integer array with 100 slots (the places in which values of an array are stored). To access a specific part element of the array, you merely put the array name and, in brackets, an index number. This corresponds to a specific element of the array. The one trick is that the first index number, and thus the first element, is zero, and the last is the number of elements minus one. The indices for a 100 element array range from 0 to 99. Be careful not to "walk off the end" of the array by trying to access element 100! What can you do with this simple knowledge? Lets say you want to store a string, because C has no built-in datatype for strings, you can make an array of characters. For example:
char astring[100]; will allow you to declare a char array of 100 elements, or slots. Then you can receive input into it from the user, and when the user types in a string, it will go in the array, the first character of the string will be at position 0, the second character at position 1, and so forth. It is relatvely easy to work with strings in this way because it allows support for any size string you can imagine all stored in a single variable with each element in the string stored in an adjacent location--think about how hard it would be to store nearly arbitrary sized strings using simple variables that only store one value. Since we can write loops that increment integers, it's very easy to scan through a string:
char astring[10]; int i = 0; /* Using scanf isn't really the best way to do this; we'll talk about that in the next tutorial, on strings */ scanf( "%s", astring ); for ( i = 0; i < 10; ++i ) { if ( astring[i] == 'a' ) { printf( "You entered an a!\n" ); } } Let's look at something new here: the scanf function call is a tad different from what we've seen before. First of all, the format string is '%s' instead of '%d'; this just tells scanf to read in a string instead of an integer. Second, we don't use the ampersand! It turns out that when we pass arrays into functions, the compiler automatically converts the array into a pointer to the first element of the array. In short, the array without any brackets will act like a pointer. So we just pass the array directly into scanf without using the ampersand and it works perfectly. Also, notice that to access the element of the array, we just use the brackets and put in the index whose value interests us; in this case, we go from 0 to 9, checking each element to see if it's equal to the character a. Note that some of these values may actually be uninitialized since the user might not input a string that fills the whole array--we'll look into how strings are handled in more detail in the next tutorial; for now, the key is simply to understand the power of accessing the array using a numerical index. Imagine how you would write that if you didn't have access to arrays! Oh boy. Multidimensional arrays are arrays that have more than one index: instead of being just a single line of slots, multidimensional arrays can be thought of as having values that spread across two or more dimensions. Here's an easy way to visualize a two-dimensional array: [][][][][] [][][][][] [][][][][] [][][][][] [][][][][] The syntax used to actually declare a two dimensional array is almost the same as that used for declaring a one-dimensional array, except that you include a set of brackets for each dimension, and include the size of the dimension. For example, here is an array that is large enough to hold a standard checkers board, with 8 rows and 8 columns:
int two_dimensional_array[8][8]; You can easily use this to store information about some kind of game or to write something like tic-tac-toe. To access it, all you need are two variables, one that goes in the first slot and one that goes in the second slot. You can make three dimensional, four dimensional, or even higher dimensional arrays, though past three dimensions, it becomes quite hard to visualize. Setting the value of an array element is as easy as accessing the element and performing an assignment. For instance,
[] = for instance,
/* set the first element of my_first to be the letter c */ my_string[0] = 'c'; or, for two dimensional arrays
[][] = ; Let me note again that you should never attempt to write data past the last element of the array, such as when you have a 10 element array, and you try to write to the [10] element. The memory for the array that was allocated for it will only be ten locations in memory, (the elements 0 through 9) but the next location could be anything. Writing to random memory could cause unpredictable effects--for example you might end up writing to the video buffer and change the video display, or you might write to memory being used by an open document and altering its contents. Usually, the operating system will not allow this kind of reckless behavior and will crash the program if it tries to write to unallocated memory. You will find lots of useful things to do with arrays, from storing information about certain things under one name, to making games like tic-tac-toe. We've already seen one example of using loops to access arrays; here is another, more interesting, example!
#include int main() { int x; int y; int array[8][8]; /* Declares an array like a chessboard */
for ( x = 0; x < 8; x++ ) { for ( y = 0; y < 8; y++ ) array[x][y] = x * y; /* Set each element to a value */ } printf( "Array Indices:\n" ); for ( x = 0; x < 8;x++ ) { for ( y = 0; y < 8; y++ ) { printf( "[%d][%d]=%d", x, y, array[x][y] ); } printf( "\n" ); } getchar(); } Just to touch upon a final point made briefly above: arrays don't require a reference operator (the ampersand) when you want to have a pointer to them. For example:
char *ptr; char str[40]; ptr = str; /* Gives the memory address without a reference operator(&) */ As opposed to
int *ptr; int num; ptr = # /* Requires & to give the memory address to the ptr */ The fact that arrays can act just like pointers can cause a great deal of confusion.
|
|
Written by Admin
|
|
Thursday, 19 February 2009 06:31 |
Character Arrays A string constant , such as "I am a string" is an array of characters. It is represented internally in C by the ASCII characters in the string, i.e., ``I'', blank, ``a'', ``m'',... for the above string, and terminated by the special null character ``\0'' so programs can find the end of the string. String constants are often used in making the output of code intelligible using printf ; printf("Hello, world\n"); printf("The value of a is: %f\n", a); String constants can be associated with variables. C provides the char type variable, which can contain one character--1 byte--at a time. A character string is stored in an array of character type, one ASCII character per location. Never forget that, since strings are conventionally terminated by the null character ``\0'', we require one extra storage location in the array! C does not provide any operator which manipulate entire strings at once. Strings are manipulated either via pointers or via special routines available from the standard string library string.h. Using character pointers is relatively easy since the name of an array is a just a pointer to its first element. Consider the following code: -------------------------------------------------------------------------------- void main() { char text_1[100], text_2[100], text_3[100]; char *ta, *tb; int i; /* set message to be an arrray */ /* of characters; initialize it */ /* to the constant string "..." */ /* let the compiler decide on */ /* its size by using [] */ char message[] = "Hello, I am a string; what are you?"; printf("Original message: %s\n", message); /* copy the message to text_1 */ /* the hard way */ i=0; while ( (text_1[i] = message[i]) != '\0' ) i++; printf("Text_1: %s\n", text_1); /* use explicit pointer arithmetic */ ta=message; tb=text_2; while ( ( *tb++ = *ta++ ) != '\0' ) ; printf("Text_2: %s\n", text_2); } -------------------------------------------------------------------------------- The standard ``string'' library contains many useful functions to manipulate strings; a description of this library can be found in an appendix of the K & R textbook. Some of the most useful functions are: char *strcpy(s,ct) -> copy ct into s, including ``\0''; return s char *strncpy(s,ct,n) -> copy ncharcater of ct into s, return s char *strncat(s,ct) -> concatenate ct to end of s; return s char *strncat(s,ct,n) -> concatenate n character of ct to end of s, terminate with ``\0''; return s int strcmp(cs,ct) -> compare cs and ct; return 0 if cs=ct, ct char *strchr(cs,c) -> return pointer to first occurence of c in cs or NULL if not encountered size_t strlen(cs) -> return length of cs (s and t are char*, cs and ct are const char*, c is an char converted to type int, and n is an int.) Consider the following code which uses some of these functions: -------------------------------------------------------------------------------- #include void main() { char line[100], *sub_text; /* initialize string */ strcpy(line,"hello, I am a string;"); printf("Line: %s\n", line); /* add to end of string */ strcat(line," what are you?"); printf("Line: %s\n", line); /* find length of string */ /* strlen brings back */ /* length as type size_t */ printf("Length of line: %d\n", (int)strlen(line)); /* find occurence of substrings */ if ( (sub_text = strchr ( line, 'W' ) )!= NULL ) printf("String starting with \"W\" ->%s\n", sub_text); if ( ( sub_text = strchr ( line, 'w' ) )!= NULL ) printf("String starting with \"w\" ->%s\n", sub_text); if ( ( sub_text = strchr ( sub_text, 'u' ) )!= NULL ) printf("String starting with \"w\" ->%s\n", sub_text);
|
|
Written by Admin
|
|
Thursday, 19 February 2009 06:36 |
|
Command-line Arguments It is standard practice in UNIX for information to be passed from the command line directly into a program through the use of one or more command-line arguments, or switches. Switches are typically used to modify the behavior of a program, or to set the values of some internal parameters. You have already encountered several of these--for example, the "ls" command lists the files in your current directory, but when the switch -l is added, "ls -l" produces a so-called ``long'' listing instead. Similarly, "ls -l -a" produces a long listing, including ``hidden'' files, the command "tail -20" prints out the last 20 lines of a file (instead of the default 10), and so on. Conceptually, switches behave very much like arguments to functions within C, and they are passed to a C program from the operating system in precisely the same way as arguments are passed between functions. Up to now, the main() statements in our programs have had nothing between the parentheses. However, UNIX actually makes available to the program (whether the programmer chooses to use the information or not) two arguments to main: an array of character strings, conventionally called argv, and an integer, usually called argc, which specifies the number of strings in that array. The full statement of the first line of the program is main(int argc, char** argv) (The syntax char** argv declares argv to be a pointer to a pointer to a character, that is, a pointer to a character array (a character string)--in other words, an array of character strings. You could also write this as char* argv[]. Don't worry too much about the details of the syntax, however--the use of the array will be made clearer below.) When you run a program, the array argv contains, in order, all the information on the command line when you entered the command (strings are delineated by whitespace), including the command itself. The integer argc gives the total number of strings, and is therefore equal to equal to the number of arguments plus one. For example, if you typed a.out -i 2 -g -x 3 4 the program would receive argc = 7 argv[0] = "a.out" argv[1] = "-i" argv[2] = "2" argv[3] = "-g" argv[4] = "-x" argv[5] = "3" argv[6] = "4" Note that the arguments, even the numeric ones, are all strings at this point. It is the programmer's job to decode them and decide what to do with them. The following program simply prints out its own name and arguments: #include main(int argc, char** argv) { int i; printf("argc = %d\n", argc); for (i = 0; i < argc; i++) printf("argv[%d] = \"%s\"\n", i, argv[i]); } UNIX programmers have certain conventions about how to interpret the argument list. They are by no means mandatory, but it will make your program easier for others to use and understand if you stick to them. First, switches and key terms are always preceded by a ``-'' character. This makes them easy to recognize as you loop through the argument list. Then, depending on the switch, the next arguments may contain information to be interpreted as integers, floats, or just kept as character strings. With these conventions, the most common way to ``parse'' the argument list is with a for loop and a switch statement, as follows: #include #include main(int argc, char** argv) { /* Set defaults for all parameters: */ int a_value = 0; float b_value = 0.0; char* c_value = NULL; int d1_value = 0, d2_value = 0; int i; /* Start at i = 1 to skip the command name. */ for (i = 1; i < argc; i++) { /* Check for a switch (leading "-"). */ if (argv[i][0] == '-') { /* Use the next character to decide what to do. */ switch (argv[i][1]) { case 'a': a_value = atoi(argv[++i]); break; case 'b': b_value = atof(argv[++i]); break; case 'c': c_value = argv[++i]; break; case 'd': d1_value = atoi(argv[++i]); d2_value = atoi(argv[++i]); break; } } } printf("a = %d\n", a_value); printf("b = %f\n", b_value); if (c_value != NULL) printf("c = \"%s\"\n", c_value); printf("d1 = %d, d2 = %d\n", d1_value, d2_value); } Note that argv[i][j] means the j-th character of the i-th character string. The if statement checks for a leading ``-'' (character 0), then the switch statement allows various courses of action to be taken depending on the next character in the string (character 1 here). Note the use of argv[++i] to increase i before use, allowing us to access the next string in a single compact statement. The functions atoi and atof are defined in stdlib.h. They convert from character strings to ints and doubles, respectively. A typical command line might be: a.out -a 3 -b 5.6 -c "I am a string" -d 222 111 (The use of double quotes with -c here makes sure that the shell treats the entire string, including the spaces, as a single object.) Arbitrarily complex command lines can be handled in this way. Finally, here's a simple program showing how to place parsing statements in a separate function whose purpose is to interpret the command line and set the values of its arguments: /********************************/ /* */ /* Getting arguments from */ /* */ /* the Command Line */ /* */ /********************************/ /* Steve McMillan */ /* Written: Winter 1995 */ #include #include void get_args(int argc, char** argv, int* a_value, float* b_value) { int i; /* Start at i = 1 to skip the command name. */ for (i = 1; i < argc; i++) { /* Check for a switch (leading "-"). */ if (argv[i][0] == '-') { /* Use the next character to decide what to do. */ switch (argv[i][1]) { case 'a': *a_value = atoi(argv[++i]); break; case 'b': *b_value = atof(argv[++i]); break; default: fprintf(stderr, "Unknown switch %s\n", argv[i]); } } } } main(int argc, char** argv) { /* Set defaults for all parameters: */ int a = 0; float b = 0.0; get_args(argc, argv, &a, &b); printf("a = %d\n", a); printf("b = %f\n", b); }
|
|
Written by Admin
|
|
Thursday, 19 February 2009 06:20 |
|
Conditionals
If statements The ability to control the flow of your program, letting it make decisions on what code to execute, is valuable to the programmer. The if statement allows you to control if a program enters a section of code or not based on whether a given condition is true or false. One of the important functions of the if statement is that it allows the program to select an action based upon the user's input. For example, by using an if statement to check a user-entered password, your program can decide whether a user is allowed access to the program. Without a conditional statement such as the if statement, programs would run almost the exact same way every time, always following the same sequence of function calls. If statements allow the flow of the program to be changed, which leads to more interesting code. Before discussing the actual structure of the if statement, let us examine the meaning of TRUE and FALSE in computer terminology. A true statement is one that evaluates to a nonzero number. A false statement evaluates to zero. When you perform comparison with the relational operators, the operator will return 1 if the comparison is true, or 0 if the comparison is false. For example, the check 0 == 2 evaluates to 0. The check 2 == 2 evaluates to a 1. If this confuses you, try to use a printf statement to output the result of those various comparisons (for example printf ( "%d", 2 == 1 );) When programming, the aim of the program will often require the checking of one value stored by a variable against another value to determine whether one is larger, smaller, or equal to the other. There are a number of operators that allow these checks. Here are the relational operators, as they are known, along with examples: > greater than 5 > 4 is TRUE < less than 4 < 5 is TRUE >= greater than or equal 4 >= 4 is TRUE <= less than or equal 3 <= 4 is TRUE == equal to 5 == 5 is TRUE != not equal to 5 != 4 is TRUE
It is highly probable that you have seen these before, probably with slightly different symbols. They should not present any hindrance to understanding. Now that you understand TRUE and FALSE well as the comparison operators, let us look at the actual structure of if statements. The structure of an if statement is as follows: if ( statement is TRUE ) Execute this line of code
Here is a simple example that shows the syntax: if ( 5 < 10 ) printf( "Five is now less than ten, that's a big surprise" );
Here, we're just evaluating the statement, "is five less than ten", to see if it is true or not; with any luck, it's not! If you want, you can write your own full program including stdio.h and put this in the main function and run it to test. To have more than one statement execute after an if statement that evaluates to true, use braces, like we did with the body of the main function. Anything inside braces is called a compound statement, or a block. When using if statements, the code that depends on the if statement is called the "body" of the if statement. For example:
if ( TRUE ) { /* between the braces is the body of the if statement */ Execute all statements inside the body } I recommend always putting braces following if statements. If you do this, you never have to remember to put them in when you want more than one statement to be executed, and you make the body of the if statement more visually clear. Else Sometimes when the condition in an if statement evaluates to false, it would be nice to execute some code instead of the code executed when the statement evalutes to true. The "else" statement effectively says that whatever code after it (whether a single line or code between brackets) is executed if the if statement is FALSE. It can look like this:
if ( TRUE ) { /* Execute these statements if TRUE */ } else { /* Execute these statements if FALSE */ } Else if Another use of else is when there are multiple conditional statements that may all evaluate to true, yet you want only one if statement's body to execute. You can use an "else if" statement following an if statement and its body; that way, if the first statement is true, the "else if" will be ignored, but if the if statement is false, it will then check the condition for the else if statement. If the if statement was true the else statement will not be checked. It is possible to use numerous else if statements to ensure that only one block of code is executed. Let's look at a simple program for you to try out on your own.
#include int main() /* Most important part of the program! */ { int age; /* Need a variable... */
printf( "Please enter your age" ); /* Asks for age */ scanf( "%d", &age ); /* The input is put in age */ if ( age < 100 ) { /* If the age is less than 100 */ printf ("You are pretty young!\n" ); /* Just to show you it works... */ } else if ( age == 100 ) { /* I use else just to show an example */ printf( "You are old\n" ); } else { printf( "You are really old\n" ); /* Executed if no other statement is */ } return 0; } More interesting conditions using boolean operators
Boolean operators allow you to create more complex conditional statements. For example, if you wish to check if a variable is both greater than five and less than ten, you could use the Boolean AND to ensure both var > 5 and var < 10 are true. In the following discussion of Boolean operators, I will capitalize the Boolean operators in order to distinguish them from normal English. The actual C operators of equivalent function will be described further along into the tutorial - the C symbols are not: OR, AND, NOT, although they are of equivalent function. When using if statements, you will often wish to check multiple different conditions. You must understand the Boolean operators OR, NOT, and AND. The boolean operators function in a similar way to the comparison operators: each returns 0 if evaluates to FALSE or 1 if it evaluates to TRUE. NOT: The NOT operator accepts one input. If that input is TRUE, it returns FALSE, and if that input is FALSE, it returns TRUE. For example, NOT (1) evalutes to 0, and NOT (0) evalutes to 1. NOT (any number but zero) evaluates to 0. In C NOT is written as !. NOT is evaluated prior to both AND and OR. AND: This is another important command. AND returns TRUE if both inputs are TRUE (if 'this' AND 'that' are true). (1) AND (0) would evaluate to zero because one of the inputs is false (both must be TRUE for it to evaluate to TRUE). (1) AND (1) evaluates to 1. (any number but 0) AND (0) evaluates to 0. The AND operator is written && in C. Do not be confused by thinking it checks equality between numbers: it does not. Keep in mind that the AND operator is evaluated before the OR operator. OR: Very useful is the OR statement! If either (or both) of the two values it checks are TRUE then it returns TRUE. For example, (1) OR (0) evaluates to 1. (0) OR (0) evaluates to 0. The OR is written as || in C. Those are the pipe characters. On your keyboard, they may look like a stretched colon. On my computer the pipe shares its key with \. Keep in mind that OR will be evaluated after AND. It is possible to combine several Boolean operators in a single statement; often you will find doing so to be of great value when creating complex expressions for if statements. What is !(1 && 0)? Of course, it would be TRUE. It is true is because 1 && 0 evaluates to 0 and !0 evaluates to TRUE (ie, 1). Try some of these - they're not too hard. If you have questions about them, feel free to stop by our forums.
A. !( 1 || 0 ) ANSWER: 0 B. !( 1 || 1 && 0 ) ANSWER: 0 (AND is evaluated before OR) C. !( ( 1 || 0 ) && 0 ) ANSWER: 1 (Parenthesis are useful)
Switch Case
Switch case statements are a substitute for long if statements that compare a variable to several "integral" values ("integral" values are simply values that can be expressed as an integer, such as the value of a char). The basic format for using switch case is outlined below. The value of the variable given into switch is compared to the value following each of the cases, and when one value matches the value of the variable, the computer continues executing the program from that point.
switch ( ) { case this-value: Code to execute if == this-value break; case that-value: Code to execute if == that-value break; ... default: Code to execute if does not equal the value following any of the cases break; } The condition of a switch statement is a value. The case says that if it has the value of whatever is after that case then do whatever follows the colon. The break is used to break out of the case statements. Break is a keyword that breaks out of the code block, usually surrounded by braces, which it is in. In this case, break prevents the program from falling through and executing the code in all the other case statements. An important thing to note about the switch statement is that the case values may only be constant integral expressions. Sadly, it isn't legal to use case like this:
int a = 10; int b = 10; int c = 20; switch ( a ) { case b: /* Code */ break; case c: /* Code */ break; default: /* Code */ break; } The default case is optional, but it is wise to include it as it handles any unexpected cases. It can be useful to put some kind of output to alert you to the code entering the default case if you don't expect it to. Switch statements serve as a simple way to write long if statements when the requirements are met. Often it can be used to process input from a user. Below is a sample program, in which not all of the proper functions are actually declared, but which shows how one would use switch in a program.
#include void playgame(); void loadgame(); void playmultiplayer();
int main() { int input; printf( "1. Play game\n" ); printf( "2. Load game\n" ); printf( "3. Play multiplayer\n" ); printf( "4. Exit\n" ); printf( "Selection: " ); scanf( "%d", &input ); switch ( input ) { case 1: /* Note the colon, not a semicolon */ playgame(); break; case 2: loadgame(); break; case 3: playmultiplayer(); break; case 4: printf( "Thanks for playing!\n" ); break; default: printf( "Bad input, quitting!\n" ); break; } getchar(); } This program will compile, but cannot be run until the undefined functions are given bodies, but it serves as a model (albeit simple) for processing input. If you do not understand this then try mentally putting in if statements for the case statements. Default simply skips out of the switch case construction and allows the program to terminate naturally. If you do not like that, then you can make a loop around the whole thing to have it wait for valid input. You could easily make a few small functions if you wish to test the code.
|
|
|
|
<< Start < Prev 1 2 3 4 Next > End >>
|
|
Page 1 of 4 |
|
Information Technology - Tutorials & Notes
|