C Programming Language

Honors Computer Systems Organization (Prof. Grishman)

Background

The designers of Java were heavily influenced by C and C++, so there are many similarities between these earlier languages and Java.  We will focus on the differences, and primarily on the use of pointers, and structures containing pointers.

C is a relatively simple language.  Most earlier widely used programming languages, such as FORTRAN, COBOL, ALGOL, and PL/I, were intended for application programming, and some (particularly COBOL and PL./I) were quite complex.  C was developed for operating system implementation (for UNIX, specifically).  It was initially a one-person effort for small machines, which led to the design of a language which was relatively simple and easy to implement.  (for a history of C, see: The Development of the C Language by Dennis M. Ritchie.)  It performed relatively little checking (some more was added in ANSI C), placing more responsibility on the programmer.

C was later augmented with object-oriented capabilities to create C++;  we will not discuss those capabilities here.

Running C

We will be using Microsoft Visual C++ in class, although students are free to use other C implementations.  For our basic tasks (which will not involve Visual C++ graphics capabilities), we want to create a 'Win32 Console Application' and then, within the application, to create a 'C++ source file'.  For a graphical description of this process,  see the notes from Joshua Hart.  Unlike Java, C is translated directly into machine language for the target machine.

Basics

A minimal 'Hello, world' application:
#include <stdio.h>

main ()
{
  printf("Hello, world\n");
}

Variable declaration (like Java) and simple integer output:
#include <stdio.h>
main ()
{
 int a;
 a = 3;
 printf("The value of a is %i\n", a);
}
Main program with function:
#include <stdio.h>
int sum (int, int);

main ()
{
 int a;
 a = sum (3, 5);
 printf("The value of a is %i\n", a);
}

int sum (int i, int j)
{
 return i + j;
}

note that function type information must be declared before the function is first used.  The #include (preprocessor) statement includes a header file with function declarations for the main IO functions.

Arrays and pointers

(Chapter 5 of Kernighan and Ritchie)

Character strings are represented as 0-terminated arrays of characters;  they are not a separate type in C.

char stg[] = "harry"
creates a 6-element array, where the last element is 0.  To compute the length of a string:
#include <stdio.h>
int mylen (char[]);

void main ()
{
 printf ("String is %i characters long.", mylen("quack moo"));
}

int mylen (char stg[])
{
 int count = 0;
 for (int i=0; stg[i] != 0; i++) count++;
 return count;
}

this can also be rewritten using pointers:
#include <stdio.h>
int mylen (char*);

void main ()
{
 printf ("String is %i characters long.", mylen("quack moo"));
}

int mylen (char* stg)
{
 int count = 0;
 while (*stg++) count++;
 return count;
}

Note that the 0 character at the end of the string lets us know 'when to stop' without passing separate length information.

In C, one can perform arithmetic on pointers (such as the "stg++" shown above) -- in effect, doing arithmetic on addresses.  The C compiler knows the size of the items being pointed to, and adjusts the arithmetic accordingly.  Thus chars are each a single byte, so "stg++" adds 1 to the address in stg;  on the other hand, if we had a pointer "int* p", where ints took up 4 bytes, "p++" would add 4 to the address.  C offers no protection once you start doing arithmetic on pointers ... it's easy to clobber any data in memory, by mistake or on purpose.

Returning values through pointers

As in Java, simple types such as ints are passed by value, while arrays are passed by reference, so ordinarily it is not possible to return simple integer values through the argument list.  However, in C it is possible to pass the addresses of variables, and thus modify these variables:
#include <stdio.h>
void swap (int*, int*);

main ()
{
 int a, b;
 a = 3;
 b = 5;
 swap (&a, &b);
 printf ("Now a = %i and b = %i \n", a, b);
}

void swap (int *x, int *y)
{
 int temp;
 temp = *x;
 *x = *y;
 *y = temp;
}

Memory allocation

In C, memory allocation is handled by the programmer.  To get a block of N bytes, one invokes malloc(N);  malloc returns a pointer to the block which has been allocated, or NULL if there is no more space.  [the malloc return type is void*;  this can then be cast to a pointer of the appropriate type].  The space is uninitialized.

To free up this space when it is no longer needed, call free.  Freeing up space which is still in use, or freeing up space which was not allocated by malloc, can produce some very hard-to-find bugs.

Ex:  creating a copy of a string (K&R p. 143).

Structures

(Chapter 6 of Kernighan and Ritchie)

Structures are (very roughly) like Java classes with fields but no methods.  To define a structure with two members:

struct point {
    int x;
    int y;
};
to declare variables of this type:
struct point point1, point2;
to access members of this structure:
point1.x