Learn Cocoa

Learn C for Cocoa

This tutorial explains the parts of C you need to get started with Cocoa. We cover most concepts in a page or two instead of an entire chapter. Don't skim. Give your complete attention to each section.

You should already know at least one scripting or programming language, including functions, variables and loops. You'll also need to type commands into the Mac OS X Terminal.

This Cocoa Dev Central tutorial is written by Scott Stevenson
 
Copyright © 2004-2015 Scott Stevenson

Skills Check

Make sure you understand the code below before continuing.
 
function display_area_code ($code) { print ("$code "); } $area_codes[0] = 408; $area_codes[1] = 650; $area_codes[2] = 510; /* this is a comment */ $count = 3; for ($i = 0; $i < $count; $i++) display_area_code ($area_codes[$i]);
This example has a function, a print statement, a comment, an array, variables, and a loop. If all of this makes sense to you, you're ready to use this tutorial.

To download the examples instead of typing them, grab the following disk image: All examples for tutorial

You must have Xcode installed to build software on Mac OS X, though most of the code here will probably work on any OS.

A Sample C Program

This is your first C program. Paste this example into a plain text editor and name the file test1.c
 
test1.c
#include <stdio.h> main () { printf ("I'm a C program\n"); }
The #include <stdio.h> statement includes the C code that deals with input and output. We need this for the printf function.

The next line defines the main function that all C programs have.

Finally, I call the printf function with some text to display on the command line. The \n inserts a new line after the text.

Use GCC to Compile

Open Terminal and change to the directory that contains the test.c file. Enter the command gcc test1.c -o test1. To run the program, enter ./test1 on the command line.

If see errors, go back and make sure you pasted the sample source code correctly.
 
host% gcc test1.c -o test1 host% ./test1 I'm a C program host%
The -o parameter for gcc sets the name of the program file. If you leave this out, the program will just be called "a.out".

About the Compiler

You need to use a compiler to convert your C source code into a binary program before you can run it. A compiled program often runs much faster than a script. Much of Mac OS X is written in C.

In this tutorial, we're using gcc on the command line to compile, but Xcode provides a graphical front end to the same tools.
 

Portability

A C program can usually only run on the same type of computer it was compiled on. If you compile your C source on Mac OS X, you can't run the program on something like Linux. You have to recompile the same code on Linux.

In more complex C programs, you have to change the code for each platform you compile for. This is called porting the code.

C Differences

It's easier to learn C if you can compare it to a language you already know. Below is a list of concepts that are new to you if you're coming from a scripting language like PHP or Perl:
 
Basic C Concepts
compiler creates useable programs from C source
typed variables kind of data that a variable contains
typed functions the kind of data returned from a function
header files (.h) declare functions and variables in a separate file
structs groups of related values
enums lists of predefined values
pointers aliases to other variables

These are all pretty simple concepts. The C language is not that complicated, it's just that all the different pieces can be put together in a way that makes things seem confusing.

Without pointers, C would look almost identical to PHP. Pointers are tricky conceptually, but Cocoa abstracts you from the most of the those details for basic programming.

You're not going to learn about pointers in this tutorial. The focus here is getting you up and running quickly. You can go back and revisit pointers when you want to get into more serious programming.

Typed Variables

In scripting languages, you can use variables freely. You're allowed to change the contents of a variable from an integer number, to a decimal number, and finally to text:
 
$variable = 2; $variable = 1.618; $variable = 'A';
In C, the rules are more strict. You have to declare the type of data a variable will hold, and the type can't change later. Here's the C equivalent of the snippet above:
 
int variable1 = 2; float variable2 = 1.618; char variable3 = 'A';
Notice that I had to define three separate variables in the C version, one for each type of data. You only have to declare the variable type once, though:
 
float variable2 = 1.618; variable2 = 3.921; variable2 = 4.212;

Available Types

For our purposes, these are the built-in C types you need to know about:
 
Type Description Examples
int integer numbers, including negatives 0, 78, -1400
unsigned int integer numbers (no negatives) 0, 46, 900
float floating point decimal numbers 0.0, 1.618, -1.4
char single text character or symbol 'a', 'D', '?'

Although you won't see them as often, be aware of the double type, which is a version of float that can hold larger decimal point numbers, and long, which is a larger version of int.

C also allows you to create your own variable types.

Typed Functions

In C, you have to declare the type of data you plan to return from a function. The return type can be any C variable type, and is placed to the left of the function name.
 
int numberOfPeople () { return 3; } float dollarsAndCents () { return 10.33; } char firstLetter () { return 'A'; }
You can also specify the return type as void. For now, you can just think of this as saying that no value will be returned:
 
