Intro to C -- the Saga Continues ...


Functions

Functions are the basic building unit of a C program. They are usually a set of statements put together to complete a single task. A function expects some inputs from the calling function and gives back a return value. A well-writen modularized C progaram typically include a very short main function and a lot of functions or modules to do individual tasks.

To declear a function:

   int add(int, int);
   void add_prt(int, int);
   int main();

Implementation of functions:

   int add(int a, int b){

     a += b;     
     return a;

   }
   
   void add_prt(int a, int b) {

     int c=add(a,b);
     printf("%d + %d = %d\n", a, b, c);

   }

To call a function:

   int main(){

     int a = 3;
     int b = 5;

     int  c = add(3,5);

     printf("c = add(3,5)\t");
     printf("3 + 5 = %d\n",c);

     c = add(a,b);

     printf("c = add(a,b)\t");
     printf("%d + %d = %d\n", a, b, c);

     c = add(a,b) - 2;

     printf("c = add(a,b)-2\t");
     printf("%d + %d - 2 = %d\n", a, b, c);

     printf("add_prt(3,5)\t");
     add_prt(3,5);
   }

Download the sample program.


Modularized "Hello, world"

Here is a modified "Hello, world" program which will ask for your name and say hello to you! It uses two modules to do the asking-name and saying-hello tasks.

   #include <stdio.h>

   void get_name(char name[]) {
  
     printf("What's your name? ");
     scanf("%s", name);
     
   }

   void say_hello(char name[]) {

     printf("Hello, %s!\n", name);

   }

   int main(){

     char name[20];

     get_name(name);
     say_hello(name);

   }

Download the sample program.


Pointers, Arrays and Character Strings

A pointer is a variable which stores the address of a piece of memory. The size of the memory depends on the type of the pointer, which can be any of the basic variable types. A lot of data structures in C are built upon the use of pointers. It's like the soul of C -- you should be able to use it freely to be an expert in the programming language.

To declear a pointer variable, use "*":

   int *p, *q;
   double *d;
   char *c;

To point a pointer to an actual storage, use "&" for the address of a variable:

   int P, Q;
   double D;
   char C;

   p = &P;
   q = &Q;
   d = &D;
   c = &C;

To allocate and release memory dynamically:

   #include <stdlib.h>

   p = (int*) malloc(sizeof(int));
   d = (double*) malloc(sizeof(double));
   c = (char*) malloc(sizeof(char));

   ...

   free(p);
   free(d);
   free(c);

Pointers of the same type can be assigned to each other:

   q = p;

To refer to the variable a pointer points to, use "*":

   *p = 3;
   Q = 6;
   Q += *p;
   *p += Q;

An array is a pointer to a block of data of the same type:

   #include <stdlib.h>
   
   int a[20];
   int *b;
   b = (int*) malloc (20 * sizeof(int));
   
   int i;
   for (i = 0; i < 20; i++) a[i] = 1;
   b[0]=1;
   for (i = 1; i < 20; i++) b[i] = b[i-1] + 1;

   free(b);

Pointer arithmetics: pointers are stored as long int numbers internally, so integers can be added to or substracted from them. However, this only makes sense when using with arrays. We know that the name of an array is a pointer to its first member, or a[0] is equivalent to *a. The next member of the array is a[1], or *(a+1). No matter what type the array is, *(a+1) always refer to the member next to *a.

A character string is a char type array:

   #include <string.h>
   #include <stdlib.h>
   
   char str[30];
   char *str1, *str2;
   
   str1 = str;
   str2 = (char*) malloc (30 * sizeof(char));

   strcpy(str,"Hello, world!");
   strcpy(str2,str1);
   strcat(str2," Bye.");
   if (strcmp(str1,str2) == 0) printf("The two strings are the same.\n");
   else printf("The two strings are different.\n");

   free(str2);


Using pointers as function arguments

A C function can only return one value, but you can use pointers as function arguments to get more out of the function. Here is the tranditional sample program (data swap) to tell the difference between pointers and normal variables as function arguments.

   #include <stdio.h>

   void swap_var(int a, int b){

     int c;
     c = a;
     a = b;
     b = c;

   }

   void swap_ptr(int *a, int *b){

     int c;
     c = *a;
     *a = *b;
     *b = c;
   }

   int main(){

     int a = 3;
     int b = 5;

     printf("a = %d, b = %d\n",a,b);
  
     swap_var(a,b);
     printf("After swap_var(a,b):\t a = %d, b = %d\n",a,b);
  
     swap_ptr(&a, &b);
     printf("After swap_ptr(&a,&b):\t a = %d, b = %d\n",a,b);
   }

