C Programming

C Program Structure

  1. Every C program consists of functions. These can be in one or more files and a single file can contain multiple functions.
  2. The names of C files is also up to you, but the files containing functions should have names that end in ".c"
  3. A typical ".c" file has the structure:
    comment
    include statements
    functions
    	
  4. You can name the functions in your C programs whatever you like except that the name main is special.
  5. Every complete C program must have a function named main somewhere.

Example


/**
 * Simple program that prints "Hello, World" to
 * standard output.
 */

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

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

  return 0;
}

C functions

  1. Function definition syntax:
      return_type function_name( parameter_list )
      {
        statements
      }	  
    	
  2. A function can be declared without including the function body of statements. The syntax of a function declaration is:
      return_type function_name( parameter_list );
    	

Header files

  1. A header file typically contains function declarations (not function definitions).
  2. Header file names should end in ".h" instead of ".c"
  3. A declaration for a function must occur in a file before any call to the function.
  4. Declarations of all functions called in a file can be written at the beginning of the file (after the comments).
  5. Alternatively, declarations of all functions called can be placed in a separate header file and then effectively placed at the beginning of the file with an include statement:
    #include header_file
    	
  6. Standard C header files contain declarations for functions in C libraries. In this case the header file name is enclosed in < and > delimiters.
  7. Include statements for programmer defined header files, not part of the compiler C libraries, should enclose the header file names in quotes: "..."

Variable types/declarations

  1. Basic signed integer types
     char  -128 to 127
     short -32768 to 32767
     int   -2147483648 to 2147483647
     long  (typically same range as int)
    	
  2. Basic unsigned integer types
     unsigned char  0 to 255
     unsigned short 0 to 65535 
     unsigned int   0 to 4294967295
     unsigned long  (typically same range as int)
    	  
    	
  3. Basic floating point types
     float    -3.40282e38 to 3.40282e38  (and also -inf and +inf)
     double	  -1.79769e308 to 1.79769e308 (and -inf and +inf)
    	
  4. Declaration syntax:
    type variable_list;	  
    	
  5. Example declarations:
     int x;
     int y, z;
     float f;
     int n = 5;
    	
  6. Variable declarations can occur in a file outside any function or inside some function.
  7. Variables can be referenced from the point of declaration to the end of the unit in which they are declared.

