Presentation is loading. Please wait.

Presentation is loading. Please wait.

Programming in C Miscellaneous Topics.

Similar presentations


Presentation on theme: "Programming in C Miscellaneous Topics."— Presentation transcript:

1 Programming in C Miscellaneous Topics

2 Fixed 2-d Arrays Number of rows and columns fixed at compile time int gameBoard [ 5 ] [ 3 ]; 5 rows, 3 columns Use 2-d indexing int x = gameBoard[ row ][ col ]; (0,0) (0,1) (0,2) (1,0) (1,1) (1,2) (2,0) (2,1) (2,2) (3,0) (3,1) (3,2) (4,0) (4,1) (4,2) 7/28/09

3 Dynamic 2-d Arrays (1) Number of rows fixed at compile time, but variable number of columns in each row Really an array of int*, where each int* points to the row. Indexing with row / column still ok 3 rows, each dynamically allocated with (possibly) different number of columns (row sizes) int *gameBoard[ 3 ]; The rows, possibly different sizes gameBoard[ 0 ] = (int *)malloc( 4 * sizeof( int )); gameBoard[ 1 ] = (int *)malloc( 6 * sizeof( int )); gameBoard[ 2 ] = (int *)malloc( 8 * sizeof( int )); 7/28/09

4 Dynamic 2-d Arrays (2) Number of rows and columns dynamically allocated. Indexing with row / column still ok A pointer to the (first element of the) array of row pointers int **gameBoard; The array of row pointers gameBoard = (int **)malloc( 3 * sizeof( int *)); The rows, possibly different sizes gameBoard[ 0 ] = (int *)malloc( 4 * sizeof( int )); gameBoard[ 1 ] = (int *)malloc( 6 * sizeof( int )); gameBoard[ 2 ] = (int *)malloc( 8 * sizeof( int )); 7/28/09

5 Compiler directives Compiler directives begin with # and are interpreted by the preprocessor The most common directives are #include Used for file inclusion (See K&R ) #define Used for constant/macro definitions (see K&R ) #if, #ifdef, #ifndef, #else, #elif, #endif Used for conditional compilation (see K&R ) 7/28/09

6 #include The #include directive is used to include the contents of another file into the file being compiled. It is usually used to include header (.h) files into the source. #include files may be nested so that one .h file may #include another .h file A line of the form #include <filename> causes replacement of that line by the entire contents of the file filename. The named file is searched for in implementation specific places, usually /usr/include on Linux Similarly, a line of the form #include “filename” first searches in the same directory as the source file, and if that search fails, continues searching as above. 7/28/09

7 #define A line of the form #define identifier token-sequence
Causes the preprocessor to replace all occurrences of identifier with the token-sequence (except in quoted strings). Note that this is a text replacement. #defines are most commonly used to give names to “magic constants” For example #define MAXSIZE 100 replaces every occurrence of MAXSIZE with 100 as in int table[MAXSIZE]; 7/28/09

8 #define macros The #define directive may also be used to create a simple macro. Care must be taken when writing macros and when calling macros because the arguments are copied literally. For example, the simple macro below doesn’t work properly in all instances. #define SQUARE(x) x * x Assuming int z = 4, what is the value of y after the assignment int y = SQUARE( z - 1 ); Even when written correctly as #define SQUARE(x) (x) * (x) Calling the macro may result in erroneous side effects. Assuming again that int z = 4, what is the value of z after the assignment int y = SQUARE( ++z ) Nonetheless, macros like this can make code easier to read as we’ll see later 7/28/09

9 Importing #defines The most common way to #define symbols is within your .c file #define DEBUG #define MAX 100 It is also possible to “import” #defines on the compiler command line gcc -o myProg -DDEBUG -DMAX=100 myProg.c You cannot use the command line to redefine a symbol already defined in your .c file 7/28/09

10 Predefined Constants The C pre-processor predefines several #define constants __FILE__ is the name of the file being compiled __LINE__ is the current line number being compiled These may be helpful if printed as part of debug output printf(“Bad Input: %s, %d\n”, __FILE__, __LINE__); 7/28/09

11 assert( ) The C library provides a macro named assert( ) which can be very helpful for debugging The parameter to assert is any boolean expression -- assert( expression ); If the boolean expression is true, nothing happens and execution continues on the next line If the boolean expression is false, a message is printed to stderr and your program terminates To use assert( ), you must #include <assert.h> assert( ) may be disabled by #define NDEBUG prior to #include <assert.h> Or by importing NDEBUG via the command line 7/28/09

12 Using assert( ) Use assert( ) to verify an array index
int scores[100]; int k = <some complicated calculation > assert( k >= 0 && k < 1000 ); Use assert( ) to check for NULL pointers int *ptr = malloc( 4 * sizeof( int ) ); assert( ptr != NULL); Use assert( ) to check functions that shouldn’t fail int errorCode = foo ( ); assert( errorCode == 0); /* but NOT assert(foo( ) == 0); */ 7/28/09

13 Conditional Compilation
The preprocessor directives #ifdef (read as “if defined”), #ifndef (read as “if not defined”), #if, #else, #elif (read as “else if”), and #endif (together with #defines) can be used to control which lines in a course file are compiled and which are not. Each directive appears on a separate line. Each #if and subsequent #elif is evaluated as true (1) or false (0) based on the definition (or lack of definition) of the identifier that follows. Lines that follow a false (0) evaluation are skipped. Conditional compilation is frequently used to avoid multiple inclusions of the same header (.h) file, compiling lines used for debugging, and (in system level .h files) to compile certain lines based on the type of system on which the program is being compiled. 7/28/09