Download the sample program.


Structures

Sometimes one needs to work on a lot of common properties of a single type of object. For example, in a N-body integrater, one uses the three components of coordinates and three components of velocities of all the particles. With the knowledge of array, we can use six arrays with same dimension (the number of particles in the system) for all these values. However, it will be much nicer if we can combine all the six fields together and use a single variable for an individual particle.

   typedef struct _planet Planet;
   struct _planet{
     char name[10];
     double x[3];
     double v[3];
   };

   ...

   Planet p;
   Planet ps[9];
   Planet *pp;

   struct _planet p2;

A field of a structure variable is refered by the name of the variable followed by a "." and the name of the filed:

   strcpy(p.name,"Earth");
   ps[0].x[0] = 1.;
   (*pp).v[0] = 1.;
In the last example, the parethesis is not required, but it will make the code easier to read. There is an easier and more illustrative way to refer to the fields of a pointer to a structure. The last example is equivalent to:
   pp->v[0] = 1.;


Putting everything together: a linked list

Here is an example which is usually used on the first data structure class: a linked list. The codes demonstrate how to use pointers, structures, and functions. In this example we create a linked list to store people's age, sorted by their names.

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


typedef struct _node List;  /* the name of the list will be a pointer to a node, so alias List type to Node */
typedef struct _node Node;
struct _node {
  Node *next;
  char *name;
  int age;
};


/* to create a new node with a name and an age */
Node* create(char *name, int age){

  Node* anode = (Node*) malloc(sizeof(Node));

  anode->name = (char*) malloc(sizeof(char) * (strlen(name)+1));  /* need one extra space for the null character */
  strcpy(anode->name, name);
  anode->age = age;
  anode->next = NULL;
  
  return anode;   /* memory dynamically allocated in subroutines is not released after exiting the function */
}

/* to destroy an node */
void destroy(Node *anode){
  free(anode->name);
  free(anode);
}

/* to insert a node */
void insert(List* list, char* name, int age){

  Node* p = list;
  Node* anode = create(name, age);
  
  while (p->next && (strcmp(anode->name, p->next->name)>0)) p = p->next;
  anode->next = p->next;
  p->next = anode;
}

/* to search a name */
Node* search(List *list, char *name){

  Node* p = list;

  while (p->next && (strcmp(name, p->next->name)>0)) p = p->next;
  if (p->next && !strcmp(name, p->next->name)) return p->next;
  else return NULL;
}

/* to delete a node */
int delete(List *list, char* name){

  Node *q, *p = list;

  while (p->next && (strcmp(name, p->next->name)>0)) p = p->next;
  if (p->next && !strcmp(name, p->next->name)) {
    q = p->next;
    p->next = p->next->next;
    destroy(q);
    return 1;
  }
  else return 0;
}

/* to kill the whole list */
void kill(List *list){
  Node *q, *p=list;

  while (p->next){
    q = p;
    p = p->next;
    destroy(q);
  }
  destroy(p);
}

/* show a node */
void printnode(Node* anode){

  printf("%s is %d years old.\n", anode->name, anode->age);
}

/* show the whole list */
void printall(List* list){

  Node* p = list;

  while (p->next) {
    printnode(p->next);
    p = p->next;
  }
}

/* print a task selection menu */
int tasksel(){
  char ch=0;
  
  while (ch < '0' || ch > '4') {
    printf("\nPlease select a task:\n");
    printf("  1. Add a person\n");
    printf("  2. Delete a person\n");
    printf("  3. Search a person\n");
    printf("  4. Show the whole pool\n");
    printf("  0. Exit\n");
    ch = getchar();
  }

  return ch-'0';    
}

main(){

  List *pool = create("",0);  /* the header node is empty for easy programing */
  int task;
  char name[20];
  int age;
  Node *anode;

  while (task = tasksel()) {
    switch (task) {
    case 1: 
      printf("Name? ");
      scanf("%s",name); 
      printf("Age? ");
      scanf("%d",&age);
      insert(pool, name, age);
      printf("Inserted\n");
      break;
    case 2:
      printf("Name to delete? ");
      scanf("%s",name);
      if (delete(pool, name)) printf("%s is deleted.\n",name);
      else printf("%s is not on file.\n");
      break;
    case 3:
      printf("Name to search? ");
      scanf("%s", name);
      if (anode = search(pool, name)) printnode(anode);
      else printf("Not found.\n");
      break;
    case 4:
      printall(pool);
    }
  }	

  kill(pool);
}

Download the sample program.