Advertise

Monday 16 September 2013

C Programming Part 2 - Constructs, Variable, Declaration & Constants

C Programming Language Primer 2 - Constructs, Variable, Declaration & Constants


C contains a number of looping constructs, such as the "while" loop:

PHP Code:
/* while.c */

   #include 

   
void main()
   {
     
int test 10;
     while( 
test )
     {
       
printf"test = %d\n"test );
       
test test 2;
     }
   } 

If "test" starts with an initial value less than or equal to 0 the "while" loop will not execute even once. There is a variant, "do", that will always execute at least once:

PHP Code:
/* do.c */

   #include 

   
void main()
   {
     
int test 10;
     do
     {
       
printf"test = %d\n"test );
       
test test 2;
     }
     while( 
test );
   } 
The most common looping construct is the "for" loop, which creates a loop much like the "while" loop but in a more compact form:

PHP Code:
/* for.c */

   #include 
  
   
void main()
   {
     
int test;
     for( 
test 10test 0test test )
     {
       
printf"test = %d\n"test );
     }
   } 

Notice that with all these loops, the initial loop statement does not end with a ";". If a ";" was placed at the end of the "for" statement above, the "for" statement would execute to completion, but not run any of the statements in the body of the loop.


The "for" loop has the syntax:

PHP Code:
for( <initialization>; <operating test>; <modifying expression> ) 

All the elements in parentheses are optional. A "for" loop could be run indefinitely with:

PHP Code:
for( ; ; )
   {
     ...
   } 

-- although using an indefinite "while" is cleaner:

PHP Code:
while( )
   {
     ...
   } 

It is possible to use multiple expressions in either the initialization or the modifying expression with the "," operator:


PHP Code:
/* formax.c */

   #include 

   
void main()
   {
     
int ab;
     for ( 
2561512 2)
     {
       
printf"a = %d  b = %d\n"a);
     }
   } 

The conditional tests available to C are as follows:

PHP Code:
== b    equals                      
   a 
!= b    not equals
   a 
b     less than                   
   a 
b     greater than
   a 
<= b    less than or equals         
   a 
>= b    greater than or equals 

The fact that "==" is used to perform the "equals" test, while "=" is used as the assignment operator, often causes confusion and is a common bug in C programming:

PHP Code:
== b    Is "a" equal to "b"?
   
b     Assign value of "b" to "a"

C also contains decision-making statements, such as "if":

PHP Code:
/* if.c */

   #include 
   #define MISSILE 1

   
void fireint weapon );

   
void main()
   {
     
fireMISSILE );
   }

   
void fireint weapon )
   {
     if( 
weapon == MISSILE )
     {
       
printf"Fired missile!\n" );
     }
     if( 
weapon != MISSILE )
     {
       
printf"Unknown weapon!\n");
     }
   } 

This example can be more easily implemented using an "else" clause:

PHP Code:
/* ifelse.c */

   
void fireint weapon )
   {
     if( 
weapon == MISSILE )
     {
       
printf"Fired missile!\n" );
     }
     else
     {
       
printf"Unknown weapon!\n");
     }
   } 

Since there is only one statement in each clause the curly brackets aren't really necessary. This example would work just as well:

PHP Code:
void fireint weapon )
   {
     if( 
weapon == MISSILE )
       
printf"Fired missile!\n" );
     else
       
printf"Unknown weapon!\n" );
   } 

However, the brackets make the structure more obvious and prevent errors if you add statements to the conditional clauses. The compiler doesn't care one way or another, it generates the same code.

There is no "elseif" keyword, but "if" statements can be nested:

PHP Code:
/* nestif.c */

   #include 
   #define MISSILE 1
   #define LASER 2

   
void fireint weapon )

   
void main()
   {
     
fireLASER );
   }

   