void printHello () { printf ("Hello\n"); }

Types for Parameters

It's also necessary to define types for values passed into a function. Unlike scripting languages, though, you can't set default values.
 
int difference (int value1, int value2) { return value1 - value2; } float changeDue (float amountPaid, float costOfItem) { return amountPaid - costOfItem; }

Declaring Functions

In C, a function has to be declared before any other code can call it. You can put all the functions before main(), but this quickly becomes a lot of work.

The solution is a function prototype. It looks like a function definition, but it doesn't have curly braces and ends in a semicolon:
 
int difference ( int value1, int value2 ); float changeDue ( float amountPaid, float costOfItem );
In a function prototype, you specify the type of data to return, the function name, and a type for each value passed into the function.

Here's an example. Paste the contents into a file called test2.c
 
test2.c
#include <stdio.h> int sum ( int x, int y ); main () { int theSum = sum (10, 11); printf ( "Sum: %i\n", theSum ); } int sum ( int x, int y ) { return x + y; }
I include stdio.h so I can use printf. After that, I declare the sum function using a prototype. Inside main, I call the sum function, and store the result in a variable called theSum.

Because the sum function specifies a return type of int, I need to declare theSum as an int too. The variable type should match the function return type.

I display the contents of theSum using printf. At the bottom is the sum function itself, which just adds the two number together. This is called the function implementation.
 

Compile the Example

Open Terminal and change to the directory which contains test2.c. Then, type "gcc test2.c -o test2" to compile.

Type "./test2" to run the program.
 
host% gcc test2.c -o test2 host% ./test2 Sum: 21 host%

Format Strings

You might be wondering what that %i in the above example means. In some scripting languages like PHP, you can freely embed variables inside of double quotes:
 
$var1 = 3; $var2 = 8; print ("First value: $var1 second value: $var2");
In C, you can't embed variables directly inside text. You have to use a format string with markers for the variables:
 
int var1 = 3; int var2 = 8; printf ("First value: %i second value: %i", var1, var2);
Format Markers
int %i / %d
unsigned int %u
float %f
char %c
The format string is everything inside the double quotes. Put a % marker anywhere you want the contents of a variable to appear.

The letter you put next to the percent symbol depends on the type of value you want to display. In this case, I use %i because I have int variables.

The format string is followed by a comma, and the name of one variable for each marker you used. It's critical that the variable names come after the closing quote and a single comma.

Cocoa programs use NSLog instead of printf, but the formatting rules are almost identical.

Type Casting

Sometimes you need to convert a variable from one type to another. For example, you might have a float that you need to use in a function that requires an int.

Sometimes you can just use an int variable in place of a float without any errors, but it's better to do the conversion yourself. This conversion is called casting.
 
int multiply (int x, int y) { return x * y; } int trips = 6; float distance = 4.874; int approxDistance = (int)distance; int total = multiply ( trips, approxDistance );
So casting is basically putting the desired type in parantheses, just to the left of the value.

The results of casting vary on what you're converting to and from. Converting a float to an int will simply chop off the digits after the decimal point. Casting does not round numbers up.

Casting temporarily converts the contents only, not the variable itself. In the above example, distance is a still a float variable after the cast, so you have to use the cast again every time you want it treated as an int.
 

More Casting Examples

Here's a way to call the function without using the approxDistance variable. I can just do the cast inside the function call instead:
 
int result = multiply (trips, (int)distance);
Sometimes you need to convert the data returned from a function into a different type. You use the same form for that:
 
int multiply (int x, int y) { return x * y; } float result; result = (float) multiply (3, 6);
From the function definition, I can see that multiply returns an int. I want to store the result in a float, so when I call the function, I use a (float) cast before the function name. The result variable will have a value of 18.0.

Header Files

Since you need to declare all functions in C before you can use them, it would be helpful to group related function declarations and manage them in a single place. This is what header files do.

Header files are vital in large projects because they give you an overview of source code without having to look through every line of code.

Create a Header File

Here's a sample header file. Copy the contents into a file named math_functions.h
 
math_functions.h
int sum (int x, int y); float average (float x, float y, float z);
Here are the function implementations. Paste the contents into a file called math_functions.c
 
math_functions.c
int sum (int x, int y) { return (x + y); } float average (float x, float y, float z) { return (x + y + z) / 3; }
In the average function, I separated the addition from the division using parenthesis. If I didn't, only the last number would be divided. It's always good practice to group all the values used in a single math operation.

