Introduction to C for C++ programmers

C is the official language for systems development on Unix systems. We will be using the C language for virtually every assignment in this course.

All of you have experience with C++ from CMSC 270 and CMSC 510. C++ is a superset of the C language, and shares many features with C, including if-else statements, loops, arrays, and pointers.

Because the C++ language replaces a number of key features from C with more modern equivalents, the main thing you will have to learn is those original C features that C++ replaces. This document will serve as your introduction to those features.

No cout or cin

C++ uses the convenient cout and cin constructs in combination with the stream insertion and extraction operators << and >> to do input and output. C uses functions from the C standard input/output library instead.

To use any of the standard input/output functions in C you need to use this #include statement:

#include <stdio.h>

To print to the standard output C uses the printf function.

int number = 2;
printf("1 + 1 = %d\n",number);

printf stands for "print formatted." This function takes one or more parameters. The first parameter is always a text string that may contain output placeholders. This example's format string contains one placeholder, %d, which is a placeholder for a single decimal integer value. Following the format string in printf is a list of values separated by commas. These values will be used to replace the placeholders in the format string in left-to-right order when we print. In this example, we use the value stored in the number variable to replace the %d placeholder.

Note also the newline character \n at the end of the format string. This tells printf to emit a newline character at the end of its output so that any further output that appears will appear on the next line after what we have just printed.

Here is a table of the most common format codes used with printf.

CodeWhat it prints
%dints
%ffloats as decimal number
%efloats in scientific notation
%lfdoubles as decimal number
%scharacter strings

More extensive documentation on C format codes is available here.

C uses the scanf function to read inputs from the console.

float h;
scanf("%f",&h);

scanf is similar to printf, in that its first parameter is a format string that contains one or more placeholders. The placeholders tell scanf how many items it should expect to read from the user and what their types are. In this case, we are expecting to read a single float from the user, so we use a format string of "%f". After the format string we have a list of one or more pointers to variables that we want to read the input into. In this example we use the address-of operator & to get a pointer to the variable we want to read our input into.

To print or read text input from files, C uses fprintf and fscanf in place of printf and scanf.

The following example is a program that opens up a text file named "data.txt" containing a list of integers, reads thoses integers, and computes their sum.

#include <stdio.h>

int main (int argc, const char * argv[])
{
  FILE *input;
  int term, sum;

  sum = 0;

  // Open input file in read mode.
  input = fopen("data.txt","r");
  // Read input until we reach end of file
  while(!feof(input))
  {
    fscanf(input,"%d",&term);
    sum = sum + term;
  }
  // Close input file
  fclose(input);

  printf("The sum of the numbers is %d.\n",sum);

  return 0;
}

Here is a second example that generates a pseudorandom number sequence and saves it to an output file.

#include <stdio.h>

int main (int argc, const char * argv[])
{
  FILE *output;
  int x, n;

  // Seed value to start the sequence
  x = 152;

  // Open output file in write mode
  output = fopen("random.txt","w");

  for(n = 0;n < 1000;n++)
  {
    x = (17389*x+12553)%11657; // Generate next number in sequence
    fprintf(output,"%d\n",x%10);
  }

  fclose(output);

  printf("Done.\n");

  return 0;
}

C strings

C++ offers the handy string class to help you work with text in programs. C does not have classes, so C programs store text as null-terminated arrays of characters and uses pointers to those arrays of characters.

Here are some basic examples. To use preset blocks of text in a program you can simply obtain a pointer to text literal.

const char* greeting = "Hello, World!";

To read text that the user has typed you have to set up an array of chars to hold the text and then use scanf to read text the user types.

char buffer[64];
scanf("%s",buffer);

Important warning In the example above we set up an array of size 64 to receive the text the user typed. This array has room for 63 characters plus the '\0' character that marks the end of the text. If the user types more than 63 characters scanf will write past the end of the buffer array. This is what is known as a buffer overflow, and may cause your program to crash or produce incorrect results.

The C standard library contains a number of functions designed to work with text strings. All of these functions are available via the #include statement