void fireint weapon )
   {
     if( 
weapon == MISSILE )
     {
       
printf"Fired missile!\n" );
     }
     else
     {
       if( 
weapon == LASER )
       {
         
printf"Fired laser!\n" );
       }
       else
       {
         
printf"Unknown weapon!\n");
       }
     }
   } 

This is somewhat clumsy. The "switch" statement does a cleaner job:

PHP Code:
/* switch.c */

   
void fireint weapon )
   {
     switch( 
weapon )
     {
     case 
MISSILE:
       
printf"Fired missile!\n" );
       break;
     case 
LASER:
       
printf"Fired laser!\n" );
       break;
     default:
       
printf"Unknown weapon!\n");
       break;
     }
   } 

The "switch" statement tests the value of a single variable; unlike the "if" statement, it can't test multiple variables. The optional "default" clause is used to handle conditions not covered by the other cases.

Each clause ends in a "break", which causes execution to break out of the "switch". Leaving out a "break" can be another subtle error in a C program, since if it isn't there, execution flows right through to the next clause. However, this can be used to advantage. Suppose in our example the routine can also be asked to fire a ROCKET, which is the same as a MISSILE:

PHP Code:
void fireint weapon )
   {
     switch( 
weapon )
     {
     case 
ROCKET:
     case 
MISSILE:
       
printf"Fired missile!\n" );
       break;
     case 
LASER:
       
printf"Fired laser!\n" );
       break;
     default:
       
printf"Unknown weapon!\n");
       break;
     }
   } 

The "break" statement is not specific to "switch" statements. It can be used to break out of other control structures, though good program design tends to avoid such improvisations:

PHP Code:
/* break.c */

   #include 

   
void main()
   {
     
int n;
     for( 
010)
     {
       if( 
== )
       {
         break;  
/* Punch out of loop at value 5. */
       
}
       else
       {
         
printf"%d\n");
       }
     }
   } 

If the "for" loop were nested inside a "while" loop, a "break" out of the

"for" loop would still leave you stuck in the "while" loop. The "break" keyword only applies to the control construct that executes it.

There is also a "continue" statement that skips to the end of the loop body and continues with the next iteration of the loop. For example:

PHP Code:
/* continue.c */

   #include 

   
void main()
   {
     
int n;
     for( 
010)
     {
       if( 
== )
       {
         continue;
       }
       else
       {
         
printf"%d\n");
       }
     }
   } 

Finally, there is a "goto" statement:

PHP Code:
goto punchout;
   ...
   
punchout

-- that jumps to an arbitrary tag within a function, but the use of this statement is generally discouraged and it is rarely seen in practice.


While these are the lot of C's true control structures, there is also a special "conditional operator" that performs a simple conditional assignment of the form:

PHP Code:
if( == 5)
   {
     
= -10;
   }
   else
   {
     
255;
   } 

-- using a much tidier, if more cryptic, format:

PHP Code:
= ( == ) ? -10 255 

the ?: construct is called a ternary operator -- or the ternary operator -- as it takes 3 arguments.

C Variables, Declarations and Constants


C supports a flexible set of variable types and structures, as well as common arithmetic and math functions along with a few interesting operators that are unique to C. This chapter explains them in detail, and ends with a short discussion of preprocessor commands.

C includes the following fundamental data types:-

[Image: BMD9sHG.png]

These are representative values. The definitions tend to vary between implementations. For example, in some systems an "int" is 16 bits, and a "long double" could be 64 bits. The only thing that is guaranteed is the precedence:

PHP Code:
short <= int <= long
   float 
<= double <= long double 


One peculiarity of C that can lead to maddening problems is that while there is an "unsigned char" data type, for some reason many functions that deal with individual characters require variables to be declared "int" or "unsigned int".

Declarations are of the form:

PHP Code:
int myvaltmp1tmp2;
   
unsigned int marker1 1marker2 10;
   
float magnitudephase

