Search Contact information
University of Cambridge Home Department of Engineering
University of Cambridge >  Engineering Department >  computing help
next up previous contents
Next: More information Up: ANSI C for Programmers Previous: Find the bug   Contents


Exercises 3

  1. Improve your primes program so that

  2. Put 10 integers in a file, one per line. Write a program that reads the numbers then prints their sum and and average.

  3. Write a program that counts the characters, words and lines in a file.

  4. Read the 1st 10 uids from /etc/passwd, save them in an array of strings and sort them using qsort.

  5. Take a simple program (the malloc example on page [*] will do) and break it up into 2 or 3 source files. See if you can compile them into an executable. Try adding static to variable and function definitions to see what difference it makes. Write a makefile for it.

  6. Write a program that given a filename will produce a new file encrypted using any method you like. Then write another program to decrypt files.

  7. Write a program to count the number of ways that 8 queens can be placed on a chess board without any 2 of them being on the same row, column or diagonal.

  8. Hashing - First a solution to the last hash exercise.
    #include <stdio.h>
    #include <stdlib.h>
    #define TABLE_SIZE 50
    #define MAX_STR_LEN 64
    #define EMPTY  -1
    
    typedef struct {
       char str[MAX_STR_LEN]; 
       int value;
    } Entry;
    
    char str[MAX_STR_LEN];
    
    /* Create an array of elements of type Entry */
    Entry table[TABLE_SIZE];
    
    int process(char *str){
      int val = 1;
      while (*str){
         val = val * (*str);
         str++;
      }
      return val;
    }
    
    char * get_string(char str[])
    {
       printf("Input a string\n");
       return gets(str);
    }
    
    int hashfn(char *str){
      int total = 0;
      int i;
      while (i = *str++)
          total += i;
      return total % TABLE_SIZE;
    }
    
    
    void set_table_values(void){
    /* set all the value entries in the table to EMPTY
       (here we assume that the process() routine doesn't
        produce -1)
    */
    int i;
      for (i =0;i<TABLE_SIZE;i++)
          table[i].value= EMPTY;
    }
    
    int find_entry(char *str, int bucket){
       if (table[bucket].value == EMPTY){
          strcpy(table[bucket].str,str);
          table[bucket].value = process(str);
       }
       else{
          if (strcmp(table[bucket].str,str)){
             bucket = (bucket +1)% TABLE_SIZE;
             return find_entry(str, bucket);
          }
       }
    
       return table[bucket].value;
    }
    
    
    main(){
    int bucket;
    int val;
           set_table_values();
    
    /* Use get_string repeatedly. For each string:-
           use the hash function to find the string's entry
           in the table.
    */
           while(get_string(str)){
             if (! strcmp(str,"end")){
                 printf("Program ended\n");
                 exit(0);
             }
    
             bucket = hashfn(str);
             val = find_entry(str,bucket);
             printf("Value of <%s> is %d\n",str,val);
           }
    }
    

    Another approach to collisions is for each entry in the hash table to be the beginning of a linked list of items that produce the same hash function value. First we need to alter the Entry structure so that it includes pointer to another Entry. There's a slight complication here in that we can't define a pointer to something which isn't defined yet, so we introduce a tag name to the structure.

    typedef struct _entry {
     int value;
     struct _entry *next;
     char str[20];
    } Entry;
    

    New entry structures can be generated using the following routine.

    Entry *create_an_entry(void){
    Entry *entry;
      entry = (Entry*) malloc(sizeof (Entry));
      return entry;
    }
    

    find_entry needs to be re-written.

    int find_entry(Entry ** entry, char *str){
     if (*entry == NULL){
        *entry =  create_an_entry();
        set_entry(*entry,str);
        return (*entry)->value;
     }
     else{ 
        if ((*entry) -> value != EMPTY){
           if (!strcmp ((*entry) ->str, str)){
              printf("Valueue for <%s> already calculated\n",str);
              return (*entry) -> value;
           }
           else{
              printf("There's a collision: <%s> and <%s> share\n",
                        (*entry) ->str, str);
              printf("the same hashfn valueue\n");
     
              find_entry(&((*entry)->next),str);
              
           }
        }
        else{
           printf("<%s> is a new string\n",str);
           set_entry((*entry),str);
           return (*entry)->value;
        }    
     }
    }
    

    The initial table can now be

    /* Create an array of elements of type Entry */
    Entry *table[TABLE_SIZE];
    
    These entries need to be initialised to NULL.

    Now write a program with the following main routine to test all this out.

    main(){
    int bucket;
    int value;
           set_table_values();
    
    /* Use get_string repeatedly. For each string:-
           use the hash function to find the string's entry
           in the table.
    */
           while(get_string(str)){
             if (! strcmp(str,"end")){
                 printf("Program ended\n");
                 exit(0);
             }
    
             bucket = hashfn(str);
             value = find_entry(&(table[bucket]), str);
             printf("Valueue of <%s> is %d\n",str,value);
           }
    }
    
    This program could be further elaborated


next up previous contents
Next: More information Up: ANSI C for Programmers Previous: Find the bug   Contents
Tim Love 2010-04-27