Using Header Files

Here's a program that uses the functions declared in the header file. Copy the contents into a file called test3.c
 
test3.c
#include <stdio.h> #include "math_functions.h" main () { int theSum = sum (8, 12); float theAverage = average (16.9, 7.86, 3.4); printf ("the sum is: %i ", theSum); printf ("and the average is: %f \n", theAverage); printf ("average casted to an int is: %i \n", (int)theAverage); }
After the standard stdio.h, I include math_functions.h. This allows the program call the sum and average functions.

Inside main, I call the sum function and store the result in an int variable. Then I call the average function and store the result in a float variable.

The program uses printf three times. Once using the %i symbol for the int variable theSum, once using %f for the float variable theAverage, and once with %i by casting theAverage to int.

The stdio.h include is in angle brackets because it's from a C library (more on that later). The math_functions.h file is specific to this program, so it's in double quotes.

Compile the Example

You should now have three files, all in the same directory:

math_functions.h - math function declarations
math_functions.c - math function implementations
test3.c - the actual program

Switch back to Terminal, and change to the directory which contains the three files. To compile the program, type "gcc test3.c math_functions.c -o test3".

Run the program by typing "./test3"
 
host% gcc test3.c math_functions.c -o test3 host% ./test3 the sum is: 20 and the average is: 9.386666 average casted to an int is: 9 host%
This time we gave gcc two input files: test3.c and math_functions.c. The gcc command combine the contents the two .c files into a single program.

I don't need to list the header file math_functions.h on the command line. I just use the #include statement instead.

Structs

Structs are structured groups of variables. Here's an example of a struct designed to store song information.
 
typedef struct { int lengthInSeconds; int yearRecorded; } Song;
Struct Diagram It looks like I'm declaring two int variables, but I'm actually creating a new type of variable. The typedef statement assigns a name to the struct. In this case, the name is Song.

Every Song variable I declare will hold two values: lengthInSeconds and yearRecorded. In this case, both fields hold int values, but a field in a struct can be any type (even another struct).

Once you define a struct, you can use it the same way you'd use int, float or char. You can make as many Song variables as you want, each with their own length and year.

You assign a value to field in a struct using the dot syntax:
 
Song song1; song1.lengthInSeconds = 213; song1.yearRecorded = 1994; Song song2; song2.lengthInSeconds = 248; song2.yearRecorded = 1998;
I created a variable called song1 and gave it a type of Song. I then set the length and year using the dot syntax. The variable song2 is also a Song, but it has different values for its fields.

Structs in Functions

Functions can specify structs as input or output. These function declarations and the struct itself can be put in a header file.

Paste the following code into a file called song.h
 
song.h
typedef struct { int lengthInSeconds; int yearRecorded; } Song; Song make_song (int seconds, int year); void display_song (Song theSong);
In this header file, I defined the Song struct. I also declared two functions, make_song and display_song. Now we need to create the method implementations.

Paste the following code into a file called song.c
 
song.c
#include <stdio.h> #include "song.h" Song make_song (int seconds, int year) { Song newSong; newSong.lengthInSeconds = seconds; newSong.yearRecorded = year; display_song (newSong); return newSong; } void display_song (Song theSong) { printf ("the song is %i seconds long ", theSong.lengthInSeconds); printf ("and was made in %i\n", theSong.yearRecorded); }
The make_song function takes two int values and returns a Song struct. The display_song function takes any Song struct as input, and displays its values. Note that the make_song function calls display_song when a new Song is created.

I had to include song.h in song.c because the functions use the Song type. You have to include the song.h header in any file which uses Song in any way.

Structs in Use

Now we need a program that uses the song.h and song.c files. Paste the following code into a file called test4.c
 
test4.c
#include <stdio.h> #include "song.h" main () { Song firstSong = make_song (210, 2004); Song secondSong = make_song (256, 1992); Song thirdSong = { 223, 1997 }; display_song ( thirdSong ); Song fourthSong = { 199, 2003 }; }
In this program, I create two Songs using the make_song function. Rather than using make_song for the third song, I use a special syntax that involves putting comma-separated values between curly brackets.

Note that when I don't call make_song to create a song, the display_song function doesn't get automatically called. So on the next line, I call it manually. The fourth song is created in the same way, but since I never call display_song for it, it's never displayed in Terminal.

It's better to use a function to create a new struct instance so you can control the process more precisely. In this case, I can automatically display information about each Song that's created.

Compile the Example

Now that you have song.h, song.c and test4.c, you can compile them and see the output.