Variable names can be at least 31 characters long, though modern compilers will always support longer names. Variables names can be made up of letters, digits, and the "_" (underscore) character; the first character must be a letter. While it is possible to use uppercase letters in variable names, conventional C usage reserves uppercase for constant names. A leading "_" is also legal, but is generally reserved for marking internal library names.

C allows several variables to be declared in the same statement, with commas separating the declarations. The variables can be initialized when declared. Constant values for declarations can be declared in various formats:

PHP Code:
128        decimal int
   256u       decimal unsigned int
   512l       decimal long int
   0xAF       hex int
   0173       octal int
   0.243      float
   0.1732f    float
   15.75E2    float
   
'a'        character
   
"giday"    string 

There are a number of special characters defined in C:

PHP Code:
'\a'     alarm (beepcharacter
   
'\p'     backspace
   
'\f'     formfeed
   
'\n'     newline
   
'\r'     carriage return
   
'\t'     horizontal tab
   
'\v'     vertical tab
   
'\\'     backslash
   
'\?'     question mark
   
'\''     single quote
   
'\"'     double quote
   
'\0NN'   character code in octal
   
'\xNN'   character code in hex
   
'\0'     null character 

"Symbolic constants" can be specified using the "define" C preprocessor declaration:

PHP Code:
#define PI 3.141592654 

There is also a "const" declaration that defines a read-only variable, such as a memory location in ROM:

const int a;

Arrays can be declared and initialized:

PHP Code:
int myarray[10];
   
unsigned int list[5] = { 1015121923 };
   
float rdata[128], grid[5][5]; 

All C arrays have a starting index of 0, so "list" has the indexes 0 through 4. Elements in "rdata" would be accessed as follows:

PHP Code:
for( 0<= 127)
   {
      
printf "\f\n"rdata[i] );
   } 

C does not perform rigorous bounds checking on array access. It is easy to overrun the bounds of the array, and the only symptom will be that the program acts very strangely.

Of particular importance are arrays of characters, which are used to store

strings:

PHP Code:
char s[128];
   
strcpys"This is a test!"); 

The string "This is a test!" is used to initialize "s" through the "strcpy()" function, discussed in a later chapter. The stored string will contain a terminating "null" character (the character with ASCII code 0, represented by '\0'). The null is used by C functions that manipulate strings to determine where the end of the string is, and it is important to remember the null is there.

The curious reader may wonder why the "strcpy()" function is needed to initialize the string. It might seem to be easier to do:

PHP Code:
char s[128] = "This is a test!"

In fact, this is an absurd operation, but to explain why, the concept of "pointers" must be introduced.

C programs can define pointers that contain the address of a variable or

an array. For example, a pointer could be defined named:

PHP Code:
int *ptr

-- that gives the address of a variable, rather than the variable itself. A value could then be put into that location with the statement:

PHP Code:
*ptr 345

In an inverse fashion, the address of a variable can be obtained with "&":

PHP Code:
int tmp;
   
somefunc( &tmp ); 

To sum up:
  1. A pointer is declared in the form: "*myptr".
  2. If "myvar" is a variable, then "&myvar" is a pointer to that variable.
  3. If "myptr" is a pointer, then "*myptr" gives the variable data for that pointer.


Pointers are useful because they allow a function to return a value through a parameter variable. Otherwise, the function will simply get the data the variable contains and have no access to the variable itself.

One peculiar aspect of C is that the name of an array actually specifies a pointer to the first element in the array. For example, given the string declaration:

PHP Code:
char s[256]; 

-- then the function call:

PHP Code:
somefunc

-- will actually pass the address of the character array to the function, and the function will be able to modify it. However:

