8-Bit Software Online Conversion

An alternative input function is gets() which reads a string of characters from the stream stdin until a newline character is detected. The newline character is replaced by a null (0 byte) in the target string. This function has the advantage of allowing whitespace to be read in. The following program is a modification to the earlier one, using gets() instead of scanf(). #include <stdio.h> #include <stdlib.h> #include <string.h> main() { char data[80]; char *p; char name[30]; int age; printf("\nEnter your name and age "); /* Read in a string of data */ gets(data); /* P is a pointer to the last character in the input string */ p = &data[strlen(data) - 1]; /* Remove any trailing spaces by replacing them with null bytes */ while(*p == ' '){ *p = 0; p--; } /* Locate last space in the string */ p = strrchr(data,' '); /* Read age from string and convert to an integer */ age = atoi(p); /* Terminate data string at start of age field */ *p = 0; /* Copy data string to name variable */ strcpy(name,data); /* Display results */ printf("\nName is %s age is %d",name,age); } The most common output function is printf() which is very similar to scanf() except that it writes formatted data out to the standard output stream stdout. Printf() takes a list of output data fields and applies format specifiers to each and outputs the result. The format specifiers are basicaly the same as for scanf() except that flags may be added to the format specifiers. These flags include; - Which left justifies the output padding to the right with spaces. + Which causes numbers to be prefixed by their sign The width specifier is also slightly different for printf(). In its most useful form is the precision specifier; width.precision So, to print a floating point number to three decimal places you would use; printf("%.3f",x); And to pad a string with spaces to the right or truncate the string to twenty characters if it is longer, to form a fixed twenty character width; printf("%-20.20s",data); Special character constants may appear in the printf() parameter list. These are; \n Newline \r Carriage return \t Tab \b Sound the computer's bell \f Formfeed \v Vertical tab \\ Backslash character \' Single quote \" Double quote \? Question mark \O Octal string \x Hexadecimal string Thus, to display "Hello World", surrounded in quote marks and followed by a newline you would use; printf("\"Hello World\"\n"); The following program shows how a decimal integer may be displayed as a decimal, hexadecimal or octal integer. The 04 following the % in the printf() format tells the compiler to pad the displayed figure to a width of at least four digits padded with leading zeroes if required. /* A simple decimal to hexadecimal and octal conversion program */ #include <stdio.h> main() { int x; do{ printf("\nEnter a number, or 0 to end "); scanf("%d",&x); printf("%04d %04X %04o",x,x,x); }while(x != 0); } There are associated functions to printf() which you should be aware of. fprintf() has the prototype; fprintf(FILE *fp,char *format[,argument,...]); This variation on printf() simply sends the formatted output to the specfied file stream. sprintf() has the function prototype; sprintf(char *s,char *format[,argument,...]); and writes the formatted output to a string. You should take care using sprintf() that the target string has been declared long enough to hold the result of the sprintf() output. Otherwise other data will be overwritten in memory. An example of using sprintf() to copy multiple data to a string; #include<stdio.h> int main() { char buffer[50]; sprintf(buffer,"7 * 5 == %d\n",7 * 5); puts(buffer); } An alternative to printf() for outputting a simple string to the stream stdout is puts(). This function sends a string to the stream stdout followed by a newline character. It is faster than printf(), but far less flexible. Instead of; printf("Hello World\n"); You can use; puts("Hello World"); PROGRAM CONTROL STATEMENTS As with any computer language, C includes statements which test the outcome of an expression. The outcome of the test is either TRUE or FALSE. The C language defines a value of TRUE as being non-zero, and FALSE as being zero. Selection statements: The general purpose selection statement is "if" which follows the general form; if (expression) statement else statement Where "statement" may be a single statement, or a code block enclosed in curly braces. The "else" is optional. If the result of the expression equates to TRUE, then the statement(s) following the if() will be evaluated. Otherwise the statement(s) following the else, if there is one, will be evaluated. An alternative to the if....else combination is the ?: command which takes the form; expression ? true_expression : false_expression Where if the expression evaluates to TRUE, then the true_expression will be evaluated, otherwise the false_expression will be evaluated. Thus we get; #include <stdio.h> main() { int x; x = 6; printf("\nx is an %s number", x % 2 == 0 ? "even" : "odd"); } C also provides a multiple branch selection statement, switch, which successively tests a value of an expression against a list of values and branches program execution to the first match found. The general form of switch is; switch (expression){ case value1 : statements break; case value2 : statements break; case valuen : statements break; default : statements The break statement is optional, but if ommited, program execution will continue down the list. #include <stdio.h> main() { int x; x = 6; switch(x){ case 0 : printf("\nx equals zero"); break; case 1 : printf("\nx equals one"); break; case 2 : printf("\nx equals two"); break; case 3 : printf("\nx equals three"); break; default : printf("\nx is larger than three"); } } Switch statements may be nested within one another. This is a particuarly useful feature for confusing people who read your source code! Iteration statements: C provides three looping or iteration statements; for, while, and do-while. The for loop has the general form; for(initialization;condition;increment) and is useful for counters such as in this example which displays the entire ascii character set; #include <stdio.h> main() { int x; for(x = 32; x < 128; x++) printf("%d\t%c\t",x,x); } An infinite for loop is also quite valid; for(;;){ statements } Also, C allows empty statements. The following for loop removes leading spaces from a string; for(; *str == ' '; str++) ; Notice the lack of an initializer, and the empty statement following the loop. The while loop is somewhat simpler than the for loop and follows the general form; while (condition) statements The statement following the condition, or statements enclosed in curly braces will be executed untill the condition is FALSE. If the condition is false before the loop commences, the loop statements will not be executed. The do- while loop on the other hand is always executed at least once. It takes the general form; do{ statements }while(condition); Jump statements: The "return" statement is used to return from a function to the calling function. Depending upon the declared return data type of the function it may or may not return a value; int MULT(int x, int y) { return(x * y); } or; void FUNCA() { printf("\nHello World"); return; } The "break" statement is used to break out of a loop or from a switch statement. In a loop it may be used to terminate the loop prematurely, as shown here; #include <stdio.h> main() { int x; for(x = 0; x < 256; x++){ if (x == 100) break; printf("%d\t",x); } } In contrast to "break" is "continue", which forces the next iteration of the loop to occur, effectively forcing program contol back to the loop statement. C provides a function for terminating the program prematurely, "exit()". Exit() may be used with a return value to pass back to the calling program; exit(return_value); POINTERS A pointer is a variable which holds the memory address of an item of data. Hence it points to another item. A pointer is declared like an ordinary variable, but its name is prefixed by '*', thus; char *p; This declares the variable 'p' to be a pointer to a character variable. Pointers are very powerful, and similarly dangerous! If only because a pointer can be inadvertently set to point to the code segment of a program and then some value assigned to the address of the pointer! The following program illustrates a simple, though fairly useless application of a pointer; #include <stdio.h> main() { int a; int *x; /* x is a pointer to an integer data type */ a = 100; x = &a; printf("\nVariable 'a' holds the value %d at memory address %p",a,x); } Here is a more useful example of a pointer illustrating how because the compiler knows the type of data pointed to by the pointer, when the pointer is incremented it is incremented the correct number of bytes for the data type. In this case two bytes; #include <stdio.h> main() { int n; int a[25]; int *x; /* x is a pointer to an integer data type */ /* Assign x to point to array element zero */ x = a; /* Assign values to the array */ for(n = 0; n < 25; n++) a[n] = n; /* Now print out all array element values */ for(n = 0; n < 25; n++ , x++) printf("\nElement %d holds %d",n,*x); } To read or assign a value to the address held by a pointer you use the indirection operator '*'. Thus in the above example, to print the value at the memory address pointed to by variable x we have used '*x'. Pointers may be incremented and decremented and have other mathematics applied to them also. For example in the above program to move variable x along the array one element at a time we put the statement 'x++' in the for loop. We could move x along two elements by saying 'x += 2'. Notice that this doesn't mean "add 2 bytes to the value of x", but rather it means "add 2 of the pointer's data type size units to the value of x". Pointers are used extensively in dynamic memory allocation. When a program is running it is often necessary to temporarily allocate a block of data, say a table, in memory. C provides the function malloc() for this purpose which follows the general form; any pointer type = malloc(number_of_bytes); malloc() actually returns a void pointer type, which means it can be any type; integer, character, floating point or whatever. This example allocates a table in memory for 1000 integers; #include <stdio.h> #include <stdlib.h> main() { int *x; int n; /* x is a pointer to an integer data type */ /* Create a 1000 element table, sizeof() returns the compiler */ /* specific number of bytes used to store an integer */ x = malloc(1000 * sizeof(int)); /* Check to see if the memory allocation succeeded */ if (x == NULL){ printf("\nUnable to allocate a 1000 element integer table"); exit(0); } /* Assign values to each table element */ for(n = 0; n < 1000; n++){ *x = n; x++; } /* Return x to the start of the table */ x -= 1000; /* Display the values in the table */ for(n = 0; n < 1000; n++){ printf("\nElement %d holds a value of %d",n,*x); x++; } /* Deallocate the block of memory now its no longer required */ free(x); } Pointers are also extensively used with character arrays, called strings. Since all C program strings are terminated by a zero byte we can count the letters in a string using a pointer; #include <stdio.h> #include <string.h> main() { char *p; char text[100]; int len; /* Initialise variable 'text' with some writing */ strcpy(text,"This is a string of data"); /* Set variable p to the start of variable text */ p = text; /* Initialise variable len to zero */ len = 0; /* Count the characters in variable text */ while(*p){ len++; p++; } /* Display the result */ printf("\nThe string of data has %d characters in it",len); } FUNCTIONS Functions are the source code procedures which comprise a C program. They follow the general form; return_type function_name(parameter_list) { statements } The return_type specifies the data type which will be returned by the function; char, int, double, void &c. The code within a C function is invisible to any other C function, and jumps may not be made from one function into the middle of another, although functions may call other functions. Also, functions cannot be defined within functions, only within source modules. Parameters may be passed to a function either by value, or by reference. If a parameter is passed by value, then only a copy of the current value of the parameter is passed to the function. A parameter passed by reference however, is a pointer to the actual parameter which may then be changed by the function. The following example passes two parameters by value to a function, funca(), which attempts to change the value of the variables passed to it. And then passes the same two parameters by reference to funcb() which also attempts to modify their values.