Switch to Terminal, change to the directory that contains the three files, and enter the command "gcc test4.c song.c -o test4".

Type "./test4" to run the program.
 
host% gcc test4.c song.c -o test4 host% ./test4 the song is 210 seconds long and was made in 2004 the song is 256 seconds long and was made in 1992 the song is 223 seconds long and was made in 1997 host%

Constants

The value of a variable can change as a program runs. By contrast, a constant is assigned a value once in the declaration, and that value can't change until the program is restarted.
 
const float goldenRatio = 1.618; const int daysInWeek = 7;
You can have a constant version of any of the standard C variable types. The only trick is that you have to supply a value when you create the variable.

Enums

We could spend a lot of time on enums, but in the spirit of focusing on the relevance to Cocoa, we're going to make this really, really simple.

Here's an enum from Cocoa's NSString class which defines text search options:
 
enum { NSCaseInsensitiveSearch = 1, NSLiteralSearch = 2, NSBackwardsSearch = 4, NSAnchoredSearch = 8, NSNumericSearch = 64 };
Apple uses enums in Cocoa to group a series of related constants. This is often used as a way to set a "mode" for a particular function. The values of the constants don't really matter, just the name.

Here's an example of an enum in use. Don't worry about understanding what this code does, just focus on how the enum is being used:
 
[string compare:anotherString options:NSCaseInsensitiveSearch]; [string compare:anotherString options:NSLiteralSearch];

Libraries

The stdio.h file included in every example is a header file for part of the standard C library. A library is a collection of reusable code. It can define things like functions, structs, constants and enums.

There are thousands of third party C libraries available. Some are free and come with .c source files. Others require a fee and provide header files and documentation but no source code.

Library Diagram

To use a third party library, you have to compile and "link" to it. For example, if I wanted to write a C program that could talk to a MySQL database, I could link to the libmysql library and include its headers in my program.

When you use code created by others, it's important to know what the terms of use are. Some licenses, for example, may require you that share all of the source code for your application.

If you're feeling adventurous, take a look in /usr/include, which is a standard place for C header files.

Final Example

Here's a final program that uses almost all of the concepts from this tutorial. You need to have the following files from before:

math_functions.h - math function declaration
math_functions.c - math function implementations
song.h - Song struct and related function declarations
song.c - implementation of the Song functions

Paste the contents of this example into a file called final.c
 
final.c
#include <stdio.h> #include "math_functions.h" #include "song.h" main () { const int numberOfSongs = 3; printf ("total number of songs will be: %i\n", numberOfSongs); int i; for (i = 0; i < numberOfSongs; i++) { printf ("loop trip %i ", i); } printf ("\n"); Song song1 = make_song (223, 1998); Song song2 = make_song (303, 2004); Song song3 = { 315, 1992 }; display_song (song3); int combinedLength = sum (song1.lengthInSeconds, song2.lengthInSeconds); printf ("combined length of song1 and song2 is %i\n", combinedLength); float x = (float) song1.lengthInSeconds; float y = (float) song2.lengthInSeconds; float z = (float) song3.lengthInSeconds; float averageLength; averageLength = average (x, y, z); printf ("average length is: %f as a float ", averageLength); printf ("and %i as an int\n", (int) averageLength); }
This example may look complex, but it's just repetition of the same concepts. If there's anything here that doesn't make sense, go back and read the previous sections.
 

Compile the Example

Make sure you have the four files previously mentioned plus final.c, all in the same directory. Switch to Terminal and change to the directory which contains the files. Enter the command gcc final.c song.c math_functions.c -o final.

Type ./final to run the program
 
host% gcc final.c song.c math_functions.c -o final host% ./final total number of songs will be: 3 loop trip 0 loop trip 1 loop trip 2 the song is 223 seconds long and was made in 1998 the song is 303 seconds long and was made in 2004 the song is 315 seconds long and was made in 1992 combined length of song1 and song2 is 526 average length is: 280.333344 as a float and 280 as an int

Wrap Up

We've covered a lot of ground in a relatively small amount of space. If you understand the code in the final example, you should be ready to start learning the basics of Objective-C and Cocoa.

As you do more programming, you'll need to look into some more advanced topics such as pointers and memory management. Some starting points for those are listed below.

Theocacao: C Memory and Arrays
Theocacao: C Pointers and Dynamic Memory

Love it? Have suggestions? Send feedback on this tutorial.
 
Copyright © 2004-2015 Scott Stevenson
Made with TextMate
Feedback Form
Cocoa Dev Central is a servicemark of Tree House Ideas
Site design © 2004-2015 Scott Stevenson