PHP Code:
s[12


-- gives the value in the array value with index 12. Remember that this is the 13th element, since indexes always start at 0.

There are more peculiarities to strings in C. Another interesting point is that a string literal actually evaluates to a pointer to the string it defines. This means that in the following operation:

PHP Code:
char *p;
   
"Life, the Universe, & Everything!"

-- "p" ends up being a pointer to the memory in which the C compiler stored the string literal, and "p[0]" would evaluate to "L". In a similar sense, the following operation:

PHP Code:
char ch;
   
ch "Life, the Universe, & Everything!"[0]; 

-- would put the character "L" into the variable "ch".

This is very well and good, but why care? The reason to care is because this explains why the operation:


PHP Code:
char s[128] = "This is a test!"

-- is absurd. This statement tells the C compiler to reserve 128 bytes of memory and set a pointer named "s" to point to them. Then it reserves another block of memory to store "This is a test!" and points "s" to that. This means the block of 128 bytes of memory that were originally allocated is now sitting empty and unusable, and the program is actually accessing the memory that stores "This is a test!".

This will seem to work for a while, until the program tries to store more bytes into that block than can fit into the 16 bytes reserved for "This is a test!". Since C is poor about bounds checking, this may cause all kinds of trouble.

This is why "strcpy()" is usually necessary. It isn't needed for a string that won't modified or will not be used to store more data than it is initialized to, and under such circumstances the following statements will work fine:

PHP Code:
char *p;
   
"Life, the Universe, & Everything! "

These issues become particularly tricky when passing strings as parameters to functions. The following example shows how to get around the pitfalls:

PHP Code:
/* strparm.c */

   #include 
   #include 

   
char *strtestchar *achar *);
  
   
int main ()
   {
     
char a[256],
          
b[256],
          
c[256];

     
strcpya"STRING A: ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" );
     
strcpyb"STRING B: ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" );
     
strcpyc"STRING C: ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" );

     
printf"Initial values of strings:\n" );
     
printf"\n" );
     
printf"   a = %s\n");
     
printf"   b = %s\n");
     
printf"   c = %s\n");
     
printf"\n" );

     
strcpycstrtesta));
  
     
printf"Final values of strings:\n" );
     
printf"\n" );
     
printf"   a = %s\n");
     
printf"   b = %s\n");
     
printf"   c = %s\n");
     
printf"\n" );
    
     return 
0;
   }
  
   
char *strtestchar *xchar *)
   {
     
printf"Values passed to function:\n" );
     
printf"\n" );
     
printf"   x = %s\n");
     
printf"   y = %s\n");
     
printf"\n" );
  
     
strcpyy"NEWSTRING B: abcdefghijklmnopqrstuvwxyz0123456789" );
     return 
"NEWSTRING C: abcdefghijklmnopqrstuvwxyz0123456789";
   } 


It is possible to define "structures" in C, which are collections of different data elements:

PHP Code:
/* struct.c */

   #include 
   #include 
  
   
struct person                              /* Define structure type. */
   
{
      
char name[50];
      
int age;
      
float wage;
   };
  
   
void displaystruct person );
  
   
int main()
   {
     
struct person m;                         /* Declare an instance of it. */
     
strcpym.name"Coyote, Wile E." );     /* Initialize it. */
     
m.age 41;
     
m.wage 25.50f;
     
display);
     return 
0;
   }
  
   
void displaystruct person p )
   {
     
printf"Name: %s\n"p.name );
     
printf"Age:  %d\n"p.age );
     
printf"Wage: %4.2f\n"p.wage );
   } 


This program has a few interesting features:
  • The structure has to be defined by a "struct" declaration before it can declare any structures themselves. In this case we define a struct of type "person".
  • Instances of the struct ("m") are then declared as by defining the structure type ("struct person").
  • Elements of the structure are accessed with a "dot" notation ("m.name", "m.age", and "m.wage").
A structure can be copied to another structure with a single assignment statement, as long as the structures are of the same type:

PHP Code:
struct person mn;
   ...
   
n


It is also possible to declare arrays of structures:

PHP Code:
struct person group[10];
   ...
   
strcpygroup[5].name"McQuack, Launchpad" ); 

