/* CPyDemo.c author: Dave Renner dmrenne@comcast.net date: 09/05/12 1545 */ #include #include struct myStructType { int myInt; char myChar; }; int myFunOne( int anInt ); // declarations int myFun2( struct myStructType *ms ); int Flunk( int three ); int myAltFun( int altInt); int VERBOSE = 0; const int my_const_test_number = 9; int my_test_input; int my_test_tot; char cr; int funNum; main(int argc, char *argv[]) { int cmd; if (argc == 2) { cmd = argv[1][0]; if (cmd == 'v') VERBOSE = 1; } printf("This is a tutorial showing differences between Python and C,\ \nexecuting some code and prompting the user in the process.\ \nThe reader is encouraged to print out this listing\ \nbefore executing the program."); if (VERBOSE) { printf("\nI will begin at the beginning.\n"); printf("\nA few months ago I developed a tutorial in Python,\ \navailable on this website www.maklisco.com.\ \nThis C program could be considered a follow-up to it.\ \nSo if the user is started with Python, now (s)he can learn C!\ \nAdmittedly, most programmers start with C and migrate to Python,\ \nbut I think the reasons for this are historical;\ \nI find Python easier to learn than C.\n"); printf("\nMy basis for comparing the two languages is a criteria\ \nI've developed from analysis of twelve or so languages I've studied."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("\nThe criteria are:\n"); printf("\nGeneral\nEnvironment\ \nIO\ \nGUI\ \nDatabase\ \nNetworking\ \nInternet\ \nMultithreading\ \nIntegration\ \nComponents\ \nSessions\ \nUtilities\ \nHousekeeping\ \nSecurity\ \nDesign\ \nDevelopment\ \nReflection\n."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("But this is getting a bit too academic already,\ \nsince I'll only focus on the criteria where the two languages\ \nare different enough to be interesting.\ \n\nFirst criterion: General: Python is interpreted, C/C++ is compiled.\ \nThis make little difference to the programmer, but considerable difference\ \nto the system integrator, who has to install the C compiler\ \nor the end user, who may find Python too slow for his/her needs\ \nor has product that requires C, such as a typical device driver.\ \nSecondly, C is a structured programming language\ \nwith an initial function ('main');\ \nPython -- though it may have an optional structured syntax\ \nis basically a scripting language, having a list of statements\ \nfrom top to bottom, like a Bourne shell script.\ \nWe'll look at this later."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("\nMeanwhile, the 'second criteria category': Environment:\ \nBoth run on either Windows or Unix/Linux with corresponding\ \ndownloadable tools, such as 'gcc'.\ \nNot much difference here.\ \nWhat does make C/C++ essentially different from Python\ \nis the Microsoft variation of it -- the Visual C/C++ product\ \nand its successors. This is a comprehensive, complex,\ \nMS-proprietary package in which, essentially, the programming task\ \nis hugely done by point-and-click, not by handwritten code.\ \nThis is well beyond the focus of my tutorial here.\ \nSo enough about the environment.\ \n\nThird criteria category: I/O: files, streams, stdout, etc.:\ \nReally pretty similar from Python to C and vice-versa.\ \nFourth criterion: Database support:\ \nLikewise. Python has some built-in advantages over C/C++,\ \nas one would expect in a higher-level language.\ \nI've still had to use third-party add-ons for support of\ \nspecific datatabases, though that was a few years ago;\ \nI'm sure it's been streamlined since then."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("\nFifth criterion: GUI support: Python has it, built-in.\ \nI haven't used it, preferring to build complex GUIs using Microsoft\ \nso much interactive programming now involves Web-based apps now\ \ninstead of local thick-clients.\ \nNetworking: TCP/IP, sockets, sftp, ssh, etc.\ \nPython has pretty usable high-level functions for low-level\ \nnetworking uses. Considerably easier than straight C.\ \nNot terribly unique from a programming point of view.\ \nInternet: Web-oriented stuff: HTML, HTTP, email, file transfer:\ \nSimilar to Networking\ \nMultithreading: ditto\ \nIntegration:\ \nPython has built-in facilities to include C code within it,\ \nand vice-versa. Python-to-C in Windows requires some extra add-ons;\ \nand can get messy.\ \nComponent support: DCOM, CORBA, extensibilty:\ \nI haven't found a need to get into this too much\ \nSession support:\ \nPython has 'pickle' for this; I find it occasionally useful;\ \nsee my Python demo for details; the C language has no equivalent."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("\nUtilities:\ \nPython has lots of built-in utilities that straight C doesn't have,\ \nas my Python demo will show.\ \nHousekeeping:\ \nWe will show some differences here.\ \nSecurity: Access, encryption, data hiding, type checking\ \nPython has various provisions for these things; C doesn't\ \nDesign:\ \nThis is sort of a nebulous concept, related to Syntax (below)\ \nThe primary difference I would classify as 'design'\ \nwould be C's strict data typing and Python's loose typing,\ \nso we'll definitely talk about this later.\ \nDevelopment: Building, packaging, deployment tools:\ \nNot too unique; we won't cover this.\ \nReflection:\ \nPython has some aids in determining data types;\ \nC doesn't so we'll ignore this, too. "); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Syntax:"); printf("\nNow here is by far, where the majority of differences lie.\ \nPython was built upon C, and was coded in C, so\ \nit's going to look a lot like C. There are many equivalencies,\ \nhowever, but if you can program in one language,\ \nyou can program in another.\ \nSo this is where we will spend most of our time."); } // not VERBOSE else { printf("\n"); } /* ************************************************************** */ // main body of code /* ************************************************************** */ printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Let's first take a look a tiny program.\ \nI'll print it here, then describe it, and execute what I can.\ \n(Obviously, we're in a program now, so I can't just start over.)\ \nHere's the listing:\ \n\n#include \ \nmain() {\ \n const int my_const_number = 9;\ \n int my_input;\ \n int my_tot;\ \n printf('Enter a digit: \\n');\ \n scanf('PERCENTd', my_input);\ \n my_tot = my_const_number + my_input;\ \n printf('The number you entered, plus 9, is PERCENTd');\ \n exit(1); \ \n}"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("\nNow, we'll execute the real code.\n"); printf("Enter a digit: \n"); scanf("%d", &my_test_input); //printf("%c", my_test_input); my_test_tot = my_const_test_number + my_test_input; printf("\nThe number you entered, plus 9, is %d", my_test_tot); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("\nWe'll look at a number of things here:\ \nEnvironmental differences:\ \nThe first line here, '#include', is a preprocessor directive.\ \nThe preprocessor (aka pre-compiler) is a program that executes some code\ \nbefore the actual C compiler begins.\ \nThe preprocessor turns it into C code, in fact.\ \nI'm not sure of the original necessity of the preprocessor,\ \nand Python has no equivalent.\ \n\nIn any case, the 'include' hauls in a 'header ('dot h') file\ \nwhich defines functions and constants and other preprocessor defs,\ \nincluding those provided by the C language subsystem itself,\ \nthough programmers usually have their own header files as well,\ \nas they make it easier to define, and hence use, common functions in\ \nmultiple programs."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("\n'stdio.h' is a C-language specification for a file\ \ncontaining language-provided input-output functions.\ \nThe angle brackets specify the compiler to look in the 'usual places'\ \nfor header files within that operating system,\ \nspecified by environmental variables.\ \nIf you want to specify a specific location for a header file\ \n(your programmer-provided file), you'd just use double quotes,\ \nfor example\ \n#include '/C:/myHeaders/myHeadFile.h'.\ \n\nThis is a direct path name; unlike Python, C has no concept of 'packages.'"); printf("\nNOTE: at this point: in my code listing displayed above\ \nI've used single quote marks. In real C code, they'd be double quotes\ \nbut if I printed them out here, the compiler would get confused.\ \nPython, on the other hands, accepts either single or double quotes\ \nas long as they're symmetric.\ \nOK."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("We next encounter some variables and constant definitions.\ \n'int my_input' allocates space for a variable named 'my_input'.\ \nIt is defined outside of the function 'main', or any other function;\ \nthis makes it globally available to all functions.\ \nPython works similarly in this regard.\ \nIt will be used as an integer, so it can be added to other ints,\ \nusing a plus sign. This is intuitive,\ \nand it is how many or most computer languages operate:\ \n\nThere are standard data types, such as int and char;\ \nthey are assigned specified amounts of space (a char, usually 8 bits\ \nand an int 32 bits), and they have certain behaviors.\ \nIf 'my_input' were defined as a char, for example,\ \nit would yield a strange result if you were to add it to another int."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Python, however, does not allocate space for variable in this way.\ \nIt does so automatically when you assign it a value, and\ \ndepending on the value, gives the variable an implied type.\ \nThis is called 'loose data typing',\ \nwhereas C has 'strong data typing'.\ \nIt's one of the major differences between the two languages.\ \nBoth have their advantages and drawbacks.\ \n\nHere also, we see a 'const' language-supplied keyword modifier\ \nbefore 'my_const_number'. This, of course, defines it as a constant,\ \nnot a variable. Constants must be assigned a value within this statement.\ \nIn this respect, a constant looks like a Python variable.\ \n\nThe remaining statements here are very similar to Python.\ \nIt should be noted, though, that C is very flexible about\ \nthe use of spaces.\ \nPython uses indentations as meaning, specifically to group statements\ \ntogether in a block. This can easily lead to bugs.\ \nC enforces that grouped statements be enclosed by braces."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Now that we've done a simple program,\ \nwe'll focus on some specific topics.\ \nFirst, a few words about C's design, vis a vis Python.\ \n\nPython's structure and syntax use C as a starting point.\ \nPython, in fact, is written in C, so it looks a lot like C.\ \nPython, is also more high-level than C.\ \n\nC is more detailed and requires more specifications\ \nfrom the programmer. This is what makes C more efficient;\ \nthe compiler or interpreter doesn't have as many decisions to make.\ \nOne of the most obvious examples of C's low-level syntax\ \nis the type specifications required for data. We've hit on this briefly,\ \nand will again later.\ \n\nSecondly, Python is much more concise than C; Guido van Rossum\ \n(the creator of Python) apparently thought\ \nyou didn't need as many tokens as there are in C.\ \nPython is easier to read and write, then.\ \nBut C has the advantage of visual specificity. For example,\ \nC enforces parentheses around blocks of code; Python relies on indentation,\ \nwhich is inherently error-prone."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Enough generalities. Let's get some syntax details\ \nout of the way so we can write some more C code.\ \n\nDelimiter: for End-of-statement: in C, it is the semicolon;\ \nPython has no end-of-statement delimiter.\ \nThis allows a line of code in C to include multiple statements,\ \nthough I think this is very cryptic,\ \nand I only see examples of this in textbooks\ \nwritten by algorithm designers, not C coders.\ \n\nDelimiter: for Conditional statement: in C, it's braces.\ \nAll C statements to be executed as a group (say, as a conditional)\ \nare included in left - right braces.\ \nIn Python it's a colon, followed by (on the next line)\ \nindentation, as mentioned above.\ \nC has few rules about whitespace of any kind, in fact.\ \nC is much more concerned with tokens (text) than spacing (decoration)."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Delimiter: for Line Continuation: in C, it's the backslash,\ \nsame as Python. It's used extensively in this very program.\ \nOther syntax anomalies: if there is no action to be done,\ \nsay, in a conditional loop, C just uses a semicolon to specify this;\ \nPython uses the 'pass' keyword instead. For example:\ \n\n if ( rc == 'OK )\ \n ;\ \n else\ \n do_error_processing();\ \n "); printf("\n\nNow, let's describe the C 'printf()' facility,\ \nfor printing to standard output (by default, the console.)\ \nWe use this extensively in this program, of course.\ \nHere's the syntax:\ \n printf('PERCENTd', myIntVar);"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("\nI've stated above that we need to 'include' the header file\ \n'stdio.h' for the compiler to get the code that declares\ \nthe C library print function.\ \nI won't go into the specifics of what the printf formats are,\ \nsuffice to say that they're included in double quotes\ \n(as are print literals) and contain a percent sign,\ \nfollowed by a c (for character), d (for decimal), etc.\ \nC has no data type 'string' as such, but printf will accept 's'\ \nas a parameter for an array of printable chars ending in integer 0.\ \nThe main difference between a Python print and a C printf\ \nis that in C, 'printf' is a function (discussed below) like any other;\ \nin Python it's like a built-in language command.\ \nI'm not sure how much difference that makes to most programmers."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Now, a few structural language differences:\ \nPython has a more abbreviated set of conditional statements,\ \nwhich we don't need to discuss here;\ \nIn C, we use the 'while', and 'for' facilities for iteration,\ \nand the 'if -- then -- else' syntax for conditionals, just like Python.\ \nThe C conditional looks like this:\ \n\n if ( myVar == 6 )\ \n do_this(myVar);\ \n else {\ \n rc = do_that( myVar );\ \n if ( rc == BAD )\ \n do_error_process();\ \n };"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Here we see that int the first 'if' condition\ \nthere are no parentheses. They're not needed,\ \nsince there's only one statement.\ \nSemicolons terminate every statement (unlike Python);\ \nand there is no 'then' keyword.\ \n\nA 'for' statement is more explicit than Python;\ \nit requires explicit initiation, end-condition-checking,\ \nand a short statement as to how to continue the loop.\ \n\nFor example:\ \n // this next variable is global\ \n int myVal = 7;\ \n int my_sample_func( myVal) {\ \n int i;\ \n for (i == 0; i < 9; i++ ) {\ \n do_this();\ \n }; \ \n do_that(); \ \n i = i+ myVal;\ \n return(i);\ \n } "); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Now, we'll explain:\ \nthe first line is a comment -- two backslashes.\ \nIt may be on its own line of code, or after a semicolon\ \n(after a statement).\ \nComments may span multiple lines by a beginning forward-slash star\ \nand an ending star forward-slash.\ \nNo line terminators (backslashes) are needed\ \nafter each line of the this multiple-line comment.\ \nNote: Attempting to print text with multiple lines\ \nconfuses the compiler,\ \nso I'll just use it in a 'real function' below.\ \nIn the 'for' loop, we see that the variable 'i',\ \njust allocated above, is initialized to 0.\ \nThis happens before the first loop begins.\ \nBefore the first and every subsequent loop begins,\ \nthe value of i is compared to 9.\ \nIf it is less than 9, the loop is executed.\ \nThis is called the 'condition' of the loop."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("At the end of each loop the third statement is executed;\ \nthat is, the increment operator (++) is applied to i,\ \nincreasing the value of i each time the loop is run.\ \nWe would expect the loop to run 9 times, then.\ \nOnly when the ninth loop has completed\ \nwill the 'do_that()' function be executed,\ \nsince it is not within a code block (delineated by braces.)\ \nNext, the value of i (8) is added to the passed-in-parameter (7)\ \nto produce a new value of 15, which is passed back to the caller.\ \n\nNote that in C, unlike Python, only one value can be returned,\ \nthough there's a work-around for this: a 'struct' data type\ \ndescribed below.\ \n\nNow, a few words about another conditional statement in C:\ \nthe switch statement with cases. This is nearly identical\ \nto the switch statement in Python. The syntax is this:"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf(" int c = 5;\ \n switch( c ) { \ \n case 1:\ \n printf('PERCENTd', 1 );\ \n break;\ \n case 2:\ \n printf('PERCENTd', 2 );\ \n break;\ \n case 3:\ \n printf('PERCENTd', 3 );\ \n break;\ \n case 4:\ \n printf('PERCENTd', 4 );\ \n break;\ \n default:\ \n printf('NEWLINEc= PERCENTd', c);\ \n };"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("OK, I cheated a little bit in the above listing.\ \nbecause the C compiler was gettting confused,\ \nso I substituted the text 'PERCENT' to stand for a percent sign,\ \nand 'NEWLINE' to stand for a newline, or backslash n.\ \nI've done this throughout this program so far;\ \nsorry I haven't mentioned it till now.\ \n\nOf course, this is a rather lame example.\ \nIn real life, the integer c would be a variable,\ \nset by, perhaps, a command line parameter.\ \nIn any event, 'c' must be an integer or character\ \nto keep things simple for the compiler;\ \nit can't be a pointer or an aggregate type (discussed below).\ \n\nThe switch evaluates c for each 'case' listed;\ \nif it meets the case condition, a statement is executed.\ \nIn fact it may be a series of statements, or more likely,\ \na call to a function."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("In any case, after execution of the statement(s)\ \nthe code 'breaks' out of the switch and goes on.\ \nIf the 'break' is not specified, the code will fall through\ \nto the next statement, and without testing the condition,\ \nwill execute it, which is rarely what you want,\ \nso that's why we have the 'break'.\ \nThe 'default' case is applied if 'c' doesn't meet\ \nany of the previous conditions.\ \n\nNow we'll run this code; it will print out '5'\n"); int c = 5; switch( c ) { case 1: printf("%d", 1 ); break; case 2: printf("%d", 2 ); break; case 4: printf("%d", 4 ); break; default: printf("\nc = %d", c); }; printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("\nSo much for conditionals. Now a little about functions.\ \nI've been remiss in not bringing up functions till now\ \nbut a simple C program requires only one function\ \ncalled 'main'.\ \nIn practice, nearly all C programs call multiple functions.\ \nIn fact, the 'printf' statement, ubiquitous in this program,\ \nis not really a 'statement' (as it is in Python 2.6 and below)\ \nbut a function included in the C Standard Library,\ \nwhich is part of all C installations.\ \n\nSo what is a function? Simple a bunch of C statements:\ \nvariable and constant allocations and initiations,\ \nconditional and iterative loops ('for', 'while', 'if-else', etc.),\ \ncomputations ('a = b + 5');, etc., etc.\ \n\nC, in fact, really has very few native facilities.\ \nAlmost everything in C is done by functions using these native facilities.\ \nFunctions may be easily converted into actual mini-programs, in fact."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("First thing about functions:\ \nin C, a function must be defined or declared before it's called\ \nfrom another function so the compiler can recognize what you're calling.\ \nIn traditional-style C, you declared functions\ \nat the top of the module, outside of any function, like this:\ \n\n int myFunc( int myFirstParm, char mySecondParm);\ \n\nThis told the compiler that the function was located\ \nwithin the listing (module) somewhere.\ \nThis allowed the program listing to be written in 'top-down' style,\ \nthat is, with the top-level function 'main' listed first,\ \nfollowed by all functions directly called by main,\ \nthen followed by all functions directly called by\ \nthe first function called by main, etc."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("More recent C styles put 'main' at the bottom of the listing,\ \nall functions directly called by main directly above it, etc.\ \nso that the most independent functions (calling no others)\ \nappear at the top.\ \nThis eliminates the need for 'declarations',\ \nsince each function's 'definition' (i.e., actual code) appears\ \nbefore it's invoked (called) by another function.\ \n\nOK. Now, we'll discuss function 'signatures',\ \nsomething that is highly simplified in Python,\ \nbut is, of course, more complicated in C.\ \nA function signature, or declaration, looks like this:\ \n\n int myFunc( int myIntArg, char myCharArg )"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("The first word, 'int', is the data type that will be returned.\ \nNote that in C only one value may be returned.\ \nThis is unlike Python, in which multiple values of disparate types\ \nmay be returned from a function.\ \nIf you want to do the equivalent in C, you have to put the values\ \ninto an aggregate structure (a programmer-defined C 'struct',\ \ndiscussed below.\ \n\nThe arguments or parameters to the function (inside the parentheses)\ \nmust be of the data type specified. The function need not return them,\ \nthough it often will.\ \nAs mentioned above, functions in C are either programmer-supplied,\ \nlinked in through a third-party library,\ \nor are included in the C Standard Library."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Functions often use 'modifiers'\ \nappearing to the left of the return type in its signature.\ \nModifiers, described later, are more often associated with data,\ \nnot functions, but there is at least one that only refers to a function;\ \nit is 'inline', appearing like this:\ \n\n inline int myFunc( int my1, int my1 )\ \n\nThis directs the compiler to convert the function to straight code\ \nwherever it's invoked. So in the compiled module, the function\ \nis not really 'called'; the code is merely repeated wherever the call is.\ \nThis is useful for short functions that are called very frequently;\ \nit may speed up execution time considerably.\ \n\nAnother modifier used in a function declaration, NOT in a definition,\ \nis 'extern'.\ \nThis tells the compiler that the function is located in an external module,\ \nwhich will be compiled.\ \nMany, if not most, C programs, will have a few externs\ \nat the top of the listing."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("OK. So far, I've presented a bare-bones C program\ \nand have given examples of some important concepts in C:\ \n'main', variables, functions, conditional and iterative statements,\ \nthe preprocessor, user input, the print function, comments, coding blocks,\ \nand code design.\ \nNow, I'll go into a little more depth about some language features,\ \nand then into some new topics, and finally some more real code.\ \n\nOK. I'll start with aggregate data types.\ \n\nAggregates are combinations of the native data types\ \nlike char, bool, int, float, double, short int, and long.\ \nThis is very different from Python, which has built-in aggregates,\ \neach with their own possible operations; types like list, tuple, dict, etc.\ \n\nOne type of C aggregate type is a 'struct'. It is programmer-created.\ \nIt looks like this:"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf(" struct myStructtype {\ \n int myInt;\ \n char myChar;\ \n }; "); printf("\n\nThis isn't a very colorful description, but you see my point.\ \n\nNow you can allocate space for a variable\ \nwhich has the size of the 'myStructtype' data type, like this:\ \n\n struct myStructtype myVar;\ \n\nA shortened form,\ \nwhere only one variable will be assigned to that type, is as follows:\ \n\n struct myStructtype {\ \n int myInt;\ \n char myChar;\ \n } myVar;"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Structs are similar in concept to COBOL records,\ \nor table rows in a database. A typical record structure might be:\ \n struct empRecordType {\ \n int emp_id;\ \n char emp_type;\ \n char[20] emp_name;\ \n char dept_no;\ \n }; myEmpRecord"); printf("\nTo initialize this data type,\ \neach field must be initialized separately, like this:\ \n\n emp_id = 44; emp_type = 'M'; dept_no = 99;"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("We'll program this code now and print it out:\n"); int emp_id = 44; char emp_type = 'M'; char dept_no = 99; printf("%d,%c,%c", emp_id, emp_type, dept_no); printf("\n\nThe printf statement looks somewhat like this:\ \nprintf('PERCENTd, PERCENTc, PERCENTc', emp_id, emp_type, emp_dept);"); printf("\nA second kind of aggregate type is an array.\ \nIn C, an array is a fixed-length, logically contiguous chunk of memory\ \nwhich comprises a bunch of elements all of the same data type.\ \nAn array of integers, for example, looks like this:\ \n\n int myIntArray[10] \ \n\nThis allocates a block of memory to hold ten integers.\ \n\nArrays can be allocated upon assignment using the following syntax:\ \n int myIntArray = { 1, 2, 66, 99, 77, 478, 0, 9, 0, 0 };"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Character arrays can be assigned similarly:\ \n char myCharArray = { '3', '4', '7' };\ \n\nNo length need be specified with this syntax\ \nsince the length is known to the compiler by the number of elements.\ \n\nA string is another aggregate data type.\ \nIt's just an initialized array of chars, really.\ \nStrings are always initialized along with their assignment, like this:\ \n\n char myString[] = DOUBLEQUOTEthis is my string,DOUBLEQUOTE;\ \n(Obviously a double-quote sign should be substituted for DOUBLEQUOTE.)\ \n\nA string can be copied, but not changed.\ \n\nThere is no built-in way to copy a string;\ \na library function such as 'strncpy()' must be used.\ \nThis is because a string is not a native type; it is derived from 'char'.\ \n\nWhat's interesting about arrays and strings is that they can be indexed,\ \nlike this:\ \nchar myChar = myString[3];"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("This places 4th character of myString (index begins at 0) into 'myChar'.\ \nIndexing is used a lot in navigating arrays, especially numeric arrays;\ \nnot so much in strings, in which individual chars are rarely relevant.\ \n\nNow onto the related, dreaded feature of C known as pointers.\ \nPointers are kind of tricky, and Python has eliminated them,\ \nletting the Python interpreter perform the equivalent.\ \nPointers are ubiquitous in C. You can't avoid them.\ \n\nA pointer is a type of variable whose data is a memory address.\ \nIts size is the same size as a long int, machine-dependent,\ \nbut often 32 bits, since that is usually the size of a memory address.\ \nPointers are a fundamental type in C, just like ints and chars.\ \nThey are most often used to hold addresses of more complex,\ \nderived (non-native) types, like structs, arrays, and strings.\ \n\nThe syntax of a pointer is like this: \ \n struct myStruct; \ \n struct myStruct STARpmys = &myStruct; \ \n\nSTAR indicates a pointer; verbiage left of it is the type pointed to.\ \nA pointer could also be of type 'char STARmyptr', for example."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("A pointer is not the object itself.\ \nIt is not another name for the object 'myStruct'.\ \nIt is the memory location of that object.\ \nIt's often used as a parameter to a function.\ \nHere, I'll have to digress for a moment.\ \nThough we haven't covered this yet, when you pass a parameter to a function\ \nin the form of a previously-allocated variable, you are not passing\ \nthe variable itself, but a copy of its value.\ \nThis means that if the function alters the parameter it won't alter\ \nthe variable which was previously allocated."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("\n\n int myFunOne( int anInt ); \ \n int myInt = 5; \ \n int rc; \ \n \ \n int myFunOne( int myInt ) { \ \n myInt = 4; \ \n return myInt; \ \n }; \ \n\n printf('MyInt before calling myFun: PERCENTd', myInt); \ \n rc = myFun( myInt ); \ \n printf('MyInt after calling myFun: PERCENTd', myInt); "); printf("I've coded two functions at the bottom of this listing.\ \n\nWe'll execute the code by calling them using function parameters."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); int rc; int myTestInt = 5; printf("\nMyTestInt before calling myFun: %d\n", myTestInt); rc = myFunOne( myTestInt ); printf("\ncopy of myTestInt returned by myFun: %d\n", rc); printf("\nMyInt after calling myFun: %d\n", myTestInt); printf("Here's an example:\ \n\n struct myStructType { \ \n int myInt;\ \n char myChar;\ \n };\ \n int myFun2( struct myStructType *ms );\ \n myStructType mys;\ \n myStructType STARmyp =&mys;\ \n myFun2( myp ); "); printf("Now, let's execute the code\n"); struct myStructType mys; struct myStructType *myp = &mys; myFun2( myp ); printf("\nOK, but this requires a few explanatory details.\n"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("One is that since the function appears at the bottom of the listing,\ \nit must be declared at the top, before main().\ \nBut since a parameter to the function is a pointer to type myStructType,\ \nthen 'myStructType' must be defined first.\ \n\nSecondly, we see here that we initialize the pointer myp\ \nwith AMPERSANDmsys. AMPERSAND, in C, means 'the address of'.\ \nOtherwise the pointer would be loaded\ \nwith the VALUE of myStructType, which wouldn't be meaningful,\ \nsince elements of the structure can only be accessed individually.\ \n\nPointers to all data types are generally loaded this way;\ \nfor example:\ \n int mI = 6;\ \n int *pMyI = &myI;\ \n int newInt = *pMyI;"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("The syntax is:\ \n int newInt = *pMyI;\ \n printf('De-ref value is PERCENTd', newInt) "); printf("\n\nSo the pointer data type itself is int STAR varname\ \nand the data contained within it is STAR varname.\ \nWe will demo this code:\n"); int myI = 6; int *pMyI = &myI; int newInt = *pMyI; printf("\nDe-ref value is %d\n", newInt); printf("\nA seeming exception to the rule of initializing a pointer\ \nwith AMPERSANDvarname is the casy of an array.\ \nAn array is not a data type itself; it's a label,\ \nlike a variable name or function name.\ \nIts name, then is an alias for its address.\ \nSo a pointer initialized to an array would look like:\ \n\n int *myArrayPt = myIntArrayName"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("where 'myIntArrayName' is a pre-existing array of integers.\ \n\nOK, more about pointers:\ \n\nA structure, we may recall, is a user-defined data type.\ \nIt's often used as a data record, or one in a list of records.\ \nThis record is often created dynamically (see 'malloc' below)\ \nthat is, at run time, as needed.\ \nIt is then usually linked to another dynamically-allocated record\ \nof the same structure, in an aggregate known as a 'linked list'.\ \nEach record, then, must contain a field to the next record.\ \nThis will be a pointer to the same structure type as the record itself."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("This is called a self-referential structure.\ \nIt's used like this:\ \n struct myStructType {\ \n int myI;\ \n char myC;\ \n struct myStructType *next;\ \n };\ \n\n struct myStructType my1;\ \n struct myStructType *pMy1 = &my1;\ \n struct myStructType my2;\ \n struct myStructType *pMy2 = &my2;\ \n struct myStructType my3;\ \n struct myStructType *pMy3 = &my3;\ \n\n pMy1->next = &my2;\ \n pMy2->next = &my3;\ \n pMy3->next = 0;"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Here we find the right-arrow syntax.\ \nA right-arrow means that the variable name is to be used as a pointer\ \nso we'll put an address into this field.\ \nNow, we'll execute this code."); struct myStructType { int myI; char myC; struct myStructType *next; }; struct myStructType my1; struct myStructType *pMy1 = &my1; struct myStructType my2; struct myStructType *pMy2 = &my2; struct myStructType my3; struct myStructType *pMy3 = &my3; pMy1->next = &my2; pMy2->next = &my3; pMy3->next = 0; printf("Well, it didn't blow up, so I guess it worked!!!\ \n\nWe can demonstrate this in more detail later.\ \n\nYou can also have a pointer to a function.\ \nThis is useful when you don't know which function, out of many,\ \nthat you want to execute, until run time.\ \nIn this case, all candidate functions must have the same signature,\ \nthat is, the same parameter types and return code type.\ \n\nHere's an example. We'll need your input on this."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("\n ENTER 1 to call myFunOne, 2 for myFun2:\n"); scanf("%d", &funNum); printf("\n"); int (*myFunPtr)(int) = 0; int myArg; if (funNum == 1) { myFunPtr = myFunOne; myArg = 1; } else if (funNum == 2) { myFunPtr = myAltFun; myArg = 2; } else { myFunPtr = Flunk; myArg = funNum; } myFunPtr( myArg ); printf("\n\nHere's the code. You might want to write this down,\ \nespecially the first line, before we get to the next page."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf(" int (*myFunPtr)(int) = 0;\ \n int myArg;\ \n if (funNum == 1) {\ \n myFunPtr = myFunOne;\ \n myArg = 1;\ \n } \ \n else if (funNum == 2) {\ \n myFunPtr = myAltFun;\ \n myArg = 2;\ \n } \ \n else {\ \n myFunPtr = Flunk;\ \n myArg = funNum;\ \n } \ \n myFunPtr( myArg ); "); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("The first statement sets the function pointer.\ \nThe leftmost verbiage 'int' is the function return type\ \nand the next two phrases are each enclosed in parentheses.\ \nThis looks cryptic, but it tells the compiler that it's a function pointer\ \nthat's being declared (or rather, assigned).\ \nThe parameter to the function is the final 'int', in parentheses,\ \nthe syntax that makes this a function pointer is\ \nthe STAR preceding its name, with the STAR-name enclosed in parens.\ \n\nSo depending on what the user entered, the function pointer is set\ \nto the name of the applicable function.\ \nJust the name will suffice because the C compiler interprets a function name\ \nas a pointer, or a label, actually -- something the compiler sees\ \nas an address."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Oh, almost forgot -- the acceptable syntax is to first set\ \nthe function pointer to NULL or 0. The assignment of a value\ \nmakes this statement na definition (i.e., a memory allocation),\ \nnot just a declaration of some variable that already exists.\ \nWe set it to NULL, then change the value of it later.\ \nWe'd better change it later, because if we didn't, the program would crash!\ \nGoing to location 0 is not allowed!"); printf("\nOK, so much for that.The function is invoked by its pointer.\ \n\nOne more point, so to speak, about pointers.\ \nPointers can point to other pointers. The syntax is this:\ \n char **myPtr;\ \nThis is a pointer to an already existing character pointer.\ \nIf it points to an array, and it usually does,\ \nthe format for creating the array is this:\ \n char *myArray[];\ \nTypical examples of the C command line argument (discussed below)\ \nuse either syntax."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("To visualize an array of pointers, think of an array of strings.\ \nEach pointer in this array contains the memory address of a string.\ \nSo elements of the array\ \n char *colors[] = {'red','blue', 'green'}\ \ncan be accessed (de-referenced) as strings, as in the statement:\ \n printf('PERCENTs', colors[1]);\ \nWe'll execute this statement to print 'blue'"); char *colors[] = {"red", "blue", "green"}; printf("\n%s\n", colors[1]); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("\nNow I'll digress a bit to catch up on a couple of data types.\ \nThe first is type 'enum'. It's an int, really,\ \nand is assigned to one of multiple possible values,\ \nusually represented by symbols with different integer values.\ \nHere's an example:\ \n enum CARDS { HEARTS, DIAMONDS, SPADES, CLUBS };\ \nBy default, their integer values are 0, 1, 2, 3, respectively,\ \nso they can easily be used in case statements, as labels for numbers.\ \nenums can be assigned specific values, too, to make sense in the context.\ \n enum ZIPS {BEVERLY = 90201, TIBURON = 94125, SF = 94111};\ \n\nAnother data type: w_char, meaning wide character, to accommodate\ \ninternational alphabets. You see this a lot in MS system software.\ \nA w_char is either 16 or 32 bits, depending on the system."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("One last type: null. That's right, 'null' is a type.\ \nIt's usually used as a pointer type to signify a place holder.\ \nSome C library functions, like memcpy, use it.\ \n\nMoving right along...I'll discuss a few data 'modifiers',\ \ngenerally appearing on the left-most side of a variable definition\ \nbefore its type specification. Like this: volatile int myVar.\ \nAs statements are like verbs, and variables are like nouns,\ \nmodifiers are like adjectives that describe variables.\ \nTwo of them -- 'volatile' and 'register' -- describe how the compiler\ \nshould treat the variables. 'Volatile' tells the compiler\ \nthat the variable is subject to change frequently by multiple programs.\ \nIt has 'global' scope, then (discussed below).\ \nThis affects compiler 'optimization', in which a compiler\ \nmay sometimes arrange statements in a different order to increase speed.\ \noptimization may be turned off by a compiler command-line directive,\ \nbut if it is on, a volatile modifier may be crucial in some cases,\ \nspecifically in coding for device drivers, where some variables\ \nmay be modifiable by multiple programs or by device hardware.\ \nIn normal business applications, 'volatile' isn't used."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("A second compiler-directive modifier is 'register'.\ \nThis directs the compiler to put the variable in a CPU register,\ \nnot in actual memory. This provides much quicker access\ \nfor frequently used variables. It does not guarantee register placement,\ \nbut it instructs the compiler of the programmer's preference.\ \n\nThere are four modifiers which affect the scope of the variable.\ \nHere, I'll discuss the concept of 'scope' in greater detail."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Scope refers to which sections of code can view or modify\ \na variable nor function. Local 'scope' means that a variable is known\ \nwithin its smallest enclosure. For example, in a for-loop,\ \nthe expression 'for( int i = 0; i < myLimit; i++ ) { dothis( i ); }',\ \nthe variable 'i' is defined and allocated on site,\ \nbut it can only be accessed within the for-loop itself;\ \nas soon as the loop has completed, no one knows about 'i'.\ \nSimilarly, within a function, if a variable is created, it's only known\ \nto that function. This is called an 'automatic' or 'local' variable.\ \nMost variables in a program are local. They may be passed to other functions\ \nas parameters, in which case, yes, the called program will know about them,\ \nbut only as a value, or copy or as a memory address (described above)\ \nwhose contents may be modified.\ \n\nA third type of scope is called 'global'. Global variables are placed\ \noutside of a function listing, usually at the top of the program,\ \nbefore 'main' or any other function. If a global variable is placed\ \nin the middle of the program somewhere (between functions),\ \nit's only known to the functions following it.\ \nGlobals are usually placed at the top, then.\ \nGlobals, like locals, need no keyword modifier."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("So which variable scopes need modifiers? 'static' and 'extern' variables,\ \nthat's who (which.)\ \n\nAn 'extern' variable has scope outside of the code listing (module) itself,\ \nthat is, any source module that's linked into the executable knows about it.\ \nSuch a variable is defined globally in one module, but is declared\ \nas an 'extern' in a modules that use it.\ \nSo 'extern int myWellKnownFunc( char Carg )' directs the compiler\ \nthat such a function exists in another part of the executable."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Now, a 'static' appears within a function, looking like this:\ \n\n int myFunc(char myCA) {\ \n static int mySI = 5;\ \n do_something( mySI );\ \n mySI = mySI + 2;\ \n } \ \n\nA static means that the variable is defined, allocated, and initialized\ \nonly once for the life of the program. This means that mySI starts out as 5,\ \nand, in this example, is increased by 2 each time myFunc is called.\ \n\nIt may seem strange how the compiler can allocate statics.\ \nI'll digress a bit to discuss variable storage.\ \nAll local variables are stored in the program's individual 'stack',\ \na last-in-first-out construct that pushes and pops values.\ \nThis is appropriate for use in function calls having local variables.\ \nAParms to a function are pushed onto the stack; when the function completes,\ \nthe parameters are popped, or discarded."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Global variables and functions are kept in the program's own 'heap',\ \na relatively unstructured space with relative address entry points\ \nfor each of its items. Heap elements are knowable to any part of the code,\ \nand last for the life of the running program or until\ \nprogrammatically deleted.\ \n\nStatics are sort of global, sort of local; they're an anomaly.\ \nThey're stored on the heap.\ \n\nWe've been talking about data definitions for a while.\ \nGet ready for another digression -- the difference between\ \ndata definition and data declaration.\ \nI've talked about this previously, but I want to clear up\ \none or two subtleties.\ \nTo 'define' a variable means to allocate space for it.\ \nTo 'initialize' it means to assign it a starting value.\ \nOften, the two are done in one statement, such as:\ \n int myInt = 5;\ \nTo 'declare' a variable means to tell the compiler\ \nthat it's defined somewhere else, but here is what it looks like."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("For example:\ \n\n extern int myInt;\ \n\nThis tells the compiler that the variable should be treated as an int.\ \nThe keyword 'extern' clearly tells us the variable is a declaration,\ \nnot an uninitialized variable definition.\ \nA function declaration, described above, looks sorta like an empty function.\ \n char *myFun( int argInt, char *argChar );\ \nThe only difference is that it's missing the braces.\ \n\nA user-defined C 'struct' has a slightly more subtle syntax:\ \nHere, unlike a data type known to the C compiler, like an int or char,\ \nthe layout is specifically described in a declaration, like this:\ \n\n struct myStructType {\ \n int myint;\ \n char mychar;\ \n struct myStructType *next;\ \n }; \ \n\nThis is a declaration, not a definition."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("The following is a definition:\ \n\n struct myStructType{\ \n int myint;\ \n struct myStructType *next;\ \n } myStruct;\ \n\n'myStruct' is a variable of type 'myStructType'.\ \n\nUser-defined struct type declarations are messy, so C has a facility\ \nto simplify their syntax, as well as the syntax of any variable type,\ \nIt's the 'typedef' facility. It's used like this:\ \n\n typedef struct myStructTypeSTAR pMS;\ \nSo whenever the type 'pMS' is found, it will refer to a pointer of this type.\ \ntypedef is used a lot in C, often to clarify that multiple types\ \ncan be treated the same way.\ \nSo 'typedef char w_char' would treat the type 'w_char' as a char\ \n(though I don't know why you'd want to truncate the data).\ \nThere are many system-defined types that use the typedef construct."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Just one more thing about types: there are situations\ \nwhere a variable is defined as one type,\ \nbut should be temporarily treated as another.\ \nAn aforementioned example is a pointer declared as a pointer to 'void'\ \nas a sort of placeholder type. 'void' should be changed to a specific type\ \nwhere it is used.\ \nThis is called 'casting'.\ \n\nThe C library function 'memcpy' requires casting,.\ \nHere's the syntax for type conversion:\ \n\n char *myBuf;\ \n myBuf = (char *)malloc(1024);\ \n\nNow, 'myBuf', which is a pointer to a char, or bunch of chars,\ \ncan be accessed as such by operators such as a plus sign.\ \nIf we initialize 'myBuf' to be the string 'abcdefghij',\ \nwe can increment its pointer to access its 5th element, 'e'.\ \nThis is the additional code:\ \n\n char elementE = *myBuf[4];\ \n printf('PERCENTc', elementE);"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Note that myBuf is like an unnamed array of chars; 4 is the index\ \nto the fifth element, since indexes start at 0;\ \nand STAR gets the data (the character 'e') from the location pointed to.\ \n\nWe'll demonstrate the real code later when we talk about\ \nthe Standard Library functions malloc and strcpy.\ \n\nI do have one more thing on this topic, though:\ \nC++ has replaced C in many applications. We won't discuss C++ here,\ \nbut suffice to say that it has altered the 'casting' procedure\ \nquite a bit.\ \n\nNow I want to cover a couple of operators we didn't discuss before.\ \nAs stated, an operator is like a shortcut for a function, really.\ \nThe 'plus' operator would be like a tiny function\ \nthat adds two integers together.\ \nC and Python have very similar operators. Many of these are not arithmetic\ \nin nature, such as parentheses, which enclose function code\ \nor, in Python, a colon which signifies the beginning of a function.\ \nThese operators are a type of 'token' (discussed below)\ \nthat perform a function."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("C has an operator not available in Python, the 'increment',\ \nand its complement, the 'decrement.'\ \nThe syntax, in context, is like this:\ \n myNewVal = myNewVal++; \ \n\nThis assigns a new value to the variable by incrementing its\ \nprevious value.\ \nThe increment operator acts in accordance to its operand's type,\ \nso incrementing a pointer type will increment the pointer,\ \nNOT the value of the data pointed to.\ \nSo 'myPtr++' will bring us to the next element in an array.\ \nIt had better refer to an array, or we'll be pointing to who-knows-what!\ \n\nOperators can be classified in various ways.\ \nOne of them is 'unary' and 'binary'.\ \nMost operators are binary, that is, they require two operands,\ \nusually one preceding and one following the operator (3 + 5).\ \nSome operators are unary, such as the aforementioned increment operator.\ \nIn a complex statement, the precedence of operators may be ambiguous.\ \nGenerally, you can use parentheses to resolve ambiguities,\ \n\nlike this:"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf(" (*myPtr)++ \ \n\nThis clearly signifies that it's the data that should be incremented,\ \nnot the pointer.\ \n *(ptr++) \ \non the other hand, would update the pointer, not the data.\ \nBut most of the time, you don't want to confuse a statement\ \nwith too many parentheses.\ \nSo C has a default order of precedence,\ \nmost of it conforming to well-known arithmetic.\ \nIn the expression '5 + 3 * 9', for example, the multiplication\ \nis performed first, then the addition.\ \n\nC's order of precedence can get a little non-intuitive, however,\ \nfor unary operators. The rule is that some unary operators\ \nare evaluated right to left, not left to rigbt, as we might think.\ \nA common example of this is in the above example of increments and pointers.\ \nWithout parenthesis, then, the expression 'STARptr++' \ \nevaluates to 'get the value of the address ptr,\ \nthen go to the next location; DO NOT increment the data value itself'"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("And since we're talking about expressions with plus signs, stars,\ \nand other non-characters, I'll bring up the concept of 'tokens'.\ \nA token can belong to one of several categories \ \nwhich I've unofficially put together:\ \n\n identifier\ \n keyword\ \n constant\ \n literal\ \n operator\ \n separator\ \n variable\ \n character set\ \n special character\ \n\nThe above token categories should include everything you'll see\ \nin a C program, and I think it's easier to study something, \ \nlike a language, if its various components can be categorized.\ \n\nSo -- an identifier would be a variable name or\ \na pre-processor-defined symbol."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("An identifier is sort of a symbol, often translated into an address\ \nby the compiler. A function name would be an identifier.\ \n\nA keyword would be part of the language itself, and not otherwise usable\ \nby the programmer. Examples are types, like 'char' and 'int'\ \nactions like 'switch' and 'for', etc.\ \nAll keywords are in K & R, Second Edition, page 192.\ \nIf you don't know what I'm talking about,\ \nGoogle 'K & R'.\ \n\nA constant is some sort of value, usually defined by the programmer,\ \nthat can't be changed. Strings are constants, for example.\ \nMost other kinds of constants are hard to differentiate from\ \none of the other categories.\ \nA literal is like 'a', '4', etc.\ \nAn operator is like a plus sign. Matching parentheses\ \nfollowing a function name is usually considered an operator, too\ \nthough I think it might also be called a separator.\ \nA separator could be a blank space, a semicolon, some sort of demarcation."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("A variable has already been described.\ \n\nA character set refers to any one-byte token in the ASCII set\ \nof 128 chars (in its simplest form), including alpha and numeric chars,\ \nhyphens, etc. -- anything printable.\ \nA special character would be as subset of the ASCII character set -- \ \nas would most separators, for that matter -- a star, ampersand, or the like.\ \n\nSo much for all that.\ \nUnder this discussion of 'tokens' I'll mention 'escape characters.'\ \nThey would each be an ASCII character preceded by a backslash\ \nhaving special meaning to a compiler.\ \nThe most commonly-used escape character is the newline,\ \nwhich is BACKSLASHn. Similarly, a tab would be a BACKSLASHt.\ \n\nA backslash can be used to denote numbers of a system other than base 10.\ \nIt's very common in C code to deal with hex numbers.\ \nTo print them, you'd send the compiler a sequence like 'BACKSLASHx12',\ \nmeaning that 'x' is not a literal, but a directive that\ \nthe integer following it (12) is a hex char.\ \nOtherwise, in fact, it wouldn't be a single char, would it? \ \nSo with the 'BACKSLASHx' the compiler will know to print it as '000C'.\ \n\nI'm not going to go into the hex numbering system here, though."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("But I will direct the reader to K&R p38 for a list\ \nof all the escape sequences, just for the sake of comprehensiveness.\ \n\nNow a little more about operators.\ \n\nOK, I won't make you look up those escapes.\ \nHere they are, just the single chars, assuming the backslash precedes them.\ \n'a' -- alert, sounds a beep. Unique 'cause it goes to the speaker,\ \nnot the printer. The operating system handles this.\ \n'b' -- backspace -- not used too much any more.\ \n'f' -- formfeed, and 'r' -- carriage return, and 'v' -- vertical tab.\ \nDitto; rarely used. 'n' -- ubiquitous, already discussed.\ \n't' -- horizontal tab -- used quite a bit.\ \n\nAs with most of what we've been talking about since we left 'pointers',\ \noperators are very similar to what you see in Python.\ \nTheir order of precedence has already been mentioned (K&R p53);\ \this is also a comprehensive list of all C's operators,\ \nat least two of which -- the increment and decrement -- \ \nare not available in Python."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("I've been hitting around a lot of things lately in this tutorial\ \nand I haven't been executing much code. There are just a lot of things\ \nthat aren't too easy to explain in a logical presentation;\ \nwe are constantly circling arouund. Be that as it may,\ \non the subject of syntax and tokens, I'll present a couple of more\ \nprobably non-intuitive constructs regarding conditional loops.\ \nThe first is in a 'for-loop'. It normally has three statements\ \nwithin the parenthesized 'for'. Interestingly, any of those statements\ \ncan be omitted by just keeping their delimiters, the semicolons.\ \nIn fact, technically, you don't need any conditions.\ \nYou can just say:\ \n\n for( ; ; ) "); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("A 'while' loop can be made unconditional (a 'forever' loop)\ \nby the syntax: \ \n\n while( 1 ) \ \nThis is very common syntax in C.\ \nIt looks weird, but K&R's reasoning is this:\ \nThe 'while' evaluates a condition enclosed inside parentheses.\ \nIf the condition evaluates to 'true', we do the loop.\ \nAnd -- get this -- 'true' is a Boolean type -- \ \n(No, I haven't mentioned this before.) And 'true' evaluates to 1.\ \nSo (1) is always true. The condition is met.\ \n\nJust one more topic relating to operators\ \nbefore we discuss the Standard Library, the outside environment,\ \nand C programming style.\ \n\nThat topic is 'bitwise operators', commonly used in C,\ \nnot so much in C++ or Python. That's because bit operators\ \nare intensively space-saving constructs used in very small machines\ \n(device driver programming.) They are cryptic, and where space permits\ \nhigher-level data operators and data types should be used.\ \nBut device manufacturers don't give C programmers that choice."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Bitwise operators operate on int types only, specifically,\ \ncertain specified bits within those ints.\ \nIn bitwise logic, an int is not usually treated as a 'number'\ \nbut as a series of bits, each having a value of 0 or 1.\ \nIn bitwise arithmetic, the 32-bit int 00000000000000000000000000000100 \ \ncan represent the integer 4, as it would in binary or hex logic.\ \nBut it can also represent the value of 'on' or 1, for bit 2 \ \n(bit 0 being the rightmost bit.)\ \nDevices often work by setting (to 1), unsetting (to 0),\ \nclearing (like unsetting), or toggling (changing 0 to 1, or 1 to 0).\ \nBitwise operators are used for these purposes, and very often to test bits.\ \n\nBitwise operators(listed in K&R p 48) are:\ \n & (bitwise AND)\ \n | (bitwise inclusive OR)\ \n ^ (bitwise exclusive OR)\ \n << (left shift)\ \n >> (right shift) \ \n ~ (one's complement, unary) "); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Often a device wants the user to select different modes of operation\ \nor the driver writer to select which capabilities to include with others\ \nA telephone answering machine, for example, may want to reading of digits\ \nat some times, and not at others, and may want to enable speech recording\ \nor playback at the same time.\ \nthe device may including a 32-bit 'register' (the usual nomenclature), \ \nreadable and writable by both the device driver program (that's us)\ \nand the device itself.\ \nIf, hypothetically, the device reads a 1 in bit 0, it will know\ \nto set dialtone to 'ON'. If it reads a 1 in bit 1, it will know\ \nto send a ring signal. Typically, before it takes action, though,\ \na device driver will test the status of the device,\ \nor see what bits have already been set.\ \nTypically, an AND operator, a 'shift', and a 'bit mask' is used \ \nto set or test device register bits. \ \nA bit mask is an integer with certain bits set to be AND'd or OR'd\ \nwith the register bits.\ \nA 'left shift' or 'right shift' operation is also commonly used\ \nto isolate bits."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("You see, in C, bits cannot be added or subtracted individually\ \nby the arithmetic operators plus and minus.\ \nThe entire integer must be operated on.\ \nSo bitwise operations are required to manipulate the individual bits first.\ \nThis sounds tricky, and it is.\ \n\nWe'll start with 'shift' operators. A left-shift of an integer\ \nmoves all of its bits one position to the left, so its left-most bit\ \nfalls of the face of the earth, and the newly-acquired space on the right\ \nis filled with a zero, like this:\ \nThe integer with the hex value of 14, for example, will look like this,\ \nin bit form:\ \n\n 00000000000000000000000000001110 \ \n\nor, in hex notation, 0x0E.\ \nShifting this integer two positions to the left has this format:\ \n\n 0x0E << 2 \ \n\nand the result would look like this: \ \n\n 00000000000000000000000000111000 \ \n\nor in hex notation 0x38 \ \n\nWe'll run the code now, and print the result:"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); int hexint = 0x0E << 2; printf("\nResult in hex: %x; in decimal: %d\n", hexint, hexint); printf("Yup, it's %x in hex format, %d in decimal format\n", hexint, hexint); printf("\nNow, let's look at a few other commonly-used bit manipulations. \ \nHere's a bit-wise addition statement: \ \n 0x00001001 & 0x00000011 \ \nNote that it appears as if truncating the first 24 bits; since they're 0,\ \nthe hex format (starting with 0x) doesn't use them. \ \nAt any rate, in decimal notation, this is 9 AND 3. \ \nIt should equal 12 dec, or C in hex, we think. \ \nLet's do the computation now:"); hexint = 0x00001001 & 0x00000011; printf ("\n\nResult: %x in hex, %d in decimal\n", hexint); printf("\n\nWhat, you say? The answer is 1??? \ \nWell, that's because a bitwise addition is NOT arithmetic addition, \ \nit's a comparison operation. \ \nEach bit is added to its corresponding bit above it. \ \nIf both bits are 1, the result is 1; otherwise, the result is 0. \ \nSo, for bits 0 (the right-most) the answer is 1. \ \nFor the bits 1, whose corresponding values are 0 AND 1, the result is 0, \ \nas it is for every other bit. So the net result is 1. \ \n\nLet's do another example, 0x0b AND 0x09. The result should be 3.\n"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); hexint = 0x000b & 0x0003; printf("\nResult of dec 11 and dec 3 is hex: %x\n", hexint); printf("\n\nIn the first example, I used the notation 0x00001001, \ \nand in the second, 0x09. The compiler will recognize either. \ \nAnd in each case the result will be 9 (0x1001) since \ \nthe bits 0 equal 1, and the digits 3 equal one, and none others. \ \n\nSo how is this useful? We'll examine this later, after we describe \ \nthe mechanics of all the other bit operators.\ \nWe've looked at left-shift (right-shift isn't used too often) \ \nand bitwise AND. \ \nNow, for the tilde, OR and EXCLUSIVE-OR operators. \ \n\nThe unary operator tilde (~) just reverses all the bits. \ \nThe integer 0x1001 (9), for example, becomes 0x0110 (6). \ \nWe'll see how this is used later."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Next, there is the OR operator, a straight line ( | ). \ \nThis compares a digit in a mask with a corresponding digit \ \nin the integer register to be tested, like the aforementioned AND operator. \ \nUnlike the AND, the result of an OR will be 1 if the corresponding bit \ \n(say, 0) is 1 in either the mask or the register. \ \nFor example: \ \n\n 0x0001 | 0x0100 \ \n\nwhere the first operand is the mask and the second, the register \ \n(though it really makes no difference to the result) \ \nwill result in 0x0101 (or 5), since in the mask, bit 0 is set, \ \nand in the register, bit 2 is set. \ \nLet's try it: "); hexint = 0x0001 | 0x0100; printf("\n\nOR result in hex is: %x; in decimal is: %d\n", hexint, hexint); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Now, the EXCLUSIVE OR operand (caret, or '^') works similarly \ \nexcept that 1 is only set if either bit is 1, but not both. \ \nSo, for: \ \n\n 0x0011 ^ 0x0110 \ \n\nwe would expect the result to be 0x0101. Let's try it:\n"); hexint = 0x0011 ^ 0x0110; printf("\nEXCLUSIVE OR of 3 and 6 = hex: %x\n", hexint); printf("Yup, it's 0x0110. \ \n\nLastly, there's the TILDE (~) operator, aka One's Complement Operator. \ \nAll a TILDE does is flip bits. Theoretically. Actually, it's not that simple. \ \n\nUnlike other operators here, TILDE is unary, not using a second operand. \ \nLet's try it by printing the results of statement 'int hexint = ~0x01011111.\ \nIt should produce 0x10100000. "); hexint = 0x01011111; hexint = ~hexint; printf("\n\n0x01011111 flipped is %x\n", hexint); printf("But, as we can see, it does not. Let's examine this."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("The printf() function which displays all our text in this program \ \nincluding this very sentence, can print numeric data in several formats \ \nas we've described. Here, we're printing in hex format. \ \nprintf() can't print the results of bitwise operators in zeros and ones \ \nunless each operand is printed in the same number of zeros and ones. \ \nIt prints the arithmetic result in hex format, as we specified. \ \nRemember, in hex notation, a single printed digit represents 4 bits.\ \nSo 0x0001 evaluates to 1, 0x0100 evaluates to 4, and 0x1111 to f."); printf("\n\nTO SET BITS: \ \nCreate an bitmask of 1 for each bit to be set, 0 for all others. \ \n(For example, to set bit 2, the mask is 0x00000100.) Then \ \nOR the register with the mask \ \nlike this: int newReg = 0x00001000 | 0x00000100. Here's the result:"); hexint = 0x00001000; hexint |= 0x00000100; printf("\n\nMy OR'd result: %x\n", hexint); printf("OK. Bit 3 remains set and bit 2 is newly set. Let's move on."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("TO TEST BITS: \ \nthat is, to see if bit 4, for example is set (to 1): \ \nEXCLUSIVE OR the register with a mask \ \nHere's the code: \ \n\n int result; \ \n int 2Btested = 0x00010000; \ \n int mask = 0x00010000; \ \n result = 2Btested ^ mask \ \n printf('Result is: %x', result) "); hexint = 0x00010000; hexint ^= 0x00010000; printf("\n\nResult of test is: %x\n", hexint); printf("The result is zero. That means that bit 4 must be set, \ \nsince with EXCLUSIVE OR, both corresponding bits can't be set \ \nin order for the resulting bit to be set. \ \nSimilarly, if the mask were 0x00000000, the result would be 0x00010000.\ \nThis is still a difficult-to-interpret result; we'll improve on it later."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("TO UNSET BITS: \ \nAND register with a mask of bits to be unset\ \nlike this 0x11111011 \ \nThis'll preserve all register bits except bit 3, which will be unset.\ \nSo for register 0x10101111, \ \nthe result will be 0x10101011. We'll run this code now."); hexint = 0x10101111; hexint &= 0x10101011; printf("\n\nUnsetting bit 3, we have: %x\n", hexint); printf("TO COMBINE BIT MASKS: \ \nOR register with a mask of bits to be set \ \n\nThis is used to add features, each feature represented by \ \none unique bit placement. \ \nThis is used a lot in C and Unix programming. \ \nFor example, if the 'READ' feature is represented by 0x00001000 \ \nand 'WRITE' is represented by 0x00000010, then READ plus WRITE would be: \ \n 0x00001010. This is straightforward enough. \ \nWhat may seem ironic, however, is that to add features, \ \na bitwise OR is used, not a bitwise AND. It's the OR that sets bits."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("TO TEST BITS -- IMPROVED VERSION: \ \nAbove, we used INCLUSIVE OR to test bits. This doesn't really work, though,\ \nsince we can't isolate or print the results of the bit tested. \ \nA better way is to: \ \n\nFirst, isolate the bit by shifting until the bit is in position 0\ \nSecond, to AND 1 to the integer \ \nThird by evaluating: if the result is 1, the bit is set; if 0, it's unset.\ \nHere's an example of the code: \ \n\n int myBit3Test = 0x0c; \ \n myBit3Test >>= 3; \ \n myBit3Test & 1; \ \n printf('Bit 3 is set to: PERCENTx', myBit3Test) "); hexint = 0x0c; hexint >>= 3; hexint &= 1; printf("\n\nBit 3 is set to: %x\n", hexint); printf("Let's explain."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("First of all, here's a format I don't think I've shown before: \ \n\n >>= \ \n\nThis is one of several examples of concatenated operators, whereas \ \na certain operator is combined with an equal sign. \ \nThe meaning here is: hexint = hexint >> 3 \ \nThis is just a shorter way of expressing it. They work for plus signs \ \nmultipliers, shifts, and most operators that do computation (not comparison.) \ \nWe use these shortened operators in C all the time. Python doesn't have them.\ \n\nNow, the code logic: \ \nWe initialize an integer in hex format (not just 0s and 1s); \ \nwe must express it in one of the prescribed numeric formats. \ \nThen we right-shift the integer by 3. This puts bit 3 into the position \ \nformerly held by bit 1. This changes the value of the integer, \ \nso we'd usually copy it into a variable before we do this. \ \n\nAnyway, to isolate this least significant (LSB, or right-most) bit \ \nwe AND it with 1, which is actually 0x00000001. \ \nSo if the rightmost bit is 1, then, the result will be 1; \ \nif it's 9, the result will be 0."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("This is because the AND 1 masks ensures that all bits \ \nto the left of LSB will be 0'd out. \ \n\nIn our example, the initial value was 0x0c, or decimal 12, \ \nor bit pattern 0x00001100. Bit 3, the bit to be tested, is set. \ \nBut we don't know that yet, not until we test it. \ \nBit 4 is also set, but the AND 1 removes it for the purposes of the test.\ \nPretty cool, huh?\n\n"); printf("Now, let's use the TILDE. \ \n\nTO NEGATE AN INTEGER: \ \nor turn it to negative, the syntax is: \ \n\n int myPattern; \ \n myPattern = ~myPattern; \ \n\nWe'll run this code snippet and print the results:\n"); hexint = 0x0c; printf("Orig value is: %x\n", hexint); hexint = ~hexint; printf("Negated value is: %x\n", hexint); printf("As you can see, if we reverse the value of c (1100) \ \nwe get 3 (0011). The preceding 0's in the register containing c \ \nare flipped to f."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Well I think we've covered bitwise operators enough \ \nfor a somewhat-more-than-rudimentary understanding. \ \nI actually spent more time on it than I intended, because I found it \ \nso tricky myself. In any case, let's move on."); /* ******************************************************************** START SPELL CHECK HERE ******************************************************************** */ printf("I want to go back to look at the preprocessor,\ \nsomething in C that is not in Python. \ \nThe preprocessor has a few instructions itself. As mentioned above, \ \nthey are all preceded by a hash sign and unlike C statements \ \ndo not end with a semicolon. The most important of these instructions are:\ \ninclude, if, elif, else, endif, ifdef, ifndef, define, undef, if defined, \ \nif !defined. \ \nThey are pretty straightforward. Here are some examples how they are used:\ \n\n#include \ \nloads in the source file, in this case (the usual case) a header file. \ \nA header file is generally used to contain declarations, not definitions,\ \nof data objects (variables) global to the program code. \ \nData declarations are usually located in another C module \ \nwhich will become part of the executable."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Header files can often include other header files. \ \nMultiple headers, then, may want to include the same file. \ \nYou don't want to include a file more than once; the compiler will complain\ \nabout multiple declarations. So, you use preprocessor directives \ \nto avoid this within the header file itself, specifically: \ \n\n #if !defined(MY_HDR) \ \n #define MY_HDR \ \n #include 'myHeader.h' \ \n #endif \ \n\nThen if another header file is trying to include 'myHeader.h', \ \nit won't, because MY_HDR is already defined for the object \ \n(aka translation unit.) \ \nSimilarly, multiple variations of header files may be included \ \ndepending on what is preprocessor-defined, like this: \ \n\n #if SYSTEM == UNIX \ \n #include 'myUnixHdr.h' \ \n #else \ \n #include 'myMSHdr.h' "); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Regular C code can go between precompiler directives, too. \ \nIt's a little old-fashioned but it's common to see thousands of lines \ \nof code that is conditionally compiled like this. \ \n\nAnother very common use of preprocessor directives is to \ \nconditionally include or exclude debugging code (printfs), \ \nlike so: \ \n\n #define DEBUG \ \n #ifdef DEBUG \ \n printf('We reached function xyz!'); \ \n\nNormally, the #define DEBUG directive would be placed at the top \ \nso the programmer could easily toggle it off and on. \ \nThe printf would be placed at the top of function xyz, in this case. \ \nLet's try this code. "); #define DEBUG #ifdef DEBUG printf("\n\nWe reached function xyz!\n"); #endif printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Yes, this works, Let's try another variation of this: \ \n #define DEBUG 1 \ \n\n #if DEBUG \ \n printf('DEBUG is defined') \ \n #else \ \n printf('DEBUG is not defined') "); #define DEBUG2 1 #if DEBUG2 printf("\n\nDEBUG is defined to 1\n\n"); #else printf("\n\nDEBUG is not defined\n\n"); #endif printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Here we must set DEBUG to a value or it won't precompile. \ \nUsually, 1 or 0 is used. If it's 0, the preprocessor #if condition \ \nis not met. Otherwise, for any other value, the DEBUG statement \ \nwill be printed. "); printf("Note that a preprocessor setting does not use the equal sign,\ \nas a C instruction would. \ \n\nPreprocessor conditionals are used not in executing code, \ \nbut in compiling it. So if DEBUG is not defined (set to 0), \ \ncode depending on it will not be compiled. \ \nPreprocessor directives are a quick and easy way to comment out code, then,\ \njust by directing #if 0 (code here) #endif. \ \nWhenever you want to compile the code change the directive to #if 1. \ \n\nA preprocessor #undef is occasionally used, like this: \ \n\n #ifdef getchar() \ \n #undef getchar() \ \n (now define your own specialized getchar() function here..."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Onward and upward. Let's look at C command line processing. \ \nPython has this as well, and it's very similar. \ \n\nCommand line arguments appear as two parameters for the function 'main'.\ \nThe first is of type int and the second of type pointer to pointer to char.\ \nBy convention, they're called 'argc' and 'argv'. \ \nArgc is an int telling how many arguments there are. \ \nArgv is a pointer to an array of strings, each of them being an arg. \ \nThis allows for a variable number of arguments to be processed.\ \n\nWe usually use the C library function 'getopt()' to process args. \ \nThis is very similar to Python, which of course, derives from it. \ \nHere's the syntax of how getopt is used: "); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf(" (from command line): \ \n\n myProg( -d, -v ) \ \n\n \ \n\n main( int argc, char *argv[] ) { \ \n int c; \ \n while ( ( c = getopt( argc, argv, 'dv') ) != -1 ) { \ \n switch (c) { \ \n case 'd': \ \n debug_switch = 1; \ \n break; \ \n case 'v': \ \n verbose_switch = 1; \ \n break; \ \n default: \ \n ; \ \n } \ \n } \ \n } "); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("getopt(), a gnu library function, comes with gnu C, \ \nthough, strictly speaking, it's not part of the standard library. \ \nAnd it's only used to process single-character arguments, so it's limited. \ \nBut you can see how the code works here -- it loops through all arguments \ \nuntil it processes them all. I won't test it, \ \nbecause I don't know if you're using the GNU library. \ \nSo instead, we'll process it manually. \ \nWe will assume that if there is a command line argument, there is only one,\ \nand that it has the value 'v' (verbose). \ \nOtherwise, we'll do nothing. \ \nThe code looks like this: \ \n\n #include \ \n main(int argc, char *argv[] ) { \ \n char verbose; \ \n if ( argc == 2) \ \n verbose = argv[1]; \ \n do_sumpthin_else(); \ \n exit(1); \ \n } "); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("That's it! We're setting the verbose flag, which we'll use \ \nin conditional printing later, to print more detail."); printf("Every C program has at least one command line arg -- the program itself.\ \nSo we're assuming here the user has typed in either: \ \n CPyDemo \ \n or \ \n CPyDemo v \ \n\nIn fact, I've put this code into the top of this program. \ \nTake a look at it later. So you can test it by entering a v option \ \nwhen you run this little fella again. \ \n\nOh, one more thing -- the 'exit' at the end allows us to return an int \ \nto the OS. It's a function, hence the inclusion of stdlib.h."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Now we'll go clean up a few more details before we quit. \ \nThe first is dynamic storage. This refers to some sort of memory structure\ \nor series of structures, almost always stored on the program's heap \ \n(i.e., global, not local) that the program allocates \ \nafter it has started running. This means that \ \nit is not allocated by the compiler. \ \nInstead, we call a standard library function to do this; it's called malloc.\ \nIt's used like this: \ \n\n char *myBuf; \ \n myBuf = (char *)malloc(128); \ \n\nThis will allocate an area of 128 bytes, and store its address \ \nin myBuf, which will point to a char. We have to 'cast' malloc \ \nto a pointer to char because its default is a pointer to void. \ \nUsually we'll point to a char. We may also point to a user-defined struct.\ \n\nWhat's important here is that this area must be de-allocated \ \nby the programmer when it's not in use; otherwise, it'll hog space \ \nfor nothing. You do this will a 'free myBuf' statement. \ \nTo use malloc, #include "); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("OK. File Management. Quite simple, a lot like Python. \ \nC has a type called FILE*. It's a typedef for a pointer to a struct \ \nthat has information related to a particular file. To open a file: \ \n\n FILE *fp = fopen('MyFile.dat', 'r') \ \n\nThis opens an file for writing only, for example. \ \nHere are some examples (K&R p 242): \ \n\n r open existing file for reading \ \n w create file for writing \ \n a append file (write at the end of the file.) Create if necessary \ \n rb+ open existing binary file for reading and writing \ \n\nThe fopen should always be tested by: \ \n\n if (fp == NULL) \ \n process_error(); \ \n else { \ \n read_file(); \ \n flcose( fp ); \ \n } \ \n\nThere are various C library function calls to read files line by line. \ \nThey're pretty straightforward."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Often, you want to process a file by reading it line by line.\ \nHere's the code to do this; \ \n\n FILE *fp; \ \n char line[80]; \ \n fp = fopen('myFile', 'r'); \ \n if (fp == NULL) \ \n exit(1); \ \n while ( ! feof(fp) ) { \ \n if ( fgets(line, 80, fp) == NULL ) \ \n break; \ \n printf('Another line\n'); \ \n } \ \n\nThis code is terse. (It's from K&R p 133, btw.) \ \nthe while condition actually calls a test-for-end-of-file function \ \nand if it returns negative, the loop quits. So it loops till end of file.\ \nInside the loop fgets is executed as part of a conditional, too. \ \nSo if it's unable to read a line, the result will be NULL."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("This style of K&R's works well, though it takes getting used to.\ \nI like code to be verbose and explicit, generally, so I tried rewriting this.\ \nI found it more difficult than I would have thought. \ \nI'm not going to run this code since I don't want to rely on outside files.\ \nBut speaking of programming styles, keep in mind that C is the language \ \nfor runtime efficiency, not for programmer ease-of-reading. \ \nC is used for lots of memory-intensive activities with temporary data. \ \nFor much business-related programming, other languages, \ \nsuch as Java and Python (interpreted languages) and C++ \ \n(requiring a runtime library) are used. \ \n\nC has its own history, traditions, and conventions. \ \nDifferent application areas using C have different conventions, or styles, \ \nas well. In Unix/Linux kernel-level programming, for instance, \ \nthe use of the dreaded 'goto' instruction is commonly accepted. \ \nIt's NOT in other environments, so I haven't discussed it here. \ \n\nAt any rate, I want to finish up my discussion of programming style."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("For letter casing: lower case is the default. \ \nUppercase is usually used for preprocessor #defines and const data types.\ \nUnderscore prefixes are often used by a programmer to indicate \ \nthat the variable is private, and should rarely be manipulated. \ \nThis is true in Python as well. \ \nDouble underscore prefixes are generally used only within\ \nthe language itself; programmers aren't supposed to use them \ \nin their own code. Some C language-reserved keywords have \ \nboth leading and trailing double underscores. We don't refer to them much.\ \n\nOne final wrap-up before we end with the C Standard Library. \ \nC has a list of reserved words, keywords, which together, \ \ngive us a good picture of its overall low-level features, \ \ncontrasted with Python. The keywords are listed in K&R p 192. \ \nWe've covered most of them. Here they all are, \ \nfor the sake of completion: "); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf(" auto data type; same as local, not often used \ \n break action to escape conditional loop \ \n case condition for a switch statement \ \n char data type; almost always 8 bits \ \n const data type modifier; means that it can't be modified \ \n continue action to go to top of loop \ \n default condition for a switch statement \ \n do action for conditional loop. Used in conjunction \ \n with 'while'. We haven’t' discussed it \ \n double data type. floating point. Usually 64 bits \ \n else condition. Used with 'if' condition \ \n enum data type, integer. See above \ \n extern scope modifier for variable. See above \ \n float data type. floating point. Usually 32 bits \ \n for condition. Used in loop iterations \ \n goto action to branch to label \ \n if condition. \ \n int data type. Usually 32 bits; size of memory address \ \n long data type. Usually same as int "); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf(" register data storage modifier for compiler \ \n return action to go back to calling function \ \n short data type. Usually 16 bits \ \n signed data modifier used to denote positive or negative \ \n Significant since it modifies bit pattern. Default \ \n sizeof operator, though looks like function; \ \n returns size of operand \ \n static data modifier. See above \ \n struct data type. Programmer-specified. See above \ \n switch action. Conditional, like 'if'. See above \ \n typedef data modifier to define programmer-specified types \ \n union data structure. like COBOL 'redefines'. Not used much,\ \n not discussed here \ \n unsigned data modifier. Data positive. Affects bit pattern.\ \n void data type, used as placeholder \ \n volatile data modifier. Compiler instruction. See above \ \n while condition. Starts conditional loop."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("We'll close by discussing some of the functions provided \ \nin the Standard Library. Note that this is the C Standard Library only;\ \nwe won't discuss functions provided in the newer C/C++ Standard Library. \ \nIn practice, C and C++ are both combined, but C++, with its classes, \ \ntemplates, and additional features are beyond the scope of this tutorial. \ \n\nAnyway, the C Standard Library functions are automatically linked in\ \nwith the GNU compiler (no options required), but the signatures \ \nof their functions still must be specified in our program's listings \ \nsince the functions are external. Wee do that by including \ \nvarious header files. \ \nThey are (K&R p 241): "); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf(" assert.h debug macros \ \n ctype.h test character format -- islower, isdigit, etc. \ \n errno.h error handling \ \n float.h process floating pt \ \n limits.h defines sizes of integral types \ \n locale.h to adapt code to foreign language \ \n math.h math-related -- trig, exponent and log, modulo, etc \ \n setjmp.h enable quick returns. Not often used \ \n signal.h process signals; not discussed here \ \n stdarg.h function with variable argument list. Not discussed here\ \n stddef.h rarely-used definitions \ \n stdio.h std input and output \ \n stdlib.h utilities for numeric conversion, storage, etc \ \n string.h strings -- strcpy, strcat, strcomp, strtok, etc. \ \n time.h date and time functions "); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("By far, the most commonly used are stdio and stdlib \ \nthough ctype, errno, limits, math, signal, string, and time \ \nare frequently used as well. 'stdlib.h' contains, among others: \ \n atoi converts ASCII to int. Very useful in print formatting \ \n rand generates random numbers \ \n malloc allocates memory. See above \ \n getenv gets environmental variables such as PATH \ \n system accesses system commands, like pwd, dir, etc. \ \n This is very useful, sometimes necessary \ \n qsort Sorts two objects using Quicsksort algorithm. \ \n Much easier than writing this routine yourself"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("stdio.h provides, among others: \ \n fopen opens file. See above \ \n fclose closes file \ \n printf prints to console or stdout, per format. See above \ \n sprintf prints to string \ \n fprintf prints to file \ \n scanf scans console or stdin, waits for user input, \ \n processes text according to format. See below \ \n sscanf scans input string, otherwise, same as scanf. \ \n Very useful in formatting for printing \ \n fscanf scans file, otherwise, same as scanf. Not often used \ \n getchar read one char at a time from stdin. \ \n Used a lot in testing \ 7\n This is a built-in preprocessor macro, or snippet of code.\ \n Macros aren't used too much any more; inlines are preferred \ \n putchar write one char at a time to stdout. \ \n Also used in testing. A preprocessor macro \ \n getc getchar from file \ \n putc putchar from file \ \n ungetc pushes char last read back onto input stream"); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf(" gets reads a line from stdin \ \n puts writes a line to stdin \ \n fgets reads a line from input file \ \n fputs writes a line to output file \ \n fread reads user-defined block from a file into array. \ \n Versatile, and useful for binary data \ \n fwrite writes n number of chars to file. \ \n Versatile, and useful for binary data \ \n\nA 'line' here means ASCII text terminated by carriage return (newline.) \ \n\nMost of these functions are pretty straightforward. \ \nThose that format data can be used to construct 'records'. \ \nThey would be the printf and scanf functions. \ \nA little about formatting, then we'll quit. \ \n\nAs mentioned above, PERCENT is a delimiter for formatting symbols. \ \nHaving this delimiter, printf can use regular text chars as symbols, \ \nnot literals. Once interpreted, they become literal, \ \nhence, the entire text to be printed, symbols included, \ \nis enclosed by double quotes, and becomes first parameter to the function."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("So much for that introduction. Now for the fine points about formats.\ \nAll are optional except for the data type. Here they are: \ \n\n minus-sign Left-justification \ \n number Minimum field width \ \n dot Delimiter, separating field width from precision \ \n number Precision. See below \ \n char Data type. See below \ \n\nHere are the data types: d, i, o, x or X, u, c, s, f, e or E, g or G, p \ \nThe ones used most often are d, x, u, c, s, and f. \ \n\n d decimal \ \n x hex \ \n u unsigned decimal \ \n c single char \ \n s null-terminated string, not strictly a C type, but a format \ \n f floating point decimal (size double int) \ \n\nLet's see how all this is used: "); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("Here's an example of string justification: \ \n printf('PERCENT-15s', 'my stringlet') \ \n\nLet's try the code. Of course, we have to include string.h first."); char my_string[13]; strcpy( my_string, "my stringlet"); printf("\n\n%-15s", my_string); printf("\n\nYep. The string is left-justified. We've set the minimum length\ \nto 15 in this format, longer than the string, just to demonstrate \ \nhow the minus sign works. \ \nWithout the minus sign here the string would be right-justified,\ \n(the default, since printf usually works with numbers). \ \nYou see, ordinarily, the printed result would be space-filled on the left\ \nto accommodate the minimum length requirement. \ \n\nLet's try format 'aPERCENT15s' format (that is, without the minus sign.) "); printf("\n\n%15s", my_string); printf("\n\nRight-justified, as we expect. Spaces on the left."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("In more common use is the minimum field width; this makes sure \ \nthat large values are accommodated, but padding is done where appropriate.\ \nThis is useful for format alignment of multiple data items.\ \n\nA precision specification can have one of three meanings: \ \n\n Maximum characters in a string \ \n Number of digits after a decimal point, in a float \ \n Minimum digits in an int \ \n\nThis can set a standard limit for a text field. Sometimes truncation \ \nis preferable to a long, rambling text item. In this case, the data type\ \nwould be 's'. \ \nIt can also limit a decimal value to be manageable. \ \nWith a precision of 4, you can print pi, for example, as 3.1416 \ \ninstead of 3.14159265 or whatever. This would be used with a float data type.\ \nYou can also use 'precision' with integers to ensure it won't be truncated.\ \nThe value of this is obvious.\ \n\nMost of the commonly-used data types we've already covered, \ \nso I won't give further detail."); printf("\n\nHit CR to continue \n"); scanf("%c", &cr); printf("I hope you've found this tutorial useful. \ \nYou can send comments or questions to me at: dmrenne@comcast.net \ \n\nGood luck, have fun with C!"); } int myFunOne( int anInt ) { anInt = 4; printf("\nat myFunOne!\n"); return anInt; } int myFun2( struct myStructType *ms ) { printf("\nCalled myFun2 with struct myStructType ptr type\n"); return 1; } int myAltFun( int altInt ) { printf("You entered 2, so you reached myAltFun,\ \nand we are printing %d\n", altInt); } int Flunk( int three ) { printf("Back of the bus! I said enter 1 or 2!. You hit %d\n", three); return 1; }