7 AssignmentsTop5 Operator Precedence and Associativity6 Notes

6 Notes

6.1 Getting Started 1

6.2 Code Generation

6.3 Preprocessor -- 1

6.4 "C" Language Constructs -- 1

6.5 "C" Language Constructs -- 2

6.6 Constants

6.7 function printf() -- 1

6.8 Operators -- 2 Bitwise

& Bitwise AND
| Bitwise OR
^ Bitwise XOR
<< Left shift
>> Right Shift
~ one's complement (unary)

6.9 Character Functions -- 1

getc(FILE *fp) Read a char from *fp
getchar() #define getchar() getc(stdin)
ungetc(FILE *fp) Returns one char to *fp
ungetchar() Returns one char to stdin
putc(int c, FILE *fp) "Prints" one char to *fp
putchar(int c) #define putchar(c) putc(c,stdin)

6.10 Declarations & Initialization

 

6.11 Arrays

6.12 "C" Language Constructs -- 3

6.13 Assignment Operators

 
+= Addition
-= Subtraction
*= Multiply
/= Divide
%= Remainder/mod
&= Bitwise AND
^= Bitwise XOR
|= Bitwise OR
<<= Left shift
>>= Right Shift

6.14 Logical Expression Operators

 

Logical expression evaluation will stop as soon as the final outcome is known (ANSI "C" Standard 9899 6.5). The order of the expression evaluation is indeterminate -- most of the time.

Except as specified later (For the function call ( ), &&, ||, ?: and the comma operators), the order of evaluation of subexpressions and the order in which side effects take place are both unspecified.

ANSI "C" Standard 9899 6.5.2.3 p72 paragraph 10

The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.

True is indicated by non-zero. False by zero. ANSI "C" Standard 9899 p6.5.3.3 re: ! operator will return a one(1) for a true condition.

&& Logical AND
|| Logical OR
! Logical NOT

6.15 Comma Operator

  Kernighan p62.

6.16 Declarations - 2

6.17 Functions

6.18 "C" Language Constructs - 4

  return expressionopt;

6.19 Pointers - 1

An example program that:

  1. uses pointers to return values from a function,

/* Program to look at pointers                 */ 
/* L Taber   Feb 17, 2001   PCC                */

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

                      /* returns three results */
int sumANDswap(int *a, int *b);
int printab(int x, int y, char *string);

int a = 1;            /* external variable     */
                      /* initilized only once  */
int *ptr;

int main() 
{
int b;                /* auto variable         */
int sum;              /* for return value      */

ptr = malloc( sizeof a );
*ptr = 42;
b=5+a;

printab(a, b,    "a & b    ");
sum = sumANDswap(&a, &b);
printab(a, b,    "a & b    ");
printf("sum= %d\n\n", sum);

printab(b, *ptr, "b & *ptr ");
sum = sumANDswap(&b, ptr);
printab(b, *ptr, "b & *ptr ");
printf("sum= %d\n", sum);
}

                        /* returns three results */
int sumANDswap(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
return( *a + *b );
}

   /* strings are really character pointers ! */
int printab(int x, int y, char *string)
{
return printf(" %s %d   %d\n", string, x, y);
}

This program is available by HTTP at:
http://lt.tucson.az.us/ltaber/hl2.2009-spring/c/prt1.c.

The anotated output on my system looked like this:

 a & b     1   6
 a & b     6   1
sum= 7

 b & *ptr  1   42
 b & *ptr  42   1
sum= 43

I am using gcc version 2.95.2 20000220 (Debian GNU/Linux).

  1. Note the memory layout. Executable code, global/static variables, the heap, and then the stack.
  2. The heap is just after the global/static variables.
  3. The addresse of main() does not change.
  4. The addresse of a does not change.
  5. A second copy of b is placed on the stack at a lower address.
  6. A second set of storage is set aside for the second int on the malloc-ed. The heap is grows toward the stack.

6.20 Code Layout

 

You may want to look at Linux Torvalds coding standards for the kernel. I have converted them to HTML.