-- or even embed structures inside structure declarations:

PHP Code:
struct trip_rec
   
{
      
struct person traveler;
      
char dest[50];
      
int date[3];
      
int duration;
      
float cost;
   } 

-- in which case the nested structure would be accessed as follows:

PHP Code:
struct trip_rec t1;
   ...
   
strcpyt1.traveler.name"Martian, Marvin" ); 


The name of a structure defines a variable, not an address. If the name of a structure is passed to a function, the function works only on its local copy of the structure. To return values, an address must be specified:

PHP Code:
setstruct( &mystruct ); 

There is a shorthand way to get at the elements of a structure with the pointer to the structure instead of the structure itself. If "sptr" is a pointer to a structure of type "person", its fields can be accessed as follows:

PHP Code:
strcpysptr->name"Leghorn, Foghorn" );
   
sptr->age 50;
   
sptr->wage 12.98


C contains a concept similar to a structure known as a "union". A union is declared in much the same way as a structure. For example:

PHP Code:
union usample
   
{
     
char ch;
     
int x;
   } 

The difference is that the union can store either of these values, but not both at the same time. A "char" value or an "int" value can be stored in an instance of the union defined above, but it's not possible to store both at the same time. Only enough memory is allocated for the union to store the value of the biggest declared item in it, and that same memory is used to store data for all the declared items. Unions are not often used and will not be discussed further.

The following example program shows a practical use of structures. It tests a set of functions that perform operations on three-dimensional vectors:

PHP Code:
vadd():     Add two vectors.
   
vsub():     Subtract two vectors.
   
vdot():     Vector dot product.
   
vcross():   Vector cross product.
   
vnorm():    Norm (magnitudeof vector.
   
vangle():   Angle between two vectors.
   
vprint():   Print out vector

The program follows:

PHP Code:
/* vector.c */

   #include 
   #include 
  
   #define PI 3.141592654
  
   
struct v
   
{
      
double ijk;
   };
  
   
void vaddstruct vstruct vstruct v* );
   
void vprintstruct v );
   
void vsubstruct vstruct vstruct v* );
   
double vnormstruct v );
   
double vdotstruct vstruct v );
   
double vanglestruct vstruct v );
   
void vcrossstruct vstruct vstruct v* );
  
   
int main()
   {
     
struct v v1 = { 12}, v2 = { 3050100 }, v3;
     
double a;
  
     
printf"Sample Vector 1: " );
     
vprintv1 );
     
printf"Sample Vector 2: " );
     
vprintv2 );
  
     
vaddv1v2, &v3 );
     
printf"Vector Add:      " );
     
vprintv3 );
  
     
vsubv1v2, &v3 );
     
printf"Vector Subtract: " );
     
vprintv3 );
  
     
vcrossv1v2, &v3 );
     
printf"Cross Product:   " );
     
vprintv3 );
  
     
printf"\n" );
     
printf"Vector 1 Norm:  %f\n"vnormv1 ) );
     
printf"Vector 2 Norm:  %f\n"vnormv2 ) );
     
printf"Dot Product:    %f\n"vdotv1v2 ) );
     
180 vanglev1v2) / PI ;
     
printf"Angle:          %3f degrees.\n");
  
     return 
0;
   }
  
   
void vaddstruct v astruct v bstruct v *)  /* Add vectors. */
   
{
     
c->a.b.i;
     
c->a.b.j;
     
c->a.b.k;
   }
  
   
double vanglestruct v astruct v b )  /* Get angle between vectors. */
   
{
     
double c;
     
vdota) / ( vnorm) * vnorm) );
     return 
acos);
   }
  
   
void vcrossstruct v astruct v bstruct v *)  /* Cross product. */
   
{
     
c->a.b.a.b.j;
     
c->a.b.a.b.k;
     
c->a.b.a.b.i;
   }
  
   
double vdotstruct v astruct v b /* Dot product of vectors. */
   