14 Conditional Compilation for header files
Header (.h) files should only be included once in a source file to avoid compilation errors. Suppose the file myheader.h is #included into some source file. The .h files should be “guarded” as follows #ifndef MYHEADER_H /* same as #if !defined(MYHEADER_H) */ #define MYHEADER_H .... ... #endif How does this work? Whenever the compiler includes myheader.h, the #ifndef checks to see if the identifier MYHEADER_H has be #defined. The first time myheader.h is included, MYHEADER_H will not have been defined so the lines in the header file (in particular #define MYHEADER_H) will be included into the source file. Thereafter, when the compiler subsequently tries to include myheader.h, the #ifndef will evaluate to false (because MYHEADER_H is now defined) and all lines in myheader.h will be skipped, avoiding duplicate inclusion. 7/28/09

15 Conditional Compilation for Debugging
One simple way of debugging a program is to insert printf( ) statements are strategic points in the code. When the program is run, the output of these printf( ) statements help you debug your program. When the program is bug free, these printf( ) statements are removed from your code. Rather than removing the printf( ) statements by editting your code, conditional compilation can be used to allow or prevent them from being executed. 7/28/09

16 debug.c #ifdef DEBUG_ON #define DEBUG(x) printf(x) #else
#endif int main (int argc, char *argv[] ) { int i, count, sum = 0; assert( arcg == 2); DEBUG( "Command Line arg is: %s\n“, argv[1]); count = atoi( argv[1] ); DEBUG( "Entering for loop\n"); for (i = 0; i < count; i++) sum += i; } DEBUG ("exited for loop\n"); printf("sum = %d\n", sum); return 0;

17 Program organization main( ) is generally defined in its own .c file and generally just calls helper functions Program-specific helper functions in another .c file If there are very few helpers, they can be in the same file as main( ) Reusable functions in their own .c file Group related functions in the same file Each struct or union Defined in a separate .h file Related functions in a separate .c file File names should be indicative of the struct name 7/28/09

18 Variable Scope and Lifetime
The scope of a variable refers to that part of a program that may refer to the variable. The lifetime of a variable refers to the time in which a variable occupies a place in memory The scope and lifetime of a variable are determined by how and where the variable is defined 7/28/09

19 Global Variables Global (external) variables are defined outside of any function, near the top of your .c file. May be used anywhere in the .c file in which they are defined. Exist for the duration of your program May be used by any other .c file in your program that declares them as “extern” (unless also defined as static) Static global variables may only be used in the .c file that declares them “extern” declarations for global variables should be placed into a header file 7/28/09

20 Local variables Local variables are defined within the opening and closing braces of a function, loop, if-statement, etc. Function parameters are local to the function. Are usable only within the braces in which they are defined Exist only during the execution of the block unless also defined as static Static local variables retain their values for the duration of your program. Usually used in functions, they retain their values between calls to the function. 7/28/09

21 Function Scope All functions are external because C does not allow nesting of function definitions. So no “extern” declaration is needed All functions may be called from any .c file in your program unless they are also declared as static. Static functions may only be used within the .c file in which they are defined 7/28/09

22 variableScope.c - part 1 #include <stdio.h>
// extern definition of randomInt and prototype for getRandomInt #include “randomInt.h” /* a global variable that can only be used by functions in this .c file */ static int inputValue; /* a function that can only be called by other functions in this .c file */ static void inputPositiveInt( char *prompt ) { /* init to invalid value to enter while loop */ inputValue = -1; while (inputValue <= 0) printf( "%s", prompt); scanf( "%d", &inputValue); } 7/28/09

23 variableScope.c - part 2 /* main is the entry point for all programs */ int main( ) { /* local/automatic variables that can only be used in this function and that are destroyed when the function ends */ int i, maxValue, nrValues; inputPositiveInt("Input max random value to generate: "); maxValue = inputValue; inputPositiveInt("Input number of random ints to generate: "); nrValues = inputValue; for (i = 0; i < nrValues; i++) getRandomInt( maxValue ); printf( “%d: %d\n", i + 1, randomInt ); } return 0; /* successful completion */ 7/28/09

24 randomInt.c int randomInt; void getRandomInt( int max )
/* a global variable to be used by code in other .c files. ** This variable exists until the program ends ** Other .c files must declare this variable as "extern" ** holds the random number that was generated */ int randomInt; /* a function that can be called from any other function ** returns a random integer from 1 to max, inclusive */ void getRandomInt( int max ) { /* a local variable that can only be used inside this function, ** but persists between calls to this function */ static long lastRandom = ; lastRandom = (lastRandom * 125) % ; randomInt = (lastRandom % max) + 1; } 7/28/09

25 randomInt.h #ifndef RANDOMINT_H #define RANDOMINT_H
// global variable in randomint.c // set by calling getRandomInt( ) extern int randomInt; // prototypes for function in randomInt.c void getRandomInt(int max ); #endif 7/28/09


Download ppt "Programming in C Miscellaneous Topics."

Similar presentations


Ads by Google