6.21 Files

6.21.1 stdlib I/O functions

#include <stdio.h>

6.21.2 stdlib error functions

#include <stdio.h>
#include <errno.h>
#include <string.h>

6.21.3 Unix I/O functions

(Avoid these functions for portability)

6.21.4 I/O function Examples

 

File access examples. http://lt.tucson.az.us/ltaber/hl2.2009-spring/c/file-or-stdin.c

/* Louis Taber, 3/18/2001
 * 
 * --  Use stdin or file name on command line. 
 *
 * copy stdin to stdout if no file name is specified 
 *
 *  else opern file and send to stdout */ 

#include <stdio.h>

void filecopy(FILE *, FILE *);

int main(int argc, char *argv[])
{
FILE *fp;

if( argc == 1 )   /* No arguments -- use std input */
  {
  filecopy(stdin, stdout);
  }
else
  {
  if((fp = fopen( argv[1], "r")) == NULL)
    {
    printf("%s(line %d): can't open: %s\n", 
           __FILE__, __LINE__,  argv[1]);
    return 1;
    }
  else
    {
    filecopy(fp, stdout);
    fclose(fp);
    }
  }
return 0;
}

/* filecopy:  copy file ifp to file ofp */

void filecopy(FILE *ifp, FILE *ofp)
{
int c;

while(( c= getc(ifp)) != EOF) putc(c, ofp);
}

Program to read the roads for the route lab. http://lt.tucson.az.us/ltaber/hl2.2009-spring/c/read-roads.c

/* Louis Taber 3/18/2001
 *
 * --  Read roads 
 *
 * Example program for fscanf()
 *
 *                               */

#include <stdio.h>

int main(void)
{
FILE *fp;
int zip1, zip2, miles;
char comment[200];

if((fp = fopen( "route.dat", "r")) == NULL)
  {
  printf("%s(line %d): can't open: route.dat\n", 
         __FILE__, __LINE__);
  return 1;
  }
else
  {
  do
    {
    if( fscanf( fp, "%d %d %d %s\n", 
                    &zip1, &zip2, &miles, comment) <0 ) break;
    printf("From zip %05d to  zip %05d is %5d miles  (%s) \n", 
           zip1, zip2, miles, comment);
    }  while( zip1 != 0 );
  fclose(fp);
  }
return 0;
}

6.22 Input conversion

  Kernighan p157. Hanly & Koffman pages 35, 51-53, 88, and 464.
scanf Reads from standard input
sscanf Reads from string
fscanf Reads from file

6.23 Output conversion #2

Kernighan p161. Hanly & Koffman pages 48-50 and pages 612-615.

6.24 Other routines

#include <ctype.h>
Kernighan p161, p249. Hanly & Koffman pages 466 & Appendix B pages 844-845.

6.25 Conversion Functions

,  

  #include <ctype.h>
#include <stdlib.h>
Kernighan p249, p251. Hanly & Koffman page Appendix B page 841..

6.26 Recursion

Some problems, (not many,) lend themselves to a recursive solution. Expression evaluation is a good example of a good application of recursion.

You may want to look at Hanly & Koffman Chapter 10 Recursion on page 501..

The following program is recursive implementation of the Fibonacci series, (1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...). In the series (except for the first two numbers) each number is the sum of the previous two.

The program source is available at:
http://lt.tucson.az.us/ltaber/hl2.2009-spring/c/recursion.c

 
/* Louis Taber   PCC  April 8, 2001
 *
 * Recursion example                          */

int fib(int d)  /* Fibonacci series           */
{               /* First two numbers are 1    */
if( d <= 2 ) return 1;
                /* The rest are the sum of    */
                /* the previous two in series */  
else return fib(d-1) + fib(d-2);
}

main()          /* Call Fibonacci series      */
{               /* function fib with values   */
int i;          /* from 1 to 12               */
for( i=1; i<13; i++)
   printf("fib(%2i)=%3d   %c", 
                 i, fib(i), i%3 ? ' ' : '\n' );
return 0;
}