{
     return 
a.b.a.b.a.b.k;
   }
  
   
double vnorm struct v a )  /* Norm of vectors. */
   
{
     return 
sqrta.a.a.a.a.a.);
   }
  
   
void vprint struct v a )  /* Print vector. */
   
{
     
printf" I = %6.2f   J = %6.2f   K = %6.2f\n"a.ia.ja.);
   }
  
   
void vsub struct v astruct v bstruct v *)  /* Subtract vectors. */
   
{
     
c->a.b.i;
     
c->a.b.j;
     
c->a.b.k;
   } 


The concept of local and global variables should be clear by now. It is also possible to declare a local variable as "static", meaning it retains its value from one invocation of the function to the next. For example:

PHP Code:
#include 

   
void testfuncvoid );

   
int main()
   {
     
int ctr;
     for( 
ctr 1ctr <= 8; ++ctr )
     {
       
testfunc();
     }
     return 
0;
   }
  
   
void testfuncvoid )
   {
     static 
int v;
     
printf"%d\n"2*);
     ++
v;
   } 

This prints:

Code:
0
   2
   4
   6
   8
   10
   12
   14

-- since the initial value of a integer is 0 by default. It is not a good idea to rely on a default value!

There are two other variable declarations that should be recognized, though

there's little reason to use them: "register", which declares that a variable should be assigned to a CPU register, and "volatile", which tells the compiler that the contents of the variable may change spontaneously.

There is more and less than meets the eye to these declarations. The "register" declaration is discretionary: the variable will be loaded into a CPU register if it can, and if not it will be loaded into memory as normal. Since a good optimizing compiler will try to make the best use of CPU registers anyway, this is not in general all that useful a thing to do.

The "volatile" declaration appears ridiculous at first sight, something like one of those "joke" computer commands like "halt and catch fire". Actually, it's used to describe a hardware register that can change independently of program operation, such as the register for a realtime clock.

C is fairly flexible in conversions between data types. In many cases, the

type conversion will happen transparently. If a "char" is converted to a "short" data type, or an "int" is converted to a "long" data type, for example, the converted data type can easily accommodate any value in the original data type.

Converting from a bigger to a smaller data type can lead to odd errors. The same is true for conversions between signed and unsigned data types. For this reason, type conversions should be handled carefully, and it is usually preferable to do them explicitly, using a "cast" operation. For example, a cast conversion can be performed from an "int" value to a "float" value as follows:

PHP Code:
int a;
   
float b;
   ...
   
= (float)a

It is possible to define custom "enumerated" types in C. For example:

PHP Code:
enum day
  
{
     
saturdaysundaymondaytuesdaywednesdaythursdayfriday
  
}; 

-- defines enumerated type "day" to consist of the values of the days of the week. In practice, the values are merely text constants associated to a set of consecutive integer values. By default, the set begins at 0 and counts up, so here "saturday" has the value 0, "sunday" has the value 1, and so on. Any set of number assignments can be specified if desired:

PHP Code:
enum temps
   
{
     
zero 0freeze 32boil 220
   
}; 


Obviously much the same could be done with sets of "#define" directives, but this is a much cleaner solution. Once the type is defined, for example, variables of that type can be declared as follows:

PHP Code:
enum day today wednesday

The variable "today" will act as an "int" variable and will allow the operations valid for "int" variables. Once more, remember that C doesn't do much in the way of bounds checking, and it is not wise to rely on the C compiler to give warnings.

Finally, a "typedef" declaration can be used to define custom data types:

PHP Code:
typedef str ch[128]; 

Then variables of this type could be declared as follows:

PHP Code:
str name
 
World of Hacker © 2011 Creative Commons License
World of Hacker by KroKite is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
Based on a work at http://www.worldofhacker.com.
Permissions beyond the scope of this license may be available at https://groups.google.com/forum/#!newtopic/hackerforum.