Arrays

  1. Array declarations have this syntax:
     type variable_name[constant];	  
    	
  2. Array indices start at 0.
  3. Example:
     int a[100];
     char s[30];
     int x[3] = {5, 10, 15};
    	

    Declares an array of 100 int's: a[0], a[1], ... a[99]

    Declares an array of 30 char's: s[0], s[1], ..., s[29]

    Declares an array of 3 int's with initialized values: x[0] = 5, x[1] = 10, and x[2] = 15

  4. Character strings are represented as char arrays with a last char of integer value 0 (or as character '\0', not '0').
  5. The following declarations equivalent ways to initialize char array u to the string character string Hello
    char u[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
    char u[6] = "Hello";
    char u[] = "Hello";
    	

Pointer types

  1. Pointer values are addresses of other data values.
  2. Pointer declarations have this syntax:
     type * variable_name;	  
    	
  3. Address values can be computed with the unary operator &
  4. The dereferencing operator, unary *, is the inverse of the address operator. The dereferencing operator applied to an address of an variable yields the variable

Example

int x = 5;
int y;
int * p = &x;

y = *p; 
*p = 6;
    
  1. The value of p is the address of x
  2. *p is an alias for x
  3. After the assignments y is 5 and x is 6, p is unchanged

I/O statements

  1. The function printf implements conversion to strings for formatted printing to standard output.
  2. The function scanf implements input from standard input and conversion to various data types (int, float, double, etc.) This function skips leading whitespace, so it will skip newlines if necessary to input the next data.
  3. The function fgets reads input up to and including the next newline and stores the characters read without conversion, adding a terminating '\0' character.

Example 1

 int status;
 int n;
 float x;

 printf("Enter an integer and a float: ");
 status = scanf("%d%f", &n, &x);
 printf("n = %d, x = %f\n", n, x);

Possible Input: 
(on one line)

5 3.5

(or on two lines)

5
3.5
    
  1. Stores 5 in n and 3.5 in x and 2 in status (2 values converted)

Example 2

 char line[30];

 printf("Enter a string\n");

 fgets(line, 30, stdin);

 printf("line = %s", line);

Possible input:

(on one line)
Hello World

(or on two lines)
Hello
World
    

If the input is on one line, the output is

line = Hello World!      
    

If the input is on two lines, the ouput is

line = Hello      
    

Passing Function Parameters

  1. Parameters are passed by value - the parameter is passed
  2. The value of an array is considered the address of the first array element.
  3. So passing an array to a function, actually passes the address of the first array element.
  4. If an int array is passed to a function, the address of the first int in the array is passed. The type of value passed is therefore a pointer to int.
  5. A reverse function that reversea the order of the characters in the char array passed to it, could be declared in either of the following equivalent ways:
     void reverse(char s[]);
    
    or
    
     void reverse(char *s);
    	  
    	

    With either declaration, s can be treated as an array in the body of reverse. In particular the characters of the string parameter can be referenced using integer subscripts; e.g. as s[i] for i = 0, 1, ..., strlen(s) - 1

Partial implementation of reverse.c

/**
 * Reads one line of input from standard input and prints the characters read 
 * in reverse order.
 */

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

/* Function declarations (defined after main) */
void chomp(char s[]);
void reverse(char s[]);


int main()
{
  char line[132];
  printf("Enter a line of input\n");
  fgets(line, 132, stdin);
  chomp(line);
  reverse(line);
  printf("The input line in reverse order:\n");
  printf("%s\n", line);

  return 0;
}

/**
 * removes the last character of string s if it is a newline
 */
void chomp(char s[])
{
  /* you write this */


}

/**
 * reverses the order of characters in the string s
 */
void reverse(char s[])
{
  /* you write this */


}

C String library

  1. To copy an array or compare two arrays generally requires writing code to copy or compare the elements of the arrays, one at a time.
  2. Since character strings are implemented in C as char arrays (with a terminating 0 after the last character), operations on strings such as copying, comparison, and computing the length are not builtin.
  3. However, there is a C library of functions for copying, comparing, computing string length and more.
  4. The C string library functions are declared in the header file:
    string.h 	  
    	

    So a program that uses these functions should add the include statement at the beginning of the file:

     #include <string.h>	  
    	

Some C string functions

Function declaration Description
unsigned int strlen(const char s[]); returns the length of the string stored in s (doesn't count the terminating 0.
int strcmp(const char s1[], const char s2[]); returns negative value if s1 is lexicographically less than s2 (comes before s2 as strings)
returns 0 if s1 and s2 are equal as strings
returns positive value if s1 is lexicographically greater than s2 (comes after s2 as strings)
char * strcpy(char dest[], const char src[]); copies the characters in src to dest including the terminating 0. The return value is just the value of dest, that is, the beginning address of the dest array.

Complete string example

/**
 * Reads words, one per line, from standard input.
 * Sorts the words in alphabetical order and 
 * prints to standard output.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXLEN 31
#define MAXCNT 100

void sort(char s[][MAXLEN], int n);
void print(char s[][MAXLEN], int n);
void chomp(char w[]);

int main()
{
  char w[MAXLEN];
  char words[MAXCNT][MAXLEN];
  int cnt = 0;


  printf("Enter words, one per line. ctrl-d to finish\n");
  
  while( fgets(w, MAXLEN, stdin) != NULL ) {
    chomp(w);
    strcpy(words[cnt], w);
    cnt++;
  }

  sort(words, cnt);

  printf("\nSorted words\n");
  print(words, cnt);
  
  return 0;
}


void sort(char s[][MAXLEN], int n)
{
  char tmp[MAXLEN];
  int len, i;
  int maxpos;

  for(len = n; len > 1; len--) {
    maxpos = 0;
    for(i = 1; i < len; i++) {
      if (strcmp(s[maxpos], s[i]) < 0) {
	maxpos = i;
      }
    }
    strcpy(tmp, s[maxpos]);
    strcpy(s[maxpos], s[len - 1]);
    strcpy(s[len - 1], tmp);
  }
  
}

void print(char s[][MAXLEN], int n)
{
  int i;

  for(i = 0; i < n; i++) {
    printf("%s\n", s[i]);
  }

}

/**
 * remove trailing newline from string w if there is one.
 */
void chomp(char w[])
{
  int n = strlen(w);
  if (w[n-1] == '\n') {
    w[n-1] = 0;
  }
}