And the output:

fib( 1)=  1    fib( 2)=  1    fib( 3)=  2   
fib( 4)=  3    fib( 5)=  5    fib( 6)=  8   
fib( 7)= 13    fib( 8)= 21    fib( 9)= 34   
fib(10)= 55    fib(11)= 89    fib(12)=144   

6.27 Function pointers

It is some times desirable to be able to pass the address of a function to another part of a program. This can be useful in sorts. It can also be required for certain calls to the operating system for error handling and signals.

The example is about as simple as it can get. There are two different functions, one twice, doubles a number, and half, divides a number by two. They are called alternately. The address of the function called is also printed.

The program:


/* Program to look at function pointers       */ 
/* L Taber   April 8, 2001   PCC              */

#include <stdio.h> 

int twice(int x)
  { return x*2; }  /* double number           */
int half(int x)
  { return x/2; }  /* divide number by 2      */

int main() 
{
int i;
int (*function)(int);

for( i=0; i<10; i++)
  {           /* If i is odd, function = twice    */
  if( i&1 ) function = &twice; 
  else      function = &half;
              /* call function and print results  */
              /* Print address of function in [ ] */
  printf(" f[%p](%i) = %d %c",
            function, i,  function(i), i&1 ? '\n' : ' ' );

  }
}

The source is available at:
http://lt.tucson.az.us/ltaber/hl2.2009-spring/c/function-ptr.c

And the output:

 f[0x80483f4](0) = 0   f[0x80483e0](1) = 2 
 f[0x80483f4](2) = 1   f[0x80483e0](3) = 6 
 f[0x80483f4](4) = 2   f[0x80483e0](5) = 10 
 f[0x80483f4](6) = 3   f[0x80483e0](7) = 14 
 f[0x80483f4](8) = 4   f[0x80483e0](9) = 18 

6.28 String Functions

 

C standard library string function assume that the string is null terminated.

#include <string.h>
strcpy Copy a string to another location
strncpy Copy a limited string to another location
strcat Concatenate strings
strncat Concatenate a limited string to another
strcmp compares two strings
strncmp compares two strings up to a limit
strchr Find the first specific character in a string
strrchr Find the last specific character in a string
strlen Find length of string

Other string functions: strspn, strcspn, strpbrk, strstr, and strtok.

There is also a set of functions for wide characters.

6.29 Structures

Structures are a way of keeping related data together.

General form of a structure:

struct structure-name
 {
 field-type field-name
 field-type field-name
 field-type field-name
 ...
 } variable-name;

This program uses structures

The program: The source is available at:
http://lt.tucson.az.us/ltaber/hl2.2009-spring/c/struct.c

/* Louis Taber    April 9, 2001
 *
 * Sample program for structures     */

#include <stdio.h>
#include <math.h>
        /* structure has a integer and a float */
struct twoitems
  {
  int a;
  float b;
  };
        /* Subroutine swaps values */
        /* doing type conversions  */
void swap(struct twoitems *subptr)
{
int temp;

temp = subptr->a;
subptr->a = (int)subptr->b;
subptr->b = (float)temp;
return;
}


main()
{       /* define x & y  using twoitems   */
        /* declaration                    */
 
struct twoitems x, y;
struct twoitems *ptr;
        /* initilize using dot syntax     */
x.a = 42;
x.b = 8.4;
        /* Place values in y using x      */
y.a = (int)x.b + 1;
y.b = (int)sqrt((double)y.a);
        /* Print out structure y          */
printf("y:       %3d  %f\n", y.a, y.b);

        /* Allocate space for new structure */
ptr = (struct twoitems *)malloc( sizeof(struct twoitems) );
        /* Copy all of x into allocated space  */
*ptr = x;
        /* print copy pointed to by ptr        */
printf("copy:    %3d  %f\n", ptr->a, ptr->b);
        /* Call subroutine to swap elements    */
swap(ptr);
        /* print results of swap               */
printf("swapped: %3d  %f\n", ptr->a, ptr->b);

return 0;
}


