C Tutorial: Learn C in 20 Minutes
By Huw Collingbourne for Udemy
Looking for more than a beginner’s guide? Check out Huw’s full C course.
Note: This post is part of our “Getting Started” series of free text tutorials on some of our most popular course topics.
To jump to a specific section, click the table of contents below:
A Quick Introduction to C
What You Need to Program C
Your first C project in CodeLite
Your first C project in NetBeans
Understanding a Simple C Program
Elements of the C Language
And finally…
A Quick Introduction to C
Even though it is now quite old, having been developed in the late 1960s, C is still one of the most widely used programming languages. The reason for C’s continued popularity is simple: it is a very flexible and powerful language that can be used not only to create ‘high-level’ applications such as word processors or games but also ‘low-level’ programs that interface with the computer’s hardware and memory. This makes it possible for an experienced C programmer to write very fast and efficient programs.
The downside of all this power is that C is a complex and, potentially, error-prone language. Many modern languages such as Java and C# provide built-in ‘safety nets’ to make sure that simple operations such as reading data into memory cannot easily crash your programs. However, C lets you do pretty much whatever you want to do. When you do something as simple as reading text entered by a user, it is quite possible that you will accidentally overwrite some piece of memory and cause your entire program to crash. So, in short, C is not a language for the faint-hearted. If you are a complete beginner to programming, C will provide you with many difficult problems that you would never encounter when using languages such as Java, C#, Pascal or Python. But knowledge of C will also give you a huge advantage over people who only know those more modern languages. A good C programmer simply has a deeper understanding of how computer programs actually work. And that is one reason why good C programmers are able to command high salaries.
The C language also forms the basis for languages such as C++ and Objective-C, which add an object-oriented ‘layer’ over C itself. In order to program those languages, you first need to understand C.
What You Need to Program C
Before you can write C programs, you need to install a text editor that supports C syntax. You also need a C compiler and an associated tool called a linker to translate your source code into machine code that can be run by your computer’s hardware. There are numerous free editors and Integrated Development Environments (IDEs) available for C. Two of the easiest to use are CodeLite and NetBeans. Both of these are available on multiple operating systems (Windows, OS X or Linux). They provide powerful C editors with an integrated C compiler and debugger. CodeLite can be downloaded from here. You can download NetBeans from here. For use with C, you must be sure to install either the C/C++ edition or the full (‘All’) release of NetBeans. If you are completely new to C and you are not already a NetBeans user, I would recommend starting with CodeLite, as it is a bit easier to install and it assumes that you will be programming in C or C++, whereas NetBeans supports a larger number of programming languages.
Your First C Project in CodeLite
If you install CodeLite, these are the steps you need to take to create, compile and run your first project that simply displays “hello world”.
- Select: File | New | New Project
- In the dialog (under Console) select: Simple executable (gcc)
- Click Next.
- Give the project a name, such as HelloWorld.
- Browse to choose a directory for this project (for example, C:\Test).
- Click Next. Click Finish.
You will see your new project in CodeLite’s WorkSpace panel. Click this to open up the src folder and load the file main.c into the editor. You will see that CodeLite has automatically written this small program:
#include <stdio.h>
int main(int argc, char **argv)
{
printf("hello world\n");
return 0;
}
To run this, just click CTRL+F9 or select Build and Run Project from the Build menu. This pops up a Terminal window that displays “hello world”.
Your First C Project in NetBeans
If you’ve decided to use NetBeans, these are the steps you need to take in order to create, compile and run a new project.
- Select File | New Project.
- Select the C/C++ category in the left pane of the New Project dialog.
- Select C/C++ Application in the right pane.
- Click Next.
- Enter a project name, such as HelloWorld.
- Browse to choose a directory for this project (for example, C:\Test).
- Make sure Create Main File is checked.
- Click Finish.
You will see your new project shown in the NetBeans Projects panel. Click to open up the Source Files folder and load the file main.c into the editor. You will see that, just like CodeLite, NetBeans has automatically written a small ‘hello world’ program. To compile and run this, select Run Project from the Run menu (or press F6). The output from this program is shown in the ‘Run’ tab of the docked Output window. If all goes well, this should display ‘hello world’.
Understanding a Simple C Program
Before going any further, let’s take a closer look at the ‘Hello world’ program. Although this is very short and simple, it illustrates many of the fundamental features of the C programming language.
#include
This is the first line of the program:
#include <stdio.h>
Here #include
is an instruction to the C compiler. It tells it to include the file whose name is specified between angle brackets. Here that file is called stdio.h and it forms a part of C’s standard code library. We need to include this file since it defines the printf()
function used in our program. The compiler would generate a warning if we forgot to include stdio.h. This will be explained more fully in the section on header files later on.
The main function
Now comes this bit of code:
int main(int argc, char **argv)
This is the ‘main function’: it is the first bit of code that runs when the program is started. In C the main function must be given the name main. The function name is followed by a pair of parentheses. The parentheses may contain two named arguments, arcg and argv, separated by a comma. Blocks of code, such as the code inside the main function, are enclosed by a pair of curly brackets. Note that each statement in C must be terminated with a semicolon:
justify;">printf("hello world\n");
return 0;
argc and argv
The arguments argc
and argv
in the main()
function may optionally be initialized with values passed to the program when it is run; argc
is declared to be of the type int
(an integer), while argv
is declared to be char
** which is an ‘argument vector’ or a pointer to an array of character-string arguments. If you are new to C, that probably sounds like gobbledygook. Don’t worry. For now, just think of argv
as a list of strings. I’ll have more to say about pointers later on.
To pass values to the program, you can just run the program at the command prompt and put any arguments after the name of the program itself, with spaces between each item. For example, if I wanted to pass the arguments “hello” and “world” to the program HelloWorld.exe (on Windows) or HelloWorld.app (on OS X), I would enter this at the command prompt or Terminal:
HelloWorld hello world
My program ‘receives’ those two bits of data, and it stores them in the second argument, argv
. The first argument, argc
is an automatically calculated value that represents the total number of the arguments stored in argv
. The current version of the HelloWorld program ignores any arguments passed to main()
. But try rewriting the code to match this:
int main(int argc, char **argv) {
int i;
for (i = 0; i < argc; i ) {
printf("Hello World! argc=%d arg %d is %s\n", argc, i, argv[i]); }
return 0;
}
Case-sensitivity
Be careful when you write C code. Bear in mind that the language is case-sensitive, which means that identifiers must always use the same mix of uppercase and lowercase characters. If an argument is called argc
in one place, it is no good calling it argC
or Argc
somewhere else. It must always be referred to using lowercase-only characters: argc
.
The block of code that starts with the keyword for
in the preceding example is a loop that causes the code that follows it, between the curly brackets, to execute for a certain number of times. Here the code executes for the number of times indicated by the value of the argc
argument.
The printf
function provides a useful way of embedding bits of data into a string using special place-markers: %s
prints a string; %d
prints an integer. You must be sure to put the same number and type of arguments after the string itself as the place-markers in the string. Here the string has two integer place-markers and one string place-marker:
\"Hello World! argc=%d arg %d is %s\\n\"
The printf
function substitutes the values of argc
, i
, argv[i]
, at the points marked by %d
, %d
and %s
in the string. At each turn through the for
loop, the string at the index i
in the argv
array is printed. The “\n
” at the end of the string adds a new line to it.
When you pass the program the two arguments: hello
and world
, this is the output which is displayed (notice that argument 0 is the name of the program itself):
Hello World! argc=3 arg 0 is HelloWorld
Hello World! argc=3 arg 1 is hello
Hello World! argc=3 arg 2 is world
Return values
When you declare an argument, it must always be preceded by its data type. That is why argc is preceded by the keyword int. The same is true for functions. If a function returns a value, the function must be preceded by the data type of the return value. The main function here returns an integer:
return 0;
That is why the main function has been declared using the type int:
int main(int argc, char **argv)
In this case, the return value 0 just indicates that no problems were detected. We don’t need to use this return value in this simple program. However, you will use the values returned by other functions, as we’ll see presently.
Elements of the C Language
Now that we’ve created, run and modified a simple C program, let’s examine in greater detail some of the core features of the C language.
Variables
Variables are identifiers to which values can be assigned. Each variable must be declared with a data type such as int
(integer) or double
(floating point number), and it can only be assigned values of the declared type. Here are examples of some variables:
int total;
double tax;
You assign values using the assignment operator = like this:
total = 100;
tax = 200.5;
Functions
Functions are named blocks of code. We’ve already seen the main
function. The C standard library contains many useful functions such as printf()
which we use by ‘calling’ the function by name. In a complete program, you would create numerous different functions. For example, you could write this function called add()
that takes two int
arguments, num1
and num2
and returns an int
value:
int add( int num1, int num2 ) {
num1 = num1 + num2;
return num1;
}
If you were to write this add()
function above the main
function in your program, you could call it by name, pass it two integer arguments and display the result. To do that, rewrite the main function as follows:
int main(int argc, char **argv){
printf("Result = %d\n", add(2,5));
return 0;
}
When a function doesn’t return a value, it must be declared using the keyword void
like this:
void sayhello() {
printf( "Hello\n" );
}
Mathematical operators
We’ve already used the addition operator + in the code sample above. Other mathematical operators include the multiplication *, division / and subtraction – operators. There are also ‘compound assignment operators’ that perform a calculation prior to assigning the result to a variable. This table shows some examples of common compound assignment operators along with the non-compound equivalent.
operator | example | equivalent to |
+= | a += b | a = a + b |
-= | a -= b | a = a – b |
*= | a *= b | a = a * b |
/= | a /= b | a = a / b |
When you want to increment or decrement by 1 (add 1 to, or subtract 1 from) the value of a variable, you may also use the ++
and --
operators. Here is an example of the increment (++) operator:
int a;
a = 10;
a++; // a is now 11
This is an example of the decrement (–) operator:
int a;
a = 10;
a--; // a is now 9
Tests and Comparisons
C can perform tests using the if
statement. The test expression must be placed between parentheses, and it should be capable of evaluating to tru
e or false
. If true, the statement following the test executes. Optionally, an else
clause may follow the if
clause, and this will execute if the test evaluates to false. Here is an example:
if (income > 1000000) {
bonus = 5000;
} else {
bonus = 500;
}
The > operator compares two values to test if the value on the left is greater than the value on the right. If you want to test if the value to the left is lower than the value on the right, use the < operator. To test if the two values are equal, use the == operator. Be careful that you don’t confuse the equality comparison operator == with the assignment = operator, which assigns the value on the right to a variable on the left. Here are some more comparison operators:
== // equals
!= // not equals
> // greater than
< // less than
<= // less than or equal to
>= // greater than or equal to
Switch statements
Switch statements let you perform multiple tests as an alternative to writing numerous if
and else
tests. A switch statement starts with the keyword switch
followed by an integer test value. This is followed by one or more case
statements, each of which specifies a value to be compared with the test value. If a case
value matches the test value, the code following the case
value and a colon (e.g., case 10:
) executes. Optionally, you may specify a default
which will execute if no match is made by any of the case tests. The following code shows a switch statement that tries to match an integer variable asciivalue
which represents the numeric ASCII code of a character. It assigns a descriptive string to the variable chartype
when asciivalue
is 0, 7 or 8. In all other cases, it assigns the string “Some Other Character” to chartype
.
switch( asciivalue ) {
case 0:
chartype = "NULL";
break;
case 7:
chartype = "Bell";
break;
case 8:
chartype = "BackSpace";
break;
default:
chartype = "Some Other Character";
break;
}
break
In a switch statement, all case
values will continue to be tested even after a match is made unless the break
keyword is encountered. That is why break
is placed after each case
test in the example above to ensure that the switch block is exited once a match is made.
for loops
Loops provide a way of running a block of code repeatedly. If you want to run code a fixed number of times, you could use a for
loop.
int i;
for( i = 0; i < 50; i++) {
printf(\"Loop #%d\\n\", i);
}
The code that controls this for loop
is divided into three parts. The first part initializes an int
variable, i
, with the value 0. The second section contains a test (i < 50
). The loop executes as long as this test remains true. Here the test states that the value of the variable i
must be less than 50. Finally, we have to be sure to increment the value of i
at each turn through the loop. That happens in the third part of the loop control statement (i++
) which adds 1 to i. When you run the code shown above, 50 strings are displayed, the first being “Loop #0”, while the last is “Loop #49”.
while loops
If you don’t know in advance how many times the code inside a loop needs to be run, you could use a while
loop. For example, if you want to keep prompting the user to enter something at the keyboard, you may not know in advance how many times you will need to show a prompt before the user enters valid data. Here’s a simple example that repeatedly displays “Enter y or n” until the user enters either the character ‘y’ or the character ‘n’. The character entered is assigned to the char
variable c
at each turn through the loop, and it is tested using the ‘not equals’ operator != and the ‘logical and’ operator && at each turn through the loop – so the while test here can be expressed as “while c is not ‘y’ and c is not ‘n’, run this code”:
char c;
c = \'x\';
while( (c != \'y\') && (c != \'n\') ) {
printf(\"\\nEnter y or n: \");
c = getchar();
getchar();
}
Logical Operators
In the code example above, I used the &&
operator to mean ‘and’. This lets me chain together conditions and test that all of them are true in order for the entire test to evaluate to true. If I wanted to test that any one of a set of conditions were true, I could use the ‘logical or’ operator || as in the example below, which executes some code if x is either less than 1000 or x is greater than 5000:
if (x < 1000) || (x > 5000) {
// run some code here
}
Comments
You can document your source code by adding comments that are ignored by the C compiler. Traditional C comments are placed between the delimiters /* and */ and may span many lines:
/*
* This is a traditional
* multi-line C comment
* */
Most modern C compilers also support single-line comments that begin with the // characters and end at the end of the line:
This is a single-line comment
Arrays
An array is a linear collection of elements of a specified data type. Each element has an index. The first element is at index 0. The last element is at the index given by the length of the array (that is, the number of elements) minus 1. An array can be declared with its type followed by its capacity between square brackets. This is a declaration of an array containing 5 integers:
int intarray[5];
You can index into an array using square brackets to obtain an existing element or assign a new value at a specified index. Here I assign 100 to index 2 of my array:
intarray[2] = 100;
An array can be initialized when it is declared by placing empty square brackets after the variable name and then assigning a comma-delimited list of values between curly brackets, as in this example:
int intarray[] = {1,2,3,4,5};
Strings
There is no string data type in C. What we call a string in C is really an array of characters terminated by a null ‘\0
‘ character. When you initialize a string variable, as shown below, C automatically adds a null at the end:
char mystr[] = "Hello world";
Constants
Sometimes you may want have an identifier whose value (unlike that of a variable) is never changed. In such a case, you should define a constant. The traditional way of defining a constant in C is to use the directive #define
followed by an identifier and a value to be substituted for that identifier, like this:
#define PI 3.141593
In fact, this is not a true constant since its value can be changed, as in the code below (though your compiler may show a warning message):
#define PI 3.14159
#define PI 55.5
Modern C compilers provide an alternative way of defining true constants using the keyword const
, whose values cannot be changed, like this:
const double PI = 3.14159;
Preprocessor directives
In the example above, #define
is a pre-processor directive. The C compiler includes a tool called the preprocessor that deals with special directives preceded by a hash #
character. Probably the most commonly used preprocessor directives are #define
to define constants and #include
to include header files.
Header files
A file with the extension ‘.h’ is called a ‘header file’. A header file typically contains definitions of functions and constants. The header file does not contain the implementation of functions – only their declarations. The implementations are generally contained in source code files that end with the extension ‘.c’. The declarations in a header file enable the compiler to perform various checks. For example, it can check that all the data types used by the function-calls in your program – that is, the types of the data returned from functions or passed to functions as arguments – are correct. When you include a header file, its contents are inserted into your code just as though you had cut and pasted them. The include file name is enclosed in angle brackets when it is a standard C library file:
#include <string.h>
The file name is put between double-quotes characters when it is in your working directory:
#include \"mystring.h\"
Pointers and addresses
Each piece of data in your computer’s memory is stored at some memory location or ‘address’. You can display that address using the ‘address-of’ operator &
placed before a variable name. Let’s imagine I have a string variable:
char str1[] = \"Hello\";
This is how I would display the addresses of str1:
printf(\"%d\\n\", &str1);
This would print a number which is the address in memory of the str1
array of characters:
2686746
In fact, an array variable such as str1
is itself equivalent to the address of the array, so even if I didn’t use the & operator, str1
would still give me the array address. If I were to enter this:
printf(\"%d\\n\", str1);
…the same number (that is, the address of the array of characters) would be displayed:
2686746
But let’s suppose I have another string declared like this:
char *str2 = \"Goodbye\";
Here the asterisk or ‘star’ * before the variable name indicates that str2
is not the array itself but is, in fact, a pointer to a memory location. Here it points to the address at the start of the memory holding the characters “Goodbye”. But unlike str1
(which was declared not as a pointer but as an array), str2
is not the address of the array of characters. It is a pointer or ‘reference to’ that address. So if I display the address of str2
using the & operator, I get a different address (the address of the str2
pointer variable) than if I display the address to which str2
points (the address of the array of characters). We can see this in the example below:
printf(\"%d\\n\", &str2);
printf(\"%d\\n\", str2);
This will display two different numbers, such as:
2686740
4206628
Pointers are one of the most difficult-to-understand features of the C language. The fact of the matter is that most modern object-oriented languages make very little, if any, explicit use of pointers. Even so, that doesn’t mean that languages such as Java, C# and Ruby do not, in fact, use pointers. Pointers are used all the time whenever any computer program runs. Many languages manipulate them ‘behind the scenes’ – for example, by placing an object at a memory location and automatically creating a variable that ‘points to’ the object. The programmer uses the object without ever having to know anything about the address in memory where that object is stored.
The downside of pointers is that they are not only difficult to use, but can also be dangerous. To take a simple example, a pointer lets you poke bits of data into memory that might already contain some other data. That can cause memory corruption, which could crash your program.
While the avoidance of explicit pointer manipulation makes programming simpler and less hazardous, it also makes it difficult for the programmer to interact directly with the computer’s hardware and memory. Sometimes, for maximum speed and efficiency, or when creating low-level programs such as device drivers and operating systems, direct memory-addressing using pointers is invaluable. That is one reason why, despite competition from more modern and user-friendly computer languages, C continues to be one of the most widely used and important of all programming languages. It also explains why really good C programmers (who are capable of writing robust C programs that don’t crash) are so highly valued.
And Finally…
This tutorial has been a very quick overview of C. It certainly won’t explain everything you need to know in order to write good C programs, but I hope it has given you an understanding of the core features of the C language and helped you to understand why C is one of the most enduring of programming languages.
Recommended Articles
Top courses in C# (programming language)
C# (programming language) students also learn
Empower your team. Lead the industry.
Get a subscription to a library of online courses and digital learning tools for your organization with Udemy Business.