#include <string.h>

Here is a list of some of the more useful string functions. In every case where these functions work with a pointer to char, the pointer is actually intended to point to an array of chars.

FunctionWhat it does
strcpy(char* dest,char* source)Copies a string from source to dest
strlen(char* str)Returns the length of the string str
strcmp(char* one,char* two)Compares one and two for alphabetical order

The strcmp function compares two string arrays one and two, and returns -1 if one comes before two in alphabetical order, 0 if the two strings are the same, and 1 if one comes after two in alphabetical order. (Be careful when using this function: in the ASCII coding system all of the upper case letters come before the lower case letters, so "Zebra" comes before "apple" in alphabetical order.)

More extensive documentation on C string functions is available here.

No new or delete

C++ uses the new and delete operators both to create objects and arrays. Typical C++ code to create an array of 100 ints looks like

int* A = new int[100];

C does not have either a new or a delete operator. Instead, C makes use of a pair of library functions, malloc() and free() to dynamically allocate and deallocate memory. To use either of these library functions you have to start with the appropriate #include statement:

#include <stdlib.h>

The malloc() function takes as its sole parameter the size in bytes of the memory block you want to create. To determine the size of any of the built-in types we use the sizeof() operation. For example, to allocate an array of 100 ints we would do

int* A = (int*) malloc(100*sizeof(int));

Since malloc() returns a generic pointer of type void* we have to typecast the result of malloc to the type of pointer we want.

To delete memory that we allocated with malloc() we use free():

free(A);

structs

C++ is an object-oriented language that makes heavy use of the class construct. C is not object-oriented, so you will not be able to use classes in a C program.

The C language does include a struct construct. A struct is essentially a class with only member variables and no methods.

Here is a typical example. Suppose we wanted to construct a C equivalent for the useful vector<int> class. Our starting point would be a struct definition to define a intVector struct:

struct intVector {
  int* items;
  int size;
  int capacity;
};

A C struct is essentially a list of member variables.

C++ makes a distinction between public and private member variables. In a C struct all members are automatically public.

You can create an instance of the struct by either declaring a struct type variable directly or by using malloc() to create a pointer to a struct:

struct intVector A;
struct intVector* B = (struct intVector*) malloc(sizeof(struct intVector));

You can access the members of the struct via the familiar . and -> operators:

A.capacity = 8;
A.items = (int*) malloc(A.capacity*sizeof(int));
A.size = 0;
B->capacity = 16;
B->items = (int*) malloc(B->capacity*sizeof(int));
B->size = 0;

An alternative to the method shown above for declaring a structure type is to use a typedef construct.

typedef struct {
  int* items;
  int size;
  int capacity;
} intVector;

The primary advantage to this approach is that you don't have to use the struct keyword all over the place when you are working with a struct defined in this way. For example, the code above becomes

intVector A;
intVector* B = (intVector*) malloc(sizeof(intVector));

Which is faster and easier to type.

In place of methods in a class, C programmers typically write functions that take a pointer to the struct to be manipulated as a parameter.

Here is an alternative way to create and initialize an intVector.

intVector* makeIntVector(int capacity) {
  intVector* V = (intVector*) malloc(sizeof(intVector));
  V->capacity = capacity;
  V->items = (int*) malloc(capacity*sizeof(int));
  V->size = 0;
  return V;
}

Here is how we would define a push_back operation on our vector.

void push_back(intVector* V,int x) {
  if(V->size == V->capacity) {
    int* newItems = (int*) malloc(V->capacity*2*sizeof(int));
    int n;
    for(n = 0;n < V->size;n++)
      newItems[n] = V->items[n];
    free(V->items);
    V->items = newItems;
    V->capacity = V->capacity*2;
  }
  V->items[V->size] = x;
  V->size++;
}

In place of a destructor we have to define a function to free the intVector and its included array.

void destroy(intVector* V) {
  free(V->items);
  free(V);
}

No reference parameters

C++ introduced the handy reference parameter. C does not have reference parameters. If you want to pass an item by reference you have to pass a pointer to that item instead.