And the output:

y:         9  3.000000
copy:     42  8.400000
swapped:   8  42.000000

6.30 Linked lists

This program inputs "tokens" from the standard input and places them on a linked list keeping track of usage The source is available at:
http://lt.tucson.az.us/ltaber/hl2.2009-spring/c/link.c

/* Louis Taber   April 15, 2001     */
/*                                  */
/* Linked list program #1           */

#include <stdio.h>
#define TRUE 1

struct token
  {
  struct token *next; /* link to next item           */
  char *value;        /* link to storage for string  */
  int usecount;       /* number of times encountered */
  };

struct token * insert(char * string);
int link_count = 0;   /* count of links used  */
int item_count = 0;   /* count of items       */
 
main()
{
int i;			/* loop counter      */
char string[200];       /* max string size   */
struct token *current; 
struct token *start;
struct token *working;

start = NULL;

while( TRUE )          /* Until EOF          */ 
  {                    /* get a string       */
  if( fscanf( stdin, "%s", string ) == EOF ) break;
  if( start == NULL )
    {
    start = insert( string );
    continue;
    }
  current = start;
  while( TRUE )
    { 
    if( strcmp( string, current->value ) == 0 )
      {              /* found existing item   */
      current->usecount++;
      break;
      }
    if( current->next == NULL )  /* if end of list */
      {
      current->next = insert( string );
      break;
      }
    else 
      {              /* get next item on list */
      current = current->next;
      link_count++;
      }
    }
  }

current = start; /* print out items */
while( TRUE )
  {
  if( current == NULL ) break;
  item_count ++;
  if( current->usecount > 3 )
    printf("use:%4d --  %s\n", 
            current->usecount, current->value);
  current = current->next;    
  }
printf("\nItem count: %4d  Link count: %4d\n", 
          item_count,      link_count);
}


     /* routine to insert string at end of linked list. */
struct token * insert(char * string)
{
int str_length;
struct token * token_ptr;


     /* allocate space for structure */
token_ptr = (struct token*) malloc( sizeof( struct token ));
if( token_ptr == NULL )
  {
  printf("malloc 1 failed\n");
  exit();
  }
    /* get string length and allocate space */
str_length = strlen( string ) + 1;
    /* set initial use count */
token_ptr->usecount = 1;
    /* clear next pointer */
token_ptr->next = NULL;

    /* copy string to heap */
token_ptr->value = (char *) malloc( str_length );
if( token_ptr->value == NULL )
  {
  printf("malloc 2 failed\n");
  exit();
  }

strcpy( token_ptr->value, string );

   /* return pointer to new structure */
return token_ptr; 
}


And the edited output:


use:  13 --  things
use: 674 --  will
use:1825 --  a
use:2588 --  to
use:   7 --  Visual
use:   7 --  Cybervision

Item count: 12191  Link count: 156262111
 

This program is a modification of the prior program that uses multiple linked lists and a hashing algorithm to reduce search time. The source is available at:
http://lt.tucson.az.us/ltaber/hl2.2009-spring/c/link-hash.c

/* Louis Taber   April 16, 2001     */
/*                                  */
/* Linked list program #2           */

#include <stdio.h>
#define TRUE 1

    /* Number of linked lists */
#define MASKBITS 8
#define HASHMAX ( 1 << MASKBITS )
#define MAXMASK ( HASHMAX - 1 )

/* When run on a text file with 565839 bytes   */
/* ( ../linux/Documentation/Configure.help)    */
/* with different values of MASKBITS           */
/* This was done with an AMD K6-2 500Mhz with  */
/* 128 Mbytes running Linux                    */

/* MASKBITS   HASHMAX   U Time   Link Count    */
/*        0         1    23.42    156262111    */
/*        1         2    14.78     78120792    */
/*        4        16     2.26      9750485    */
/*        5        32     1.35      4865690    */
/*        8       256      .42       602588    */
/*       12      4096      .33        32669    */

