HOW TO PROGRAM IN C    
(also see the GTMHH on How to Program in C) 
By Meino Christian Cramer <root@solfire.ludwigsburg.netsurf.de> 
    with a few additions by Carolyn Meinel.

Newbie Note:  This lesson requires that you have a Unix shell account.  To learn what a shell account is, see the GTMHHs on how to get a good shell account.  If you know what a shell account is but don't have one, you can find an Internet Service Provider that offers them from http://www.celestin.com/pocia -- or try http://shells.techbroker.com, or get your own Unix shell by installing some sort of Unix on your home computer.  For details on how to do this, see the GTMHH on Linux.  The easiest forms of Unix to install on your home computer are Caldera (http://www.calderasystems.com), Red Hat (http://www.redhat.com), Slackware (http://www.slackware.com) or Debian (http://www.debian.com) Linux.

In this guide you will learn: 
1.0 What Is "C" ? 
2.0 What do we need to program in C? 
3.0 The first program 
4.0 C compiler vs. C compiler 
4.1 If your compiler is a K&R or "old" compiler 
4.2 If your compiler is an ANSI-compiler 
5.0 Parts and pieces of a C program 
6.0 Your Programming Environment 
7.0 How to use libraries 
7.1 Quick Review 
8.0 Data Types 
9.0 The anatomy of a procedure 
10.0 A very special data type: pointers 
11.0 Text, Strings, Arrays and more Pointers 
12.0 Pointer Arithmetics 
13.0 Structures 
14.0 IO -- Input/Output 
15.0 Additions and conclusion: 
16.0 If it doesn't work... 
17.0 Cc, Gcc And The Rest Of The World 

## 1.0 What Is "C" ? 
----------------------------------------------------------------------

    "C" is a programming language. "C" is THE programming language! :-) It is the language in which both the most powerful hacker exploits, most Unix type operating systems and very much of the programs, which you can get for free from internet sites, are written.

    The power of "C" is like the power of a fast car: Use it carefully and sensibly and you will be a winner. Use it without any knowledge and control and you will go off-road, next to a tree.

    More seriously: The design of "C" lets you make things not possible in other programming languages. "C" is the programming language for those of you, who want to gain control over the whole thing, to break into computers, or to keep the bad guys out of your computer. "C" gives YOU, the programmer, the full responsibolity, what will happen.

    OK, there are traps inside "C".  And you WILL fall over them. But, hey, we are learning from errors, we are hackers, so we want to learn, cause we are curious, therefore, there is no better way for us to learn than to make errors. The only error which should not be made is the error of avoiding errors... :-)

This tutorial will introduce the programming language C to you and it want to makes you a little bit curious. It is far beyond the scope of it to TEACH you C. If you want to learn C seriously, buy a good book about C. My favourite one is written by the inventors of C, Brian W. Kerningham and Dennis M. Ritchie and is called "The C Programming Language".

    All example programs given in this tutorial, are written for an ANSI-type of compiler. But in the following you will find tips, how to change the source codes easily, so that they will compile on K&R types of compilers without errors. You mainly have to change the beginning of the function definitions and their prototypes a little bit.

Happy learning, Happy Hacking!

Let's start the story to tell.....

### 2.0 What do we need to program in C? 
----------------------------------------------------------------------

First, let's see whether your account is prepared for you to program in C!

Log into your account and type: 

    cc

Or if this gives the result "command not found", try:

gcc

. This will call a program called "C compiler" (that's why the command is called "cc").   Note: if "gcc" works instead of "cc", then for the rest of this C porgramming guide substitute "gcc: everywhere you see "cc".

 If you have a C compiler you will get an error message (that's quite normal!) but at least you  don't get the message "command not found", whihc means you don't have a C compiler.  If that is the case, get an account with an installed C compiler.   For a list of Internet service providers around the world that you can use to search for one that offers a shell account with a C compiler,  see http://www.celestin.com/pocia.

Or, better: Install LINUX (it is not that hard! If you are able to install Windoze, you are able to install LINUX!), then install gcc, the GNU C compiler, available from http://www.gnu.org.

You have a C compiler installed at your account? Fine! But....what IS a C compiler?

    Do you remember ancient times, when hackers used hex-editors and cryptic tables of "foreign number codes" to write very very very fast and short programs? You don't?  OK, too bad you aren't old like us:) Anyhow, those programs were called "assembler" programs. "Assembler" is the native language of the central processing unit (CPU) of your computer. Because the 
only thing which is important for assembly language is to be fast and readable by the CPU of your computer, it is made of a nothing more than a bunch of NUMBERS.

    But then people (not only hackers) wanted to write programs which were easy to for humans to understand. So they invented the "compiler languages". These languages were made from words (commands) instead of numbers.  Now humans could read those words, but CPUs couldn't.

    Wrong design?

    Not really, because some egg heads also invented programs called "compilers".  Each programming language need its own compiler.  The task of these compilers is to translate the words into assembly language. The input to a compiler is a text file consisting of a (more or less) logical sequence of words, the commands which the programmer has written. This text file is 
called the "source code", because it is the "source" of the program.  The result of a run of a compiler is another file, called an "executable program".  An "executable program" is one which you can run just by typing in its name.  Have you ever tried to run those computer break-in programs you find in places like http://www.rootshell.com?  If you type in the name of a file that holds C source code, it just sits there and does nothing. You have to compile it before you can run the program.

"Programming" means to divide a task into smaller and pieces until these pieces can be expressed by a sequence of commands.

### 3.0 The first program 
----------------------------------------------------------------------

Here's the first C program you will write. It is is a short program. I promise it will be easy. You will need an ASCII editor, to enter the text. Some good editors help you in writing source code by automatically indenting the code, highlighting the commands, giving you direct access to the compiler and so on.

Get a GOOD editor. A bad one is really a pain! I prefer the very quick JED/XJED editor. It is fast and small, not a second OS-layer like the EMACS. And not that cryptic like vi.

NOTE: Carolyn is totally right here: IT IS IMPORTANT to learn to use vi, cause it is the one you will find on any *NIX system. On the other hand it comes from ancient *NIX (*NIX stands for all the different kinds of Unix like Linux, Irix, Ultrix, AIX, BSD, OpenBSD, FreeBSD, NetBSD, etc. etc.) times, its command structure is very powerful and awful IMHO.

Newbie note: Pico is a great newbie editor, and is also available in many Unix shells. We won't make too much fun of you if we catch you using it.

Type this into your favorite editor in your Unix shell account:

#include<stdio.h> 
#include<stdlib.h>

main() 
{ 
printf( "Hello, Hackers!\n" );

#if __STDC__ 
printf( "May I introduce myself: I am a compiler of the new version! \n" ); 
printf( "I am an ANSI compiler\n" ); 
#else 
printf( "I am an old K&R compiler!\n" ); 
#endif

}

Save the text in a file called "HelloHackers.c". 
 

Time to compile the human readable text, our first source code into machine readable assembly language. Time to work, compiler!

Type at the commandline of your account the following command sequence:

cc -o HelloHackers HelloHackers.c

This will call the compiler and tell it to take "HelloHackers.c" and compile ( = translate) it into an executable program called "HelloHackers".

Now check, whether the program really runs! Type:

HelloHackers

Maybe you will get an error message here, like:

HelloHackers: command not found

This looks like a path error. See the GTMHH, Programmers' Series, Number 2 for some ideas on path statements, or ask tech support at your ISP.

To execute the program despite the fact, whether you have got this error type:

./HelloHackers

Now you will get an output. This will be either

Hello, Hackers!

(May I introduce myself: I am a compiler of the new version! 
I am an ANSI compiler.)

or

Hello, Hackers!

(I am an old K&R compiler!)

Nice, isn't it?

### 4.0 C compiler vs. C compiler 
----------------------------------------------------------------------

Maybe you are wondering, why the same program can produce two different outputs without anything changing in the source code or/and with the command to produce the executable program?!

The reason is: There are two different kinds of compilers out there.

In the beginning, when C was designed, its fathers, Brian W. Kerningham and Dennis M. Ritchie, invented a style of C, which was very open. The compilers made on the base of this definition of C don't look very much for errors in the source code. They simply translate the source code despite whether there is something contradictionary  or unlogical in the source code. This kind of C is called of "the old style" or of "the K&R style". Compilers which only  can compile this kind of source codes are "K&R" compilers" or "old compilers".

More important: Because there was no official standardization of this style, different vendors add some "special features" to their compilers. Also, some aspects of this languages were not completely defined by K&R. Slowly, the one programming language C became "different languages, called C". The result was that source codes which could be compiled on one machine without any problems, produced errors on other machine with a 
different compiler.

So when you try to compile some exploit you downloaded from http://www.rootshell.com and it gives you error  messages, the fault may be that it was written in a C version that your compiler doesn't like!

Then, K&R decided to write the Second Edition of their first book about C. This time, the ANSI commitee standardized this implementation of C. All compilers which want to be "ANSI compatible" have to fullfill this standardization. These compilers are called "ANSI compilers", and this kind of C is called "ANSI-C", the modern form of C. These compilers will take a closer look to your source code and will warn you if they will find any suspicious commands.

With a little programming trick, which will be explained later in this tutorial, the source code can decide what kind of compiler it needs to use and produces an appropiate output. 
 

### 4.1 If your compiler is a K&R or "old" compiler 
----------------------------------------------------------------------

If you want to buy "The C Programming Language" by K&R get the FIRST edition of this book. It introduces the first implementation of the C programming language.

As we will see, there is one special so called "function" -- more about this later -- in each source code. It is called "main". If your compiler is a K&R compiler, please use

main()

as the definition of it.

### 4.2 If your compiler is an ANSI-compiler 
----------------------------------------------------------------------

If you want to buy "The C Programming Language" by K&R get the SECOND edition of this book. It introduces the implementation of the C, which has been standardized be the ANSI commitee. 
 

As above, this kind of C uses a special function calle "main" also. But the definition of this function is different from that above. It is

int main( int argc, char *argv[] )

.

Later we will discover more differences between these two types of C compilers. But for now, you only have to remember the kind of main-function, you should use.

Because ANSI-compilers understand the old K&R style also normally, the above example program compiles without a problem on them. In the rare case, that you get error messages or wanrings concerning "main", use

int main( int argc, char *argv[] )

instead of

main()

in the above example.

### 5.0 Parts and pieces of a C program 
----------------------------------------------------------------------

As we have seen in the above example, the process to create an executable program from a source code can abbreviated as:

    source code --> compiler --> executable program

Imagine that you want to write a really big program, say, a 3D-CAD-engine with midi interface, drumkit and real time video. This will really need a large number of lines of code to write down.  What? You want to write all these lines into one very long text file? Oh, no, that is not a good idea!

    It will be easier to write, debug, and build into a working program if you split it into a couple of files.  To make things easier, you would name each file after its contents.  For example, if you want to use the number Pi (3.1415926...), you could declare it as a constant and put it into an extra file.

    And now???

    Looking at the above example, you will get a problem: each source file fed into the compiler seems to produce one complete executable program!

    Lost?

    No! You can instruct the compiler to produce output of an  "intermediate state", if you want half translated source code.  These resulting files are called "object files" (don't ask me why...).

    After translating all single files into object files, in a last step you have to "link" them into an executable program.

    LINK?

    Yes! Linking is a process, where all "untranslated" things, left in the files, are translated and make to fit together.  Now, you have your program!

These were the "outer pieces" of a program. But the program is divided internally, too.

    These parts are called functions or procedures. There is an academically difference between them, but I take it not that seriously. Later I will show you why.

    For now, let's speak about procedures, and keep in mind, that there is another name ("functions"), which nearly the same meaning.

    Ok, back to the main theme... ;-)

    A procedure is a part of code, which do a certain thing for us, for example, it makes a sound, adds two numbers or blacken the screen (a simple screensaver). Each procedure has its own name.

    But one procedure is special. It is the start, where execution of the program begins. This function is called "main."  All other functions must have other names.

    Look at the above example program. It consist of one procedure only, the "main"-procedure. 

### 6.0 Your Programming Environment 
----------------------------------------------------------------------

    Let's have a closer look to what is called a "programming environment". But, what is it?

    A programming environment consists of all the things you need to write programs.  Often you can buy things called "integrated programming environment", mostly programs which should do "all" for you. Mostly they aren't worth the money...

    Why?

    Simply: You can get similar things for free, with all source codes of all used programs including the compiler itself (mostly a best protected secret of companies like MicroSh*t -- so this is a "hack" itself: you gain knowledge of a secret by simply downloading a tar ball ;-)

    And, more important, you can fit things together in your way, as _you_like it. No colored "click here, crash there" with the mouse. If something fails, YOU have the control. Search the error, learn from it, fix it! You don't need people who tell you, what's good for you, do it your way!

    Back to the / ...;-)

    A programming environment for the language "C" consists mainly of a couple of programs and files:

-- an ASCII text editor (don't a word processor!) 
-- a C compiler 
-- libraries 
-- header files

    Until now, we know the ASCII editor, which we have used to enter our first example program. We also know our C compiler and of what kind it is (K&R or ANSI). But what are "libraries????

    Great halls of books? Yes and NO. In this case: NO. A library is a collection of often used procedures.  These procedures has been pre-translated by the compiler.  So, if you want to use a procedure which has been written by someone else and included into a library for you, the only thing you have to do is to instruct the compiler to link against this library.

    Linking is the process where half translated parts of a program, mainly different source codes were made fit together by translating them fully (see above).

    The only thing you need to use the libraries are header files.

    Imagine the following situation: You are writing a program. You want to use a library function, say "printf" of the HelloHacker program.  But instead of typing "printf" you hacked "rpintf" into your keyboard.

    You feed the source code into the compiler. Now the compiler comes to "rpintf" and wants to know whether this is a function defined later in the source code or in a library (in which case it would pretranslate it and won't produce an error message) or whether this function is "unknown", which means: "I don't know anything about this function. Hey, hacker! This one I don't know! So: Define one, or I will not work for you!"

    Most compilers aren't that friendly and won't say anything nearly that nice. It will say something like:

    undefined reference to `rpintf'

    This is the reason why header files are used. Header files contain (not only) so called "prototypes". Prototypes are "announcements" for later defined procedures of libraries.

    So, before you can define or use a function, you have to write down a prototype of it. It is like saying to the compiler  "Hey, compiler, if you will find this one later in the source code, don't grumble! Here is what it should look like!"

    Additionally some important constants are defined in header files, for example the often used constant PI. It is more easy to type "PI" than to remember 3.1415926... every time and write it down correctly. And other things are defined there. Becoming curious? OK, type

   more /usr/include/stdlib.h

    This is only one of the standard header files. Much stuff, isn't it? Maybe you will find the file in another place on your computer, maybe /usr/local/include or something like this. But in most cases it is in /usr/include...

Oh, before I forget! One I have left out in the above list of things found in a programming environment: The debugger. A debugger is a program which helps in finding bugs in a program. But because debuggers are not part of any definition of C, each debugger works in a different way. It is beyond the scope of this tutorial to show how to use a debugger. If you want more, try

    man db

or

    man gdb

at your account. Manpagers are often the best source of informations, you can get.

### 7.0 How to use libraries 
----------------------------------------------------------------------

    Libraries are collections of often used procedures. Even more, these procedures can do very difficult tasks for us, which to implement by ourselves would take hours (days,weeks,months....).

    So, why not to write a example program, which uses a library procdedure, and header files? And with this example we will get an error, which will help us to understand some special context.

    At first, let's have a closer look to a stripped version of our first program (I have left of the code to detect the kind of compiler, you use...)

#include<stdio.h> 
#include<stdlib.h>

int main(int argc, char *argv[] ) 
{ 
    printf( "Hello, Hackers!\n" ); 
}

    Do you see, what is special with this one? No? Remember the text above!    No clue?  "Before using a function, you have to write down a prototype of it." There are two functions used in this program:

main() 
printf()

    The prototype of "printf" is defined in the header file

/usr/include/stdio.h

    If you give the command

grep printf /usr/include/stdio.h

    You will see a couple of prototypes, not only of printf itself, but of similar functions.

    What's with main() ?

    This one is special!!! It is the mother/the father of all functions. It is the point where execution of the program starts. There can be only one function of this name but it must be there. So, to be convenient, the prototype of this special function is directly "burned in" the compiler itself.

    Let's change the program to use more than main().  Let's put in the use of header files defined by ourselves and a call to a library function. Change the above source code to:

#include<stdio.h> 
#include<stdlib.h> 
#include "myprocs.h"

int main(int argc, char *argv[] ) 
{ 
    showme( "How to hack!" ); 
}

void showme( char *mywish ) 
{ 
    printf( "%s\n", mywish ); 
    printf( "%f\n", sin(35.0)); 
}

    Save this as "hh2.c" with your editor.    Next use your editor to create a file with the contents:

void showme( char *mystring );

    Save it as "myprocs.h".    Now give the command:

cc hh2.c -o hh2 

Time to learn! There are errors.... The output of the compiler looks something like :

    hh2.c: In function `showme': 
    hh2.c:14: warning: type mismatch in implicit declaration for 
                  built-in function `sin' 
    /tmp/cca008671.o: In function `showme': 
    /tmp/cca008671.o(.text+0x36): undefined reference to `sin' 
    collect2: ld returned 1 exit status

    Let's see what the compiler is trying to tell us.  First line: The compiler tells us that there is something wrong inside the function showme().

    Second line: There is a warning! Be warned! DON'T think: "Oh, this is only a warning, no error, so: proceed!" But a warning is the error of tomorrow. But it is more difficult to find those warning based errors. This warning said, that there is a type mismatch in the implicit call of the built-in function sin.

    Type mismatch?  A type mismatch is if you have ordered a really nice strawberry ice cream and will get a hot dog instead. Or in other words: If a function wants to get a text and you call it with a number. The compiler said, this happened to "sin". Let's have a look. Remember school days. What was it? "sin" stands for sine. And the argument for sine was a floating point number. So we are right here. "It is a compiler error!" Ah, wait! WE are hackers, so WE want to learn by making errors, not the compiler! What happens to the ice cream example above? They gave you a hot dog instead. The reasons? First: You have ordered an ice cream, they gave you a hot dog. They have made an error, and you have learned nothing. Better case: You have mumbled "Strawberry ice cream, please." They have understood "hot dog" and gave you what they think, you want. Your error, you have the chance to learn ;-)

    In this case, we have mumbled "sin(), please". The compiler doesn't understand that correctly, because: There is no prototype for it.

    (Note: An "implicit call" to a function is a call without having informed the compiler before, how it looks like (no prototype ofr it). This goes often hand in hand with "type mismatch" errors or warnings.)

    Where should I get the prototype definition?

    Simply, as in most cases it is absolutely sufficient to type in the command:

man sin

    My Linux box produces this answer:

----------------------------------------------------------------------

SIN(3)              Linux Programmer's Manual              SIN(3)

NAME 
       sin - sine function

SYNOPSIS 
       #include <math.h>

       double sin(double x);

DESCRIPTION 
       The sin() function returns the sine of x, where x is given 
       in radians.

RETURN VALUE 
       The sin() function returns a value between -1 and 1.

CONFORMING TO 
       SVID 3, POSIX, BSD 4.3, ISO 9899

SEE ALSO 
       acos(3), asin(3), atan(3), atan2(3), cos(3), tan(3)

                           June 8, 1993                         1 
----------------------------------------------------------------------

    Look at the text after SYNOPSIS.  There is a line with "#include <math.h>" !!! Tada! This instructs the compiler to read the header file "math.h" from the system directory /usr/include/ (or something like that, use the "whereis "math.h" command to get the correct path on your computer for this header) before proceeding.

    Insert such a line after the other #include"-lines in our example and compile it again.

    Now, the compiler don't produces that "mismatch error" again, this one is fixed. But the other one remains:

    /tmp/cca009281.o: In function `showme': 
    /tmp/cca009281.o(.text+0x36): undefined reference to `sin'

    Looks very strange....

    While the compiler is translating source code for us, it needs some temporary files to write down things to remember. These files have names like "/tmp/cca009281.o". When the compiler rereads its notes, it realizes that there is a CALL to sin(), but no one has defined this function. And now?

    DON'T PANIC! sin() is part of the math library. Someone else has written down and precompiled the source code for a sine function for us and has included it into the math library.

    Where can I get that library???

It is already there!

    On my system, the math library is called libm.so. This may be different on non-Linux systems, but the compiler uses a shorter sign for it, so it works on all systems.

    Instruct the compiler to link against the math library with the command (don't ask me, why a compiler always link "against" a library and not "link the program with a library"...)

 cc hh2.c -lm -o hh2

    And this time, there is no error messages.

    What does this little "-lm" ?

    It instructs the compiler to link against a library ("-l"). The name of the library is found by taking a "lib" and adding the rest of letters directly after "-l" and concatenating it with "lib" and you will get "libm". Viola! the ".so" is stripped of. It is like the ".c" or ".h" for source code and header files.

    Or in other words: The letter(s) directly after "-l" (the "m" in this case) describe(s) a short form of the name of the library.

    You want to see what else is in that math library? OK, no problem.    Type: 
 

more /usr/include/math.h 
 

    You will find many other prototypes of functions and other cryptic stuff. If you want to use one of that functions, write down its name and then type

man <function name>

    THIS output is more human readable, hahahaha! 
 

### 7.1 Quick Review 
----------------------------------------------------------------------

    What we have tried so far?  We have seen how to invoke the C compiler by simply typing "cc" at the command line.  We have entered some lines of a simple source code and compiled it successfully by typing"

cc <file name>.c -o <name of the executable program>

    And we have made some errors by trying to compile a source code, which contains the call to a library  function. After some lines were changed, we compiled it with:

cc <file name>.c -lm -o <name of the executable>

    We have read about libraries, header files and prototypes. 

### 8.0 Data Types 
----------------------------------------------------------------------

    Again, let's have a closer look to a thing called "data types".

    Nearly everything in a computer is data based (err...not "database", ok?). There are different kinds of data.  A piece of text is different from a number. An integer (numbers like 1, 2, 3, etc.) is different to a floating point number (3.1416, 1.345 E-19, etc.). All these are "data types".

    All things, our programs will work with are data, because it is the only thing a computer can handle -- even it sounds like Bach's Toccatta. More generally spoken, programs are tools to transform data in way, that it could be interpreted in a way, humans are able to understand that interpretations.

    Therefore it is important, that C understands different types of data.

    Look at a good book about C (K&R) to see what different kinds of data types you can use and how they are named.

    To summarize: One thing is important: each simple variable (a variable is a name you pick in a program to store data) can be of one and only one data type. To assign a data type to variable you have to define this variable. For example, the line of code:

int myvar;

    defines a variable "myvar" of the data type "int".  "int" stands for "integer" (a whole number). Furthermore it is the native data type of a certain computer (Watch this little ";"! It is the "end of statement" sign, C uses to distinguish between one command and another.). You can define 
variables of a lot of other types to store all those information, your program should work with. 
 

    But not only variables can be of different data types! To understand, how data and therefore data types are moved around in your program, we now have to take a more abstract view on data types.

    First step: a variable is of a specific data type. This is reflected in a definition like this:  

int myintvar;    /* definition of an integer variable of the data type int */  

    Do you remember the icecream/hot dog example and the resulting "type mismatch error"? Every time, a "thing" of a data type "a" is assigned to a "thing" of a different, non appropiate data type "b" you will get this error. For example:

myintvar = "C";   /* will result in a type mismatch error */

 Maybe, your compiler doesn't say anything directly about a  "type mismatch error", but the error message, which results  from this statement, has its origin in such an conflict or  mismatch of data types.

    You see? The logical consequence is, that not only the left side of an equitation is of a specific data type, also the whole bundle of expressions of the right side form after its evaluation a specific 
data type.

    Furthermore, you have learned something, which you haven't noticed... You know it? No, I don't think so. In many books (the K&R book for example) you will find a "terminus technicus": "LVALUE". What is a LVALUE? A "something" can be used as LVALUE (this is no extra data type, it is a feature...), if one can assign data to it, if it can be used as the LEFT SIDE of an equitation. For example:

myintvar = 5 + 6 - 3;   /* myinvar can be used as LVALUE, ok? */

    but:

5 + 3 - 6 = myintvar;   /* the sum isn't of a LVALUE, nonsense... */

    will result in an error at once. This is a simple example, but there more difficult cases out there, believe me!

    "ok, nice, guy...but what happens, if you divide two integer variables? It can not be taken for sure, that this equitation always results again in a integer value! Maybe the result is of a floating point value. You have no chance to proof this, while you are wrriting the program....", I hear you 
say (or think :O)

    "C" is different, I told you! Here it comes:  - First rule: The compiler only checks for the data types of all  "things", whose types are known at compile time. It will NEVER  calculate equations like the program will do at run time!!!

 - Second rule: Results of a a more exact data type ("floating point" is "more exact" as integer, for example), which will be assigned to an LVALUE "thing" of a less exact data type will be "mutated" into that data type. Example:

myintvar = 5 / 3;    /* after this, myintvar will carry the value of "1" */

      What data type exactly can be tranformed into another one, can be read in a good "C" programming book.

     - Third rule: Assigning a "thing" of one data type to another "thing" of another data type will also result in such a tranforming of data types, if they are not equivalent. Example:

myfloatvar float;         /* variable to store floating point numbers    */ 
myintvar   int;           /* you know this one...                        */

myfloatvar = 5.6;         /* assigning                                   */ 
myintvar   = myfloatvar;  /* after this, myintvar carries the value of 5 */

       Not all data types can be transformed to be fit into another type! See a good book about "C", what data types can be transformed. If an automatic transformation can not be performed by the compiler, it will report that best known "type mismatch error".

### 9.0 The anatomy of a procedure 
----------------------------------------------------------------------

    In our first programming example, the HelloHackers program, we have used nearly all, which will now introduced to you...nice tactics, isn't it?

    Back to the real thing! As far, as we know, procedures (or "functions") are building little sub parts of our program, each designed to do one special job for us. But our examples only have used that special procedure called "main"...what, if we want to write more procedures? 
 

    Ok, Blues Brothers and Sisters, here it comes: Each procedure has input data or "input parameter" (if you want to speak more elitely...), to work with and ouput data ("return value") as the result of the .... (whatever the procedure will perform). And each procedure has one unique name. The only thing we have to do, is to find the correct way, to stick them together :O)

 Now we have to distinguish between the two version of compilers again...

Newbie note: Syntax is the definition of how to talk in a certain language. Taking the icecream/hotdog example.

 "Please give me an icecream"   is correct syntax. 
 "give an Please icecream me"   is wrong syntax.

    Humans have the ability to understand even sentences with a broken syntax, so they don't say: "syntax error at line 14, identifier icecream unknown"

    The syntax of a formal language (nearly all programming languages are designated "formal languages") is much more rigorous, because a compiler or a machine isn't that intelligent...or?


     For those of you, who use a K&R compiler, the following syntax for procedures is used:

DataType0 NameOfFunction( NameOfParam1, NameOfParam2 ) 
 DataType1 NameOfParam1; 
 DataType2 NameOfParam2; 
{ 
   statements as much as you like 
}

     For the needed prototype (see above) for that function, use

DataType0 NameOfFunction(); 
 

   Explanation: "DataType0" is the data type of the value the procedure is returning after it has done its job.  "NameOfFunction" is the name of the function, you want to write. Some compilers cannot handle names longer than 32 characters.  "NameOfParam1" and "NameOfParam2" are the name (only the names) of the variables, you want to use as input parameters. Inside the procedure you can use those variables the same way, you have used "myintvar". The number of parameters you feed into a procedure is not limited. You can use as much you want to use.

    "DataType1 NameOfParam1;" and "DataType2 NameOfParam2;" are the definitions of the variables, which are used as input parameters. Its just like a definition of" int myintvar;". After the opening "{" you can type in the statements of your procedure. With:

return( <value or name of variable, which value is used> ) you can return the return value (...logically...). 
 For those of you, who use an ANSI compiler, the following syntax for procedures is used:

DataType0 NameOfFunction( DataType1 NameOfParam1, DataType2 NameOfParam2 ) 
{ 
   statements as much as you like 
}

For the needed prototype (see above) for that function, use

DataType0 NameOfFunction( DataType1 NameOfParam1, DataType2 NameOfParam2 );

Explanation:    "DataType0" is the data type of the value the procedure is returning after it has done its job.   NameOfFunction" is the name of the function, you want to write. Some compilers cannot handle names longer than 32 characters. "DataType1 NameOfParam1" and "DataType2 NameOfParam2" are the data types and names of the variables, you want to use as input parameters. Inside the procedure you can use those variables the same way, you have used "myintvar". The number of parameters you feed into a procedure is not limited. You can use as much you want to use. They acts like the definitions of variables. Its just like a definition of" int myintvar;". After the opening "{" you can type in the statements of your procedure. With return( <value or name of variable, which value is used> ); you can return the return value (...logically...).  

### 10.0 A very special data type: pointers 
----------------------------------------------------------------------

    Now it comes to a very interesting, but also complex data type -- the pointers. Much concepts of C are based on this data type. Equivalent to the "fast car" comparison to C from the beginning, pointers are like a high power fuel. In the wrong hands, it will burn down nearly everything, but taken carefully and with responsibility it will make your car even faster.

    What is a pointer?

    A pointer is a variable, which stores the memory address of "something".

    Imagine the following story: You want your rooms get painted. You will go to a painter man, carrying all your rooms with you. After he has finished his work, you will carry them back home.

    Sounds like a nightmare to you?!

    But many compilers work that way! For example, you have written a procedure, which will search for a certain word in a long text. While calling the procedure the whole text (=the rooms) are passed to the procedure (=the painter man), the procedure searches for the word, and after finding it (or not) the text is passed back to the calling function.

    Awful, isn't it?

 "C" is different, I told you...

 How would you handle this task?

    You will go to the painter man and say to him:" Hey, I am living in the Third Ave. appartment xyz. The painter man will enter your house, paint your rooms, and go back.

    Now the "C" version of this little story.

    The calling function passes the address of the memory where the long text is stored to the search procedure -- and not the whole text itsself!!!

    The search procedure will "enter" the piece of memory and will search the word. After finishing its task, the text is left alone again, and the result of the search ("found" or "not found") is passed back to the caller.

    In the little painter man story you have played the role of a pointer, you have carried the address of something -- in this case the address of your home -- with you to the master painter (= the search funtion), the master painter used the information to work on the _referenced_ object 
(=your rooms).

    This is the whole trick. The thing, which may confuse you in the beginning, is the used syntax and to decide, when to use a pointer.

    But let's see... :-)

    Again the definition of a ordinary integer variable:

int myintvar;

    "ok, why not to define a pointer like

ptr mypointer;

    it is logical and consequent?!".

 No, it is not that simple.

 Again a story: You play once more the role of a pointer, carrying the address of your home with you. But this time you will go to the fire-brigade (!) instead and give them your address. The firemen will rush to the given address and -- find no fire, instead there are some rooms, which should get 
painted.

    "Crazy story..", you say. OK! This would really not happen om reality. But what goes wrong here? You gave them the address, but not the type of work to be done. That is the reason, why a "pure pointer" doesn't exist.That's why a:

    ptr mypointer;

    does not work. When you pass a pointer to procedure, you always have to define the type of data, which will be found at the given address. Additionally there is an extra operator for defining such a pointer:

    int *myintptr;

 will define a variable (myintptr), which is able to store an address (myintptr becomes a pointer by adding this little "*"), where integer numbers will be found (the "int" in front of the definition).

    More exactly: The "*" means: the address given on the right side of this "*" carries (or better "returns") a data type of the left side of the "*". The "*" is the DEREFERENCE operator.    Use always constructs like "*myvar" instead of "* myvar". They are totally different!!!!  (the second operation is a multiplication).

    So far, so nice. Now we have a pointer variable, but we are currently not able to determine a valid memory address, where something is stored, which can be accessed using our new pointer. No problem! "C" would not be "C", if there would be no....(you know the rest...)

    Above we have seen, what DEREFERENCING means. Now the counterpart, the REFERENCING of data. DEREFENCING allows the access to the data behind a memory address, now it is time to get the address, where the data is stored. Again define two ordinary variables and fill them with data:

int myintvar1; 
int myintvar2; 
myintvar1 = 5; 
myintvar2 = 8;

    and additionally, define one nice pointer, which can be used to access integer data:

int *myintptr;

    After this, the pointer is unitialized, it "points into the desert" (is this slang used elsewhere???). This is where the REFERENCING OPERATOR will be used. After

myintptr = &myintvar1;

    myintptr is loaded with the address, where the variable myintvar1 is stored. The "&" is the REFERENCING OPERATOR. The "&" means: return the address of the "data object" of the right side. Now a little bit DEREFERENCING again. After

myintvar2 = *myintptr;

    myintvar2 will be set to "5" also.

*myinptr = 10;

    will also work and loads myintvar1, which address is stored in myintptr, with 10.   Use always constructs like "&myvar" instead of "& myvar". They are totally different!!!!  (the second operation is a binary AND).

Newbie note:   WARNING!!! As every freshly defined variable, a pointer carries "rubbish data". Using a variable in read operation without prior initialization will cause -- as a result of the rubbish data -- rubbish results. USING A UNITIALIZED POINTER WILL CAUSE EVERYTHING FROM UNWANTED RESULTS, HARDLY TO DETECT RANDOM FAILURES TO TOTAL CRASHES OF THE PROGRAM!!! Be warned!!! The first step after the definition of a pointer should ALWAYS its initialization!!!!!!

    Conclusion: As we have seen in examples in the beginning, in an equation both sides of an "=" must be of equivalent data types. More generally spoken, if

myintptr = &myintvar;

   is given, and you want to add one level of dereferencing, you have to do this on both sides of the "=" :

*myintptr = *(&myintptr);

    The "*" and the "&" operator on the right side cancel each other out. So it becomes:

*myintptr = myintptr;

Here is an example program to show you the effects of referencing and dereferencing in short:

---8<--------------------------------------------------

#include <stdlib.h> 
#include <stdio.h>

int LetsLookAtIt( int *anintptr ); /* prototype of our little subprocedure */ 
 int main( int argc, char *argv[] ) 
{

    int myvar;        /* an integer variable                */ 
    int *myintptr;    /* a pointer which can point to any 
                         location, which holds an integer 
                         value                              */ 
    int anothervar;   /* another integer variable           */

    myvar     = 1963;           /* load myvar               */ 
    myintptr  = &myvar;         /* get the address of myvar  */ 
    anothervar= 0;              /* initialize this          */ 
 

    /* Take a look, what's in there before calling the subprocedure*/ 
    printf( "%s\n", "--- BEFORE THE CALL OF THE SUBPROCEDURE ---" ); 
    printf( "anothervar: %d\n", anothervar ); 
    printf( "myvar     : %d\n", myvar      ); 
    printf( "&myvar    : %p\n", &myvar     ); 
    printf( "myintptr  : %p\n", myintptr   ); 
    printf( "*myintptr : %d\n", *myintptr  ); 
    printf( "\n\n" );

    anothervar =               /* call a subprocedure      */ 
     LetsLookAtIt( myintptr );  /* pass the returned value to 
                                   our second integer 
                                   variable                 */

    /* have a look at the results 
    */ 
    printf( "\n\n%s\n", "--- AFTER THE SUBPROCEDURE HAS RETURNED ---" ); 
    printf( "anothervar: %d\n", anothervar ); 
    printf( "myvar     : %d\n", myvar      ); 
    printf( "&myvar    : %p\n", &myvar     ); 
    printf( "myintptr  : %p\n", myintptr   ); 
    printf( "*myintptr : %d\n", *myintptr  ); 
    printf( "\n\n" );

    return( 0 );

}

int LetsLookAtIt( int *anintptr ) 
{

    int mysecndvar;

    printf( "\n%s\n", "*****This is LetLookAtIt() speaking...*****" ); 
    printf( "%s\n", "This is, what we have got as a parameter..." ); 
    printf( "anintptr     : %p\n", anintptr  ); 
    printf( "*anintptr    : %d\n", *anintptr ); 
    mysecndvar = *anintptr; 
    printf( "\n%s\n", "After doing a \"mysecndvar = *anintptr;\" we have got:" ); 
    printf( "mysecndvar   : %d\n", mysecndvar  ); 
    printf( "&mysecndvar  : %p\n", &mysecndvar ); 
    printf( "anintptr     : %p\n", anintptr    ); 
    printf( "*anintptr    : %d\n", *anintptr   ); 
    printf( "\n%s", "Now change mysecndvar with a " ); 
    printf( "%s\n", "\"mysecndvar = 2002;\""   ); 
    mysecndvar = 2002; 
    printf( "mysecndvar   : %d\n", mysecndvar  ); 
    printf( "&mysecndvar  : %p\n", &mysecndvar ); 
    printf( "anintptr     : %p\n", anintptr    ); 
    printf( "*anintptr    : %d\n", *anintptr   ); 
    printf( "\n%s\n", "Last experiment: do a..." ); 
    printf( "%s\n", "\"*anintptr = 1998;\""    ); 
    *anintptr = 1998; 
    printf( "\n%s\n", "and look at the result..." ); 
    printf( "mysecndvar   : %d\n", mysecndvar   ); 
    printf( "&mysecndvar  : %p\n", &mysecndvar  ); 
    printf( "anintptr     : %p\n", anintptr     ); 
    printf( "*anintptr    : %d\n", *anintptr    ); 
    printf( "%s\n", "good bye! back to the calling procedure," ); 
    printf( "%s\n", "and return \"1234\" as the returned value." );

    return( 1234 );

} 
 ---8<--------------------------------------------------

Memo sticker:  Remember the different prototypes and function definitions used for older K&R "C" compilers! See "The anatomy of a procedure" above.

   Compile this little program and run it. Think about the results, meditate, enter the transcendent dimension of pointer programming, fly around the world, let the sunsite in, hihihi

    Back to earth: You see the effects of all this? One thing to mention: Every time the contents of pointer, the address it is carrying, is printed to the screen, you will see something like "0xbffff314". This is one way to display memory addresses with "C":

    The "0x" stands for "next digits are in hexadecimal notation" and the rest, the "bffff314" is the address itsself. It is not important, what exactly the address is, only watch where addresses will change and where they will remain the same. The absolut values will be different on your 
machine/account for sure!

    One last thing: May be you have wondered why "main" is allways defined as

         int main( int argc, char *argv[] )

    on ANSI-compilers, despite the fact, we have not used any of the defined variables "argc" and "argv".

    This is why "main" is the first procedure to be executed and should be also the last one, before leaving the program. Therefore "main" is like an interface to the rest of your computer and especially to the OS.

    If everyone would define "main" in a different way, no program would be able to talk to another one (every program has a "main" procedure, do you remember?).

    Because Uni* and "C" are so close together (UNI* is built from C-souce code -- take a look at the sources of Linux ;), there is something like a standard:

    A program, which returns a "0" while leaving "main" says something like "ok, no errors encountered so far" to the rest of the world. Any other value means something like "hey, I have found something, we have to talk about, look into my documentation for more information!"

    The first edition of the K&R book defines the language "C" in a VERY open way: A compiler made on base of this standard, checks nearly nothing of the source code. No warnings were given. Nearly everything was allowed.

Tell me the difference of

  int myvar; 
  float *ptr1; 
  int   *ptr2;

  myvar = 2; 
  ptr1  = &myvar; 
 

and

  int myvar; 
  float *ptr1; 
  int   *ptr2;

  myvar = 2; 
  ptr1  = &myvar; 
 

    Got it? No? In the first example, the programmer definitly knows, what s/he does and tries to experiment with pointers. In the second example the programmer types "ptr1" instead of "ptr2" errornously.

    But compilers cannot see this distinction! With a compiler made on base of the first "C" standard, similiar things would compile without any warning. And believe me, such errors are very difficult to find!!! Really!!! 
 

    Therefore the ANSI people have standardized the definition of "C" as of the second edition of the K&R book.

    Now the compilers would give warnings or even errors and abort compilation, if finding such things. Don't misunderstand me: Nearly all tricks used in former days with the old standard are still possible, but you have to say something like "Hi compiler! This line is a trick and no typo! Please compile it!" explicitely in your code. And errors are also still possible ;-)

    This ANSI defintion defines "main" as

    int main( int argc, char *argv[] )

    as mentioned above.

    Again: If you have the choice between an old fashioned K&R-compiler and a compiler, which is built after the ANSI standard, choose the second one, especially while learning "C". Things are not that confusing, if doing so.

    How to check, what compiler you have?

    Use the first program, we have made as an example, to check your compiler. You have to compile it with the compiler, you want to check.

### 11.0 Text, Strings, Arrays and more Pointers 
----------------------------------------------------------------------

    Remember,

int myintvar;

    defines an integer variable and

int *myintptr;

    defines a pointer to hold the address of any memory location, where an integer variable was stored.    Keep this in mind, when we do the next step now.

    Maybe you have asked yourself the whole time while reading these little "C" tutorial: "Number, numbers, numbers...all the time numbers?! Isn't C able to handle TEXT?"

    "C" would not be "C", if the answer to this question would be "No, C can only handle numbers...". But you "C", "C" is "C", so "C" now, how to handle text... :-)

    From the computers point of view, a text consists of a long (or short) string of letters (...and some additional punctuation marks...).

    Let's define a variable, which can hold ONE letter.

    char myletter;

    That's it!    Next time, we will learn, how to......    No, I am only joking -- I won't leave you standing in the rain...    Ok, one letter isn't that much. If we do

char myletter0; 
char myletter1; 
char myletter2; 
char myletter3; 
char myletter4; 
char myletter5; 
char myletter6;

    we would be able to store all seven-letter words. Nice trick...or?    The hack is, to use a so called ARRAY!    This

char myletter0; 
char myletter1; 
char myletter2; 
char myletter3; 
char myletter4; 
char myletter5; 
char myletter6;

    will mutate to

char myletter[7];

    Now we have defined an array of seven character variables at once. If we would take a microscope to look into the main memory of our computer, we would see:

        +-+-+-+-+-+-+-+ 
        | | | | | | | |     <----- cells of memory, each is able 
        +-+-+-+-+-+-+-+            to hold one character...

index:   0 1 2 3 4 5 6

    Seven memory cells of the data type "char" each, in a row or a STRING of character variables.

    Each memory cell can be accessed by its INDEX. But be careful here: The value inside the [] of the definition of an array variable is THE NUMBER OF CELLS AND *NOT* THE HIGHEST POSSIBLE INDEX!!!!!    The index starts always with "0"!!!

    This fact is a nice opportunity to learn ;-) (making errors) 

But first: a short program? A short program ... James -- PLEASE ?! 
 

---8<--------------------------------------------------

#include <stdio.h> 
#include <stdlib.h> 
 

int main( int argc, char *argv[] ) 
{ 
    /* define an array of char and assign a short text 
    */ 
    char mystringvar[21] = "HappyHackers we are!";

    /* print the text to the screen 
    */ 
    printf( "%s\n", mystringvar );

    /* check for a certain character -- attention! 
       the first character of the string has the 
       index "0" !!! 
    */ 
    if( mystringvar[2] == 'p' ) 
    { 
        printf( "%s\n", "Check successful!" ); 
    } 
    else 
    { 
        printf( "%s\n", "Check not successful!" ); 
    }

}

---8<--------------------------------------------------

    (Furthermore, with this example you see how to handle conditions... look at the "if"-statement! Don't confuse '=' (assign to) with '==' (equal to) 
!!! It is important!)

    Imagine you are reading a big book ("Lord of the Rings", "Dune", or something like this). What do you think? When you will stop reading the book normally? What gives you the hint to stop reading? Would you first count its pages? And while reading you will decrease this number? And you will stop, when your "counter" reaches zero???

    Sounds stupid, doesn't it?  But some compilers...( surely, you know the rest...)      But "C" is different...(also a known statement...)

    Surely, you will stop after you have recognized the last page, the last line of text, the last letter and finally exactly, when your eyes have reached the first "blank" after the last letter or sign (mostly a dash :*) Correct?

    This is nearly the same way, "C" handles strings.

    The line of code

char mystringvar[21] = "HappyHackers we are!";

    will define a array variable and store "HappyHackers we are!" in it in one go.   Does someone have recognized something special in the program above? No? Finding security holes in foreign computers is more easily done, eh? The text "HappyHackers we are!" (the "" are not stored -- they are only delimiters...) is 20 characters long, why have I defined mystringvar to be 21 characters long?

    The trick is, that the "C" compiler stores not only the string itsself in the memory, it adds a zero (not the character "0", but the value 0) after the last character, the "!". This 0 has the same function as the first blank after the text of your book: It stops your program processing that string. In this case: It prevents the printf() function from printing things stored in the memory "behind" the defined array.

Therefore you need one more memory cell in the character array than the longest text to be stored.

    Ok, so far?

    Now a real complex thing. Something for future Uberhackers ;-) (this "Uberhacker" word looks like a German-English mix, isn't it Carolyn?)

    Let's write a little program again:

---8<--------------------------------------------------

#include <stdio.h> 
#include <stdlib.h> 
 

int main( int argc, char *argv[] ) /* for old compilers use main()!*/ 
{ 
    /* define a little helper variable of type char 
       to be used later in this program 
    */ 
    char mycharhelper;

    /* First we define an array of characters: 
    */ 
    char mychararray[21] ="HappyHackers we are!";

    /* Additionally we define a pointer to a character: 
    */ 
    char *mycharptr;

    /* Let's make the pointer point to the first character 
       (index=0) of our string: 
    */ 
    mycharptr = &(mychararray[0]);

    /* Let's have a look to the addresses so far: 
    */ 
    printf( "mycharptr:           %p\n", mycharptr   ); 
    printf( "&(mychararray[0]):   %p\n", &(mychararray[0]) ); 
    printf( "mychararray:         %p\n", mychararray );

    /* Now check the zero termination trick: 
       First print the whole string 
    */ 
    printf( "The whole string: %s\n", &(mychararray[0]));

    /* Now print only " we are!", starting with the 
       fourteenth character, the "w"

    */ 
    printf( "Part of the string:%s\n", &(mychararray[13]));

    /* Now cut the string after "HappyHackers", but backup 
       the character to be overwritten by our additional 
       terminating 0 first...

    */ 
    mycharhelper = mychararray[12]; /* backup the " "             */

    mychararray[12] = 0;            /* fill in a terminating zero, 
                                       leave the rest untouched   */

    /* print the result 
    */ 
    printf( "The shortened string: %s\n", &(mychararray[0]));

    /* Repair the string: 
    */ 
    mychararray[12] = mycharhelper;

    /* print it again: 
    */ 
    printf( "The repaired string: %s\n", &(mychararray[0]));

    /* no errors, so return an OK 
    */ 
    return( 0 );

}

---8<--------------------------------------------------

    Type in, compile and run!  Watch the output and find...
### 13.0 Structures 
----------------------------------------------------------------------
Rewind your knowledge about "C" back to the data types! Now it comes to a really fantastic data type! With "C" it is possible to build your own! Yes, no FX -- it is just "C".
Again a little story... :) Imagine you want to store the names of your friends, along with their birth dates, their complete addresses and finally a piece of text -- a comment or somethnig like that.
Hmmm....
What's about storing all names in arrays, all birth dates in another array, again another array for the addresses, and so on. Urks! Bad design! This may work for a handful of friends...but when it comes to a real big party...forget it!
What about this: Invent ONE big variable, designed to store all informations of one person. Fill this variable with the informations, you have and store it on disk for an later excess .. errrrr... access. Wipe out the information in the mem, fill in new information, store it also and so forth. Looks like a little database program... (but it is far away from those database programs used in the "real world" -- this is only an example... :)
Hungry? 
Curious?
Ok, here it comes: "C" makes it possible to build so called "structures". A structure is a "block" of different "sub-" variables glued together. It is like one piece of a form of a block of forms. Here is the structure equivalent to the "Hello Hackers!" program of the beginning: the address book example.
The following infos should be stored in that structured variable:
-- the complete name 
-- height of the person 
-- street 
-- town 
-- zip code 
-- birth date (day,month,year) 
-- a comment.
"Ahh! I understand!," I hear you saying, "let's make one very big character array to store all this informations in text form -- just like the text I wrote down on my notebook!"
Ok, one possibility...but it has one really big drawback: Imagine you want to search all addresses, which have a certain zip code. Because of the different length of the things stored before the zip code information, the zip code itsself will start at different -- and more important -- unknown positions in that array...again, wrong design! Better to try this one:
struct myadresstype { 
char name[50]; 
float height; 
char street[30]; 
char town [30]; 
int zipcode [10]; 
struct birth { 
int day; 
int month; 
int year; 
}; 
char comment[200]; 
};
Note: 
I live in Germany, I don't know the exact "design" of zip codes or postcodes elsewhere in the world. Let's suppose for this example, a zip code is a whole number, which can be stored in an integer variable. Ok? THANKS! ;-)
What you see above is called a structure, a composed or compound data type. You can put in those structures as much you like and all types which are known by the compiler. Even structures in structures are possible. The above example is a structure DECLARATION not a DEFINTION of a structure variable!
Newbie note: Don't carry it too far in the beginning! A seven layered structure can be highly confusing, especially when using same or similiar names for different instances of elements of the main and the sub-structures....
Newbie time again: 
DEFINITON: Every time, you write down source code, which will occupy memory in the program after compiling the source code, is a definition of something. 
Example: 
int mydefinedvar; 
will instruct the compiler to allocate enough memory for one integer variable in the resulting program: this is a definition of a variable. 
DECLARATION: Every time you write down source code, which will be handled as "information to the compiler" for later use in the source code and which won't directly cause memory allocation, is a declaration of something. In the above example, we have said to the compiler: "Compiler! I want to inform you, that I have invented a brand new type of variable -- a structure called "myaddresstype". " This is called a declaration of something. 

After the above the compiler knows about the design of this brand new type. Now, it is time to define a variable of that type:
struct myaddresstype myaddressvar;
Watch this little "struct" in the beginning! This informs the compiler "to look in his notebook for 'structure declarations'" how it looks like.
myaddresstype myaddressvar; /* DOESN'T WORK! */
Won't work! What we have so far? We have: a declared structure type and a ready-to-use defined structure variable. Fine... Let's fill the variable with "stuff"... To access the elements of structures, we will use the following pattern:
<name of the variable>.<name of the element>
For the sub-structured part of the example above ("birthday"), we will use:
<name of the variable>.<name of the element>.<name of the sub-element>
This has no end! If declared so, you can even use:
<name of the variable>.<name of the element>.<name of the sub-element>. 
<name of the sub-sub-element>.<name of the sub-sub-sub-element>.......
But be careful! For the COMPILER, it is no problem to understand those highly structured structures of a structured sub-structure.... And for you ?;-) Back to the filling job...
myaddressvar.name = "Meino Christian Cramer"; 
myaddressvar.height = 1.22; 
myaddressvar.street = "Somewherestr. 4711"; 
myaddressvar.town = "Wintermute Town"; 
myaddressvar.zipcode = 2600; 
myaddressvar.birt.day = 95; 
myaddressvar.birt.month = 15; 
myaddressvar.birt.year = 2000; /* Oh, yeah! We can store even 
the year "2000" perfectly, so 
we are prepared! No YEAR2000 
hazards! 
*/
myaddressvar.comment = "Likes strawberry icecream." 
Oh, sorry, you want to store more informations, than that above? Ok, try this one instead:
struct myaddresstype myaddressarray[100];
and 
myaddressarray[i];.name = "Meino Christian Cramer"; 
myaddressarray[i].height = 1.22; 
myaddressarray[i];.street = "Somewherestr. 4711"; 
myaddressarray[i];.town = "Wintermute Town"; 
myaddressarray[i];.zipcode = 2600; 
myaddressarray[i];.birt.day = 95; 
myaddressarray[i];.birt.month = 15; 
myaddressarray[i];.birt.year = 1998; 
myaddressarray[i];.comment = "Likes strawberry ice cream." 
With "i" set to a number between 0 and 99 (or was it 100? CHECK THIS! It is one of the most common newbie errors when using array indices...!) 
Play around a little bit with structures.
### 14.0 IO -- Input/Output 
----------------------------------------------------------------------
Our previous example programs were somehow boring: type in, compile it, run it, watch the printout. "Real" programs accept an input, "think" about this input and send it to the output. Often things are read and written from and to the hard disk. The following will give you a hint, how to start with this task.
But before coming to the details, let's have a look what your operating system (of a Unix type) is thinking about it. Uni* has three built-in "channels", with the posibility to move any data through them. These "channels" are the default for the input and ouput of data . The names of these channels are:
stdin which is the abbreviation for "standard input" 
stdout which is the abbreviation for "standard output" 
stderr which is the abbreviation for "standard error"
Oooops! There is a "standard error" in Unix ??? No, no, keep cool! This is only common slang for "standard output channel for error messages". May be, you have used these I/O-channels without having noticed, that they are there... If you type for example
echo "Hello Hackers"
'echo' will print
Hello Hackers
through the standard output (channel).
And typing in the command itsself uses the standard input (channel) for doing so. It is the keyboard, which input is echoed to stdout at once (the command appears on the screen). And if a command fails, its usually prints its error message through stderr.
Because using these channels is the default, you don't have to program any "special commands" in your program while using printf to print through stdout or fscanf() for reading the keyboard. But as mentioned above, this type-compile-run cycle is somewhow boring, everyone can do it. But not everyone is a hacker, we are HappyHackers, we are NOT "everyone" -- so let's do something more advanced!
First some explanations: If you want to access any file of a Unix filesystem, you have first to talk to the OS and tell it, what you want to do with that file. After doing so, you will get back a pointer to an OS-internal structure (you don't need to know anything about its contents, it is a kind of "scratch pad of the OS"). The structure describes any aspect of the file, so that the OS can handle your request correctly. After getting such a pointer, you will access the file. After you have finished, you have to say to the OS: "OS, I have finished the accesses to that file. You are 
now allowed to forget anything about this file, you have put into your scratch pad structure."
Requesting an access to a file is called "opening a file" Reading from a file is called "reading the file" (logical, isn't it?;) Writing to a fi......<blurb>........."writing to a file". Appending to a fi........BLAH BLAH......"appending to a file" Ending the access to a file is called "closing a file"
Now, guess the names of the library functions.... :-) 
Note: 
There are two versions of library functions for accessing files, for example:
open() and 
fopen()
I will explain the fopen/fread/fwrite/fclose familiy of commands only, but there is nothing special with the use of the open/read/write/close-family of commands. See the manpages of that commands.
Because the fopen/fread/fwrite/fclose familiy of commands is very versatile, it is important to read the manpages additionally!!! By the way: It is always important to read the manpages.... :-)
A little program? Here it comes...
!!! Again: read the manpages to the following C library functions: 
man strcmp 
man fopen 
man fread 
man printf 
man feof 
man fscanf 
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
PS: This program cannot read files named "quit" ;-)
---8<--------------------------------------------------
#include <stdio.h> 
#include <stdlib.h>
FILE *askforfile( char *afilename ); 
/* this program reads a file and counts 
* how much of each different character is in there 
*/ 
int main( int argc, char *argv[] ) 
{
/* this will be a buffer to hold parts of the 
* file, which will be rtead by our program 
*/ 
char buffer[500];
/* this will be a pointe to the buffer-array 
*/ 
char *bufferptr;
/* this array holds 256 counters. If a byte 
* with a value of 124 (for example) is found 
* in the file, counters[124] will be incremented 
* by one 
*/ 
int counters[256]; 
int bytevalue;
/* this is used to indicate the end of the file, 
* see below 
*/ 
int endoffile;
/* two counters: in C programs, variables for 
* counters are often named "i" or "j" 
*/ 
int i; 
int j; 

/* define a pointer to a FILE-structure 
* (the scratchpad of the OS mentioned above, 
* often this is called a "stream"... 
*/ 
FILE *ifp; /* I often use "ifp" for a pointer 
* to a stream, opened for input, 
* and "ofp" for a stream opened 
* for output... 
*/
/* this will carry the name of the file to be read 
*/ 
char thefilename[150]; 
/* initialize pointer to NULL, which is the 
* "pointer version" of 0, to mark, that 
* this pointer is initialized but not valid! 
*/ 
ifp = NULL; 
/* initialize the array of counters! 
*/ 
i = 0;
/* as long as i hasn't reached 256 (index = 255 is the 
* last element of the array 
*/ 
while( i < 256 ) 
{ 
/* set corresponding array element to 
* zero 
*/ 
counters[i] = 0;
/* increment index by one 
*/ 
i = i + 1; 
} 
/* ask for the filename of a file to open 
*/ 
ifp = askforfile( thefilename );
/* check, whether user wants to quit program 
*/ 
if( 0 == strcmp( thefilename, "quit" )) 
{ 
printf( "Good bye, C you next time...\n" ); 
return( 0 ); 
}
/* now read the file: but be careful, not to read from 
* "behind the file". A library function, which checks 
* for the _E_nd _O_f _F_ile, will be called each time, 
* when we have read a part of the file. After reaching 
* the end of file, the loop stops, cause feof() -- 
* the library function -- has recognized the end of 
* the file. 
* 
* 
* initialize our EndOfFile-variable to 0, saying, 
* that we haven't reach the end of the file 
* currently 
*/
endoffile = 0; 
while( endoffile == 0 ) 
{
/* fread returns the number of items 
* read. Near the end of the file, 
* this number can be less than 
* 500, for example, if the file 
* has a length of 1200 bytes. 
* Think about it ;-) 
*/ 
i = fread( buffer, 1, 500, ifp );
j = 0; 
while( j < i ) 
{ 
/* !NEVER! try to change the pointer 
* represented by the name of an 
* array itsself!!! 
* First copy pointer to an extra 
* variable 
*/ 
bufferptr = buffer;
/* this is equivalent to 
* bytevalue = buffer[j]; 
* BUT! We use the advanced 
* pointer arithmetic stuff! 
* OK? 
*/ 
bufferptr = bufferptr + j; 
bytevalue = *bufferptr;
/* now increment the appropiate 
* counter in our counter array... 
*/ 
counters[bytevalue] = counters[bytevalue] + 1;
/* next one, please... 
*/ 
j = j + 1;
}
/* check for the end of file 
*/ 
endoffile = feof( ifp ); 
} 
/* here we are! All is count in our file, we don't need 
* it anymore, so close it! 
*/ 
fclose( ifp ); 
/* print the results: 
*/ 
i = 0;
while( i < 256 ) 
{ 
/* do not report values of zero count 
* 
* "!=" means "not equal to" 
*/ 
if( counters[i] != 0 ) 
{ 
printf( "A value of %3d was found %5d times in the file.\n", 
i, counters[i] ); 
}
/* next, please... 
*/ 
i = i + 1; 
}
return( 0 );
} 
FILE *askforfile( char afilename[150] ) 
{
int cmpresult; 
FILE *tmpfp;
/* initialize pointer to NULL, which is the 
* "pointer version" of 0, to mark, that 
* this pointer is initialized but not valid! 
*/ 
tmpfp = NULL; 
/* as long as tmpfp is not set to an valid address... 
*/ 
while( tmpfp == NULL ) 
{
/* ...ask user for the filename 
*/ 
printf( "Please enter a name (path/filename) of an existing file:\n"); 
fscanf( stdin,"%s",afilename);
/* check, whether user wants to quit the program: 
compare input wth the word "quit". If equal 
the library function "strcmp()" will return zero. 
*/ 
cmpresult = strcmp( afilename, "quit" ); 
if( cmpresult == 0 ) 
{ 
printf( "....quitting!\n" ); 
return( NULL ); 
} 
else /* otherwise... */ 
{ 
/* try to open file with the filename, user has given 
*/ 
tmpfp = fopen( afilename, "rb" ); 
}
}
return( tmpfp ); 
}
---8<-------------------------------------------------- 
What you have missed so far...many, many aspects, possibilities and nearly all of the advanced power hidden in the book "C", written by Kerningham & Ritchie <../bookstore/programming.shtml>, are left out. This tutorial is no replacement for any kind of book about C <../bookstore/programming.shtml> and was never meant to be.
If you have read such a book, you will see that the example programs are often written very circumstantial in some points.
You may have missed some basic things in the last pages of this "Appetizer to C". Yes, you are right, I have left out many of the control structures, nearly all operators and many other stuff, which would not fit in the space of this little thing.
Why?
You will discover, that most of them will be the same in nearly all programming languages. And -- be honest -- if telling first, what is equal to other programming language, would not sound very interesting to you, wouldn't it?
And: Many other things, far beyond such basic scopes, like pointer to functions, multi dimensional arrays, the "," operator, all that "scope of validity of definitions" -stuff, how to build own libraries, all commands to the preprocessor, optimizing option of the compiler... I have left out. Believe me, there are so MUCH exciting things to discover!!!
### 15.0 Additions and conclusion: 
----------------------------------------------------------------------
Step 1: Control structures. 
---------------------------------------------------------------------- 
A control structure is an instrument, which allows you to take influence of the control flow of a program.
Newbie note: 
CONTROL FLOW: Imagine, you have printed out your whole program on endless paper. Then -- taking a pencil -- you will follow the commands in the sequence they will be executed by the computer. The "thing" followed by you, is the -- so called -- control flow.
DATA FLOW: Again, the same example. Start with the main() procedure. Imagine, you would be able to paint each contents of each different variable with a different color, which would not fade out. Now execute the program as above. If a certain contents of a certain variable would move to another variable, the contents will make a coloured line onto the paper from one variable to the other. After the program has finished, you will find your paper filled over and over with coloured traces of the data. What you see is the so called -- data flow.

Not-so-newbie-note: Compilers should be able to analyze a part of the control flow and a part of the data flow to make optimizations, so, that the resulting program would run faster. A little example: Analyze control and data flow of the following part of a program and optimze it afterwards by writing better code ;-)
i = 0; 
while( i < 10 ) 
{ 
j = 5; 
printf( "The variable j is set to %d\n", j ); 
printf( "The variable i is set to %d\n", i ); 
}
What would be changed by the compiler while compilation to optimize that part of code? Here is the syntax of some control structures.
IF 
~~~~~~~~~~
if( <condition> ) 
{ 
<statements executed, when conditin is TRUE> 
} 
else 
{ 
<statements executed, when conditin is FALSE> 
}
The else-branch can be omitted.
SWITCH 
~~~~~~~~~~
switch <integer variable> 
{ 
case <constant1> : statements1; break; 
case <constant2> : statements2; break; 
case <constant3> : statements3; break; 
... 
default : defstatements; break; 
}
If the value of the integer variable is equal to constant1, statements1 will be executed. After execution, the case-switch will be left. Same happens equivalent for all other values-constant pairs. If the value of the integer variable isn't equal to any of the constants of the switch, the 
defstatements are executed and the switch is left.
The default case can be ommited, and no action will be taken, if an identical constant is not found. WARNING! Be careful! Tricky variation:
switch <integer variable> 
{ 
case <constant1> : statements1; 
case <constant2> : statements2; 
case <constant3> : statements3; 
... 
default : defstatements; 
}
Imagine, the variable is equal to constant2. Now, after executing statments2, statements3 and defstatements wil be executed also, because there is no "break" statement. Be careful! I have arned you!
WHILE 
~~~~~~~~~~
while( <condition> ) 
{ 
statements of the body of the loop 
}
while the condition is true, the statements of the body of the loop will be executed.
FOR 
~~~~~~~~~~
for( <initialization>; <condition>; <variation> ) 
{ 
statements of the body of the loop 
}
This <initialization> sets an counter to an appropiate value. <condition> checks for loop-end conditions. As long <condition> is true, the loop loops. The <variation> changes some aspects of <condition>, so that condition become false at a certain point of execution.
DO 
~~~~~~~~~~
do 
{ 
statements of the body of the loop 
} while( <condition> );
While the <condition> is true, the loop loops. But this loop is executed at least once. 
Step 2: Operators 
----------------------------------------------------------------------
logical operators are: 
~~~~~~~~~~ 
== equal 
!= unequal 
> greater than 
>= greater than or equal to 
< less than 
<= less than or equal to 
&& logical and 
|| logical or 
! logical not
mathematical operatores are: 
~~~~~~~~~~ 
+,-,*,/ mathematical operations, you know them 
& bitwise and 
| bitwise or 
~ bitwise not 
++<var> increment by one first, than assign value of var 
<var>++ assign value of var first, than increment by one 
--<var> same thing, but decrement by one 
<var>-- same thing, but decrement by one 
<var>+=<val> is equal to <var> = <var> + <val>
same goes for 
-=,*=,/=
<var>%<val> remainder of division of <var>/<val>
<var> >> <val> shifts bits of <var> <val> steps to the rigth 
<var> << <val> shifts bits of <var> <val> steps to the left
cast 
~~~~~~~~~~ 
(<type>)<var> convert type of <var> to type of <type>
WARNING! Use this very carefully!!!
Step 3: Basic data types 
---------------------------------------------------------------------- 
(For the valid data ranges of each type see /usr/include/limits.h
INTEGER TYPES:
int native data type of te computer system: For example, 
if your CPU has a 32 bit core, this type should be 
4 bytes long (=32 bit)
short 2 bytes 
char 1 byte (may change in the future -- see limits.h and 
remarks on the unicode character encoding scheme 
long same as int OR two time the length of int see limits.h again. 
INTEGER PREFIXES:
Each of the above integer data type can be "signed" or "unsigned" (plus or minus). Example (absolute values may vary on your system):
signed int mysigvar; /* mysigvar is able to store values between (including) -32767 and 32768
unsigned int myusigvar; /* myusigvar is able to store values between (including) 0 and 65535 
FLOAT TYPES:
float single float, simple precision 
double double float, double precision see limits.h
SPECIAL:
void no type! useful to create a function prototype with NO return value. A definition like void myuselessvar; is -- useless. 
This is the end. Nearly... ;-)
Please! Buy a good book -- my favourite is "The C Programming Language" by Brian W. Kernigham and Dennis M. Ritchie <http://www.happyhacker.org/programming.htm> -- and read it! Programming in "C" is real fun, if you have managed the first difficulties. Don't be afraid, be curious! If you want to be really elite, try to understand the compiler grammar of "C", which is printed at the last pages of the book mentioned above. Then you will discover additionally very nice things like this dirty, quicky, tricky thing:
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h>
int main( int argc, char *argv[] ) 
{
int i;
i = 3;
switch (i) 
{
while( i < 50 ) 
{ 
case 1: printf( "%s\n", "case 1" ); i++; 
case 2: printf( "%s\n", "case 2" ); i++; 
case 3: printf( "%s\n", "case 3" ); i++; 
case 4: printf( "%s\n", "case 4" ); i++; 
case 5: printf( "%s\n", "case 5" ); i++; 
} 
} 
}
What do you think, will happen here?
### 16.0 If it doesn't work... 
----------------------------------------------------------------------
I hope you won't have to enter this chapter... 
In some cases, you will have problems while compiling the example programs. This may be caused by the version of the compiler. As mentioned, there are two kinds of C compiler out there: The K&R type of compilers and the 
ANSI-compilers. All examples above are written for the ASNI-type of compilers, but don't hesitate, if you haven't one.
If you have an old K&R compiler, you have to change the following things. Change:
int main( int argc, char *argv[] )
to
main()
and remove the list of parameters from very prototype. Example:
int prototype( int foo, int bar );
becomes
int prototype(); 
A last thing you have to change also: If you define a function other than main() for an ANSI compiler, it looks like:
int gnugnats( int foo, int bar ) 
{ 
.......
}
The same function defined for a K&R-compiler, it looks like:
int gnugnats( foo, bar ) 
int foo; 
int bar; 
{ 
.......
}
Please change this also in the above examples.
After this changes, all example programs should compile -- if they are not mistyped.
Here are some common errors, you may will encounter while writing programs in C. But first a rule to follow, while removing compile errors: Start with the very first error, the compiler will print to your screen. Often one error in the start of the source code confuses the compiler that much, that he will begin to struggle and produce many, many "pseudo errors", which 
will disappear just after removing the first error. 
SYNTAX ERROR: C have you spoken correctly not. ;-) Change it to: 
You have not spoken C correctly.
More seriously: An often "used" error, is to forget a ";" at the end of a statement. In this case, the compiler cannot decide, when to stop the current statement and it "eats" too much source code. Result: Many, many, many errors, which are no errors. Especially the reported line number of the error is mostly incorrect! Search some lines before for the missing ";". Another common error is to transpose two characters, like "rpintf" instead of "printf". This is a -- exactly spoken -- also a syntax error, but the compiler produces much cryptic stuff also. If you find something like: "unknown identifier" or "unresolved reference to xyz" and the reported identifier is really unknown (it is not, what you want to type), just fix the type, and you are the winner.
TYPE MISMATCH: You have supplied a hot dog instead of an icescream.
Mostly this happens while calling a library function. Use "man" to get the documentation for that library function and check the parameters exactly. Another source of errors is the assigment of a variable to another variable of an incompatible data type.
UNRESOLVED SYMBOL, UNRESOLVED REFERENCE TO...
First check "SYNTAX ERROR" for this. If the error remains in the source code, you may have called a function, you want to write by yourself and... you haven't done so. There is only the call, not the definition of the function. Fix it ;-) If the reported unresolved symbol is the name of a library function, you have forgotten to link against the library, which have this function included. Check the manpages of that functions for a hint. Otherwise ask the tech support or the vendors documentation for your compiler. Don't forget to #include<> the corresponding header files (they will be mentioned in the manpages of the function.
### 17.0 Cc, Gcc And The Rest Of The World 
----------------------------------------------------------------------
If you have Linux, you will have gcc installed. Gcc is the GNU C- compiler, a very mighty and good ANSI (by default) compiler. "cc" should be the command name for the system's "default" compiler. Often it is a symbolic link to the "real" executable program. On Linux boxes (and many other systems) this complier is "gcc."
How do you check to see what compilers there are? If you are sure that there is a compiler at all (type "cc" and watch the output -- see the beginning of this file) try the following:
whereis cc
You will get a path to cc, something like
/usr/bin/cc
Now type
ls -l /usr/bin/cc (or whatelse the path is on your machine)
If this produces something like (filelength, filedate etc stripped)
/usr/bin/cc -> gcc (again, the path may differ)
you have found the "real thing": cc is equal to gcc. But if there is 
something like
/usr/bin/cc
there is a "chance", that is a different compiler installed -- may be it is installed "additionally"...Type
gcc
and if there is something like
gcc: command not found
There is no gcc installed (or the PATH variable is set wrongly. Ask tech support (see this file just after the execution of our first "HelloHacker" program for more). <http://www.happyhacker.org/archives/cprogram2.htm>
For the first time use always "cc" as the command. If you are sure, that gcc is installed, use "gcc" instead. You can switch gcc to recognize both versions, K&R and ANSI, by giving an additional option to the command "gcc":
gcc -ansi
or often only
gcc
will use the ANSI-standard, but using the command
gcc -traditional
will use the old K&R version.
By default, gcc translates ANSI-type source code.
"C" you!
KEEP HACKING! 
meino 