struct token
  {
  struct token *next; /* link to next item           */
  char *value;        /* link to storage for string  */
  int usecount;       /* number of times encountered */
  };

struct token * insert(char * string);
int link_count = 0;   /* count of links used  */
int item_count = 0;   /* count of items       */


   /* Routine to determine which linked list  */
   /* This should be fast and "random".       */ 
int hash(char *st)
{
int rtn=0;
char c;

while( (c = *st++) != '\0' )
  {
  rtn = ( ( rtn ^ 0x5A5A ) << 2 ) ^ c;
  rtn = (rtn & 0xFFFF) ^ (rtn >> 12);
  }
return rtn & MAXMASK;
}

main()
{
int i;		   /* loop counter      */
int hash_count[HASHMAX];
int start_point;   /* index in to linked list array */
char string[200];  /* max string size   */
struct token *current; 
struct token *start[HASHMAX];
struct token *working;

                   /* Print hash algorithm constants */
printf("MASKBITS %d\nHASHMAX %d\nMAXMASK %08x\n", 
        MASKBITS,    HASHMAX,    MAXMASK); 

for( i=0; i<HASHMAX; i++) start[i] = NULL;

while( TRUE )          /* Until EOF          */ 
  {                    /* get a string       */
  if( fscanf( stdin, "%s", string ) == EOF ) break;
                       /* figure out which list */
  start_point = hash( string );
  if( start[start_point] == NULL )
    {                  /* place initial string */ 
    start[start_point] = insert( string );
    continue;
    }
  current = start[start_point];
  while( TRUE )
    {                /* look for existing item */ 
    if( strcmp( string, current->value ) == 0 )
      {              /* found existing item   */
      current->usecount++;
      break;
      }
    if( current->next == NULL )  /* if end of list */
      {               /* place item at end of list */
      current->next = insert( string );
      break;
      }
    else 
      {              /* get next item on list */
      current = current->next;
      link_count++;
      }
    }
  }

for( i=0; i<HASHMAX; i++ )
  {
  hash_count[i] = 0;
  current = start[i]; /* print out items */
  while( start[i] != NULL )
    {
    if( current == NULL ) break;
    item_count++;
    hash_count[i]++;
    if( current->usecount > 5 )
      printf("use:%4d --  %s\n", 
              current->usecount, current->value);
    current = current->next;    
    }
  }


for( i=0; i<HASHMAX; i++ )
  printf("%8d",hash_count[i]);
printf("\nItem count: %4d  Link count: %4d\n", 
          item_count,      link_count);

}

     /* routine to insert string at  */
     /* end of linked list.          */

struct token * insert(char * string)
{
int str_length;
struct token * token_ptr;


     /* allocate space for structure */
token_ptr = (struct token*) 
               malloc( sizeof( struct token ));
if( token_ptr == NULL )
  {
  printf("malloc 1 failed\n");
  exit();
  }
    /* get string length and allocate space */
    /* strlen does not include '\0'         */
str_length = strlen( string  ) + 1;
    /* set initial use count */
token_ptr->usecount = 1;
    /* clear next pointer */
token_ptr->next = NULL;

    /* copy string to heap */
token_ptr->value = (char *) malloc( str_length );
if( token_ptr->value == NULL )
  {
  printf("malloc 2 failed\n");
  exit();
  }

strcpy( token_ptr->value, string );

   /* return pointer to new structure */
return token_ptr; 
}


And the edited output:

MASKBITS 8
HASHMAX 256
MAXMASK 000000ff

use:  13 --  things
use: 674 --  will
use:1825 --  a
use:2588 --  to
use:   7 --  Visual
use:   7 --  Cybervision

   61   46   55   47   51   55  ...
 
Item count: 12191  Link count: 602588

Instructor: Louis Taber, louis.taber.at.pima at gmail dot com (520) 206-6850
My web site in California
The Pima Community College web site

7 AssignmentsTop5 Operator Precedence and Associativity6 Notes