The Definitive Guide to Learning C

Welcome to this definitive guide where we’ll teach you about the C programming language – as well as get you started with learning how to code with it!

C is consistently ranked as the #1 or #2 programming language, so you can be sure this information will help you find success in your hobbies or careers with a newfound, well-appreciated skillset.

If you’re ready to discover the world of C programming, let’s get started!

(Want to jump straight to learning? Use our Table of Contents to head straight to the C Learning Resources section!)

What is C? Overview & History

About Computer Programming Languages in General

Before we jump into what C is, let’s take a step back and understand what a programming language is in general.

Without going too in-depth, which you can read more about elsewhere, all computers operate based on electrical signals – primarily whether a signal is on or off. If we assign a value of 0 or 1 to these electrical signals, and give sequences of those meaning, we get what is known as binary. Binary makes up the bulk of what is called the machine code.

But for humans, machine code is not a great way to program. Instead, we developed computer programming languages, which are languages that, while being more human-readable, are able to translate into machine code. Thus, through this intermediary step, we’re able to speak a common language with the computer.

Computer from the 1970s

About the C Programming Language

So what is C?

C is a general-purpose, procedural programming language that was created as a successor to the B programming language. Developed by Dennis Ritchie and Bell Labratoriess in 1972 (yes, that long ago), the primary purpose of the language was to be able to develop functions for the first iteration of the UNIX operating system- which was developed by Ken Thomson, the original creator of the B programming language.

Since its birth, C has gone on to become a mainstay of the industry – and is in fact quoted as the most widely used programming language across all technology.

What is C Used For?

Given its age, you may wonder what C is even used for, though, especially in our modern space.

C is considered one of the lowest level languages – meaning that it was built to be extremely close to machine code. Consequently, C is able to translate very quickly into what the computer actually needs in order to operate (in other words, it’s very machine readable).

Due to its low-level nature, C has become one of the primary bases for core technologies that make our computer run – including operating systems, compilers (which many other programming languages need to work), and even large-scale databases. Without these elements, technology would not even be where it’s at, so to say C is a powerhouse is an understatement.

Regardless, though, C isn’t going anywhere, and still provides tons of value in how we program everything else for our computers.

Vector illustration of a monitor with operating system

How Does C Compare to Other Languages?

The next step in our quest to understanding C is to explore how it compares to other languages. There are a lot of other programming languages out there to learn, so what does C have that others don’t?

C has low-level memory management capabilities

For the average beginner programmer, accessing memory is generally an abstract concept that, for many projects, won’t ever matter.

However, for those pursuing software engineering and the like, having this ability has resounding implications. C comes with pointers, which essentially allow programs to directly access and modify memory as a program is used.

What does this mean, though? Well, in the larger scheme this means that programmers have a more direct method of interacting with the hardware. This brings C even closer to machine code when done properly, and can consequently have some great performance boosts.

C is almost as efficient as you can get

In conjunction with the above, C is a very efficient programming language as well because of how low-level it is.

What does this actually mean though? Unless you’re literally going to code in machine code, your program has to go through extra “translation” steps in order to render it useable. The closer a language is to machine code, the better and faster this “translation” is, resulting in the computer executing the code that much quicker.

C is not just low-level, but one of the languages closest to machine code. This is not only why it’s used for things like operating systems where speed is essential, but also why many languages have an extra step of being translated into C¬†before¬†they go to machine code. It is worth noting too that C is primarily a compiled language, so comes with the extra benefits of that as well. Either way, C is a performance powerhouse when you look at the overview of all languages.

Other programming languages are based on C

C is, more or less, one of the grand-daddies of programming. Its creation had sprawling effects across the industry, and you wouldn’t be wrong to say it has shaped the industry at large in ways we still feel the effects of.

Since it is so old, then, you shouldn’t be surprised to learn that C is the main inspiration behind many of our modern-day programming languages that you might be more familiar with.

Sometimes this influence is very direct. For example, C++ and C#, both immensely popular languages in their own right, were more or less directly based off of C. While, of course, they aren’t the same as many changes were made – such as adding more object-oriented programming principles – the similarities between the two are very obvious in their syntax!

Other languages, though, have a more indirect influence. For example, Java, JavaScript, and PHP all took a lot of elements of C, including some elements of the syntax, and worked it into their own language development.

While this doesn’t mean you shouldn’t learn other programming languages, as all languages have their pros and cons, knowing that C helped in their creation is a valuable piece of knowledge. It also means that C isn’t as unfamiliar as you might think – especially if you already know a language like C++.

Various books on programming on a shelf

Why Learn C?

Hopefully, you understand more about how C differs from other programming languages and why its efficiency is a key benefit. However, why is it worthwhile to learn? Well, let’s talk about that.

C is a very popular language and is a great skillset

We’ve mentioned this a few times already, but it is always worth repeating. C is one of the most widely used languages and is usually ranked in a top spot on any programming list.

For example, the TIOBE index we mentioned earlier historically ranks it as the #1 or #2 language every month and year (competing most usually with Java). Meanwhile, the PYPL index, a competitor to TIOBE, places C (bundled with C++) as one of the top 5 programming languages.

Why does this popularity matter? Well, in general, it’s a good indication of what skillsets people are looking for in the industry. While this might not matter as much for hobbyists, career-minded individuals may want to take note.

Even if in your career you’re not looking to specialize in C, having it on your resume will still be a plus. It shows any company that you not only have a well-rounded set of skills, but are intimately familiar with language skills that they may one day need. So, the demand for this skill is more than enough to show how important it is.

C is generally required for higher-level software engineering careers

Software engineering is a vast field that can involve quite a few areas. This can, of course, include software, but many senior software engineers will be in charge of programming systems and software that support interaction with computer hardware.

As we’ve established, systems development is a specialty of C and is commonly a company’s choice for this sort of programming. Thus, it shouldn’t be any surprise that senior software engineers tend to be the people who know C.

Of course, there are always exceptions to the rule – and you’ll definitely find situations where a company won’t require any knowledge of C for their software engineering positions. That being, it is more common to find C as a requirement – or at least an unspoken bonus that will get you picked over other job candidates.

If you want to aim high with a career in software development, C is more or less a must.

Man standing at white board while other man takes notes on laptop

Taking the time to learn C pays off (literally via your salary)

Despite C’s popularity in just about everything, it is still not a language every developer secretly knows. C++, Java, and Python skills are readily come by in job candidates, but C often gets left by the wayside – especially for people who are first learning.

Due to this, plus the fact that C does require training to use, salaries for people who know C are quite high.

For example, the following sites quoted these average salaries for a C programmer in the US (your mileage may vary in other locations):

However, this is not the ceiling – just the average. For example, a Senior Software Engineer on average earns $116K according to Payscale – and as established, these positions generally require knowledge of C.

All in all, knowledge of C can really benefit you in terms of what you can negotiate with!

Despite everything, C is still easy to learn

With all this talk of being low-level and close to machine code, you might be under the impression that C is a difficult language to learn and equivalent to studying some language from another planet.

Thankfully, this is not the case. While there are differences given that C was not designed with object-oriented programming in mind (which is the principle for most languages these days), many of the aspects of C are common in modern-day programming. You’ll still find similar syntax, the same sorts of keywords (like if/else), and more – so the coding fundamentals are more less the same as any other popular language like Java.

Though admittedly C is not as easy as a high-level programming language like Python, it really isn’t any harder than learning C++. Plus, with as popular as the language is, there are tons of resources (which you can find below), to dive into learning C.

If you learn C, you can really learn a ton of other languages

Briefly, remember how we said C is more or less the basis for a lot of other modern-day languages? Well, this has a benefit in that, if you learn C, you can learn any other language you could want.

This is actually more important than we’ve touched on before. If you have your sights on a programming career, knowing one language is usually not enough. In fact, most companies will expect you to know a few languages. So, having a language you can use to jump off of into other languages will only serve you greatly in the long run.

Cloud with numerous languages named

Resources to Learn C

Now we get the part you’ve been waiting for, how do you learn C? First, we’re going to cover some of the most basic principles you can find in any language – though briefly just to give you a taste. Then, we’ll get you a list you can pick and choose from to find the best resource to learn C from which will cover each topic more in-depth and much, much more!

C Coding Examples

Let’s dive into how you can do some of the most basic programming features of C. While there is more to learn of these basics than we’ll cover here, this should hopefully get you ready to dive more thoroughly into these topics!

Hello World

“Hello World” is where every programmer should start when learning a language. In essence, this first “program” is to get your feet wet and show you how to actually output your code into something meaningful. To do this in C, we just need to do the following:

// This gives us access to a few specific functions (discussed more below), like printing a statement to the console
#include <stdio.h>

// When the program starts, this is the default established place that the program needs to start
int main() {
    printf("Hello World"); // This says to the program, hey, print this to the console.
}

And that’s it, your first program is already done. Of course, this is no epic game or useful software, so let’s explore a few more concepts.

Variables

Whenever you want to store data in a program – whether that be a name, a number, or something else, you need to use what’s called a variable. In order to use variables, though, we first need to declare them. In C, this is done with the simple format seen below:

// Variable Format: datatype variablename = value; 

int myNumber = 1; 

char myCharacter = 'z'; 

float myDecimalNumber = 1.1;

We can store just about anything with a variable, however, in C, there are few things to keep in mind when using variables.

  • C variables are strongly typed. This means once you declare the data type (integer, float, etc.), you can’t change it.
  • C variable names can only consist of numbers, letters, and underscores.¬† Additionally, your variables should always begin with a letter or underscore, not a number.

While you can’t change the data type, you can easily assign a different value.

int myNumber = 1; 
myNumber = 2;

Furthermore, C has the ability to use constants. This means you can create variables that can store data but whose values you can never change – protecting it from unwanted reassignment. This is done as easily as adding the keyword “const” before your variable declaration.

// Constant Format: const datatype variablename = value; 

const myNumber = 2; 

// If you try to change it, such as below, this will throw an error. 
myNumber = 3;
Woman with VR google on in front of code panel
Operators

Your data is stored, but how do we manipulate our data in its simplest form? This is where we bring in operators. These symbols allow us to perform some standard “operations” common in all programming languages. Essentially, computers are good at math and evaluating math, so why not use it?

Operators come in a few different forms. The most standard most people are familiar with is the standard arithmetic operators, which involve doing common mathematical calculations like addition, subtraction, and so forth.

int firstNumber = 4; 
int secondNumber = 2; 

int result; // Note that you do not have to declare a variable at the start! 

// Addition 
result = firstNumber + secondNumber; 
// Result = 6 


// Subtraction 
result = firstNumber - secondNumber; 
// Result = 2 


// Multiplication 
result = firstNumber * secondNumber; 
// Result = 8 


// Division 
result = firstNumber / secondNumber; 
// Result = 2 


// Modulo (Returns the Remainder of Division) 
result = firstNumber % 3; 
// Result = 1

We also have assignment operators – which you’ve already seen above already when we assigned a different value to our variable with the “=” sign. However, we can combine these with our arithmetic operators to perform an operation and assign the result to the variable at the same time. Note in the example below, the firstNumber result is based on each line individually, not the entirety of the set of code.

int firstNumber = 4; 
int secondNumber = 2; 

// Addition 
firstNumber += secondNumber; 
// firstNumber = 6 


// Subtraction 
firstNumber -= secondNumber; 
// firstNumber = 2 


// Multiplication 
firstNumber *= secondNumber; 
// firstNumber = 8 


// Division 
firstNumber /= secondNumber; 
// firstNumber = 2 

// Modulo (Returns the Remainder of Division) 
firstNumber %= 3; 
// firstNumber = 1

Besides doing standard math operations, though, you can also use relational operators to evaluate a particular statement for whether it’s true (1) or false (0) – something very useful which we’ll explore later.

int firstNumber = 4;
int secondNumber = 3;

int result;

// == : Checks if two values equal each other
result = firstNumber == secondNumber;
// result is false (0)

// != : Checks if two values DO NOT equal each other
result = firstNumber != secondNumber;
// result is true (1)

// > : Checks if the value on the left is greater than the value on the right
result = firstNumber > secondNumber;
// result is true (1)

// < : Checks if the value on the left is less than the value on the right
result = firstNumber < secondNumber;
// result is false (0)

// >= : Checks if the value on the left is greater than OR equal to the value on the right
result = firstNumber >= secondNumber;
// result is true (1)

// <= : Checks if the value on the left is less than OR equal to the value on the right
result = firstNumber <= secondNumber;
// result is false (0)

There are also logical operators as well, which can be used to specify multiple variables to check, or even used to check for the opposite condition.

int firstNumber = 4;
int secondNumber = 3;
int thirdNumber = 2;

int result;

// AND: &&
// With &&, both expressions MUST be true for result to be true
result = (firstNumber > secondNumber) && (thirdNumber > secondNumber);
// result is false (0)


// OR: ||
// With ||, either expression can be true for result to be true
result = (firstNumber > secondNumber) || (thirdNumber > secondNumber);
// result is true (1)



// NOT: !
// With !, we reverse whatever the result is in the evaluation
result = !(firstNumber < thirdNumber);
// result is true (0)
Illustrated man sitting at computer
Arrays

What happens when you want to store multiple values into a single variable? This is where we come to arrays. Arrays are as simple as they sound: variables that store multiple pieces of data. This being said, keep in mind the following:

  • Like regular variables, you can’t change the data type. If you have an array of integers (int), for example, you can’t just go adding characters to it.
  • Once declared, an array’s size cannot be changed.
  • You can either declare your array with initial values or add them later.

The above being said, how does one declare an array? Let’s look!

// Array Declaration Format: dateType arrayName[sizeOfArray]

// Empty array with no values
int nums[4];

// Array with values; Can be used later to add values to empty array
int nums[4] = {1, 2, 3, 4};

Let’s say you created your array, though, and now you want to access a specific element. You can access elements in the array by what’s called an index. Indexes are simply number values that correspond to an element’s position in the array. The important thing to remember with arrays in C, though, is that indexes start at 0. As such, the first element (from our example above, 1, is index 0, NOT index 1).

We can see below the format for using this concept.

int myNumber;

int nums[4] = {1, 2, 3, 4};

// Accessing an item: arrayName[indexNumber]

myNumber = nums[0];
// myNumber = 1

// We can also use the same method to assign new values
nums[3] = 5;
// Instead of 4, the last element (index 3) is now 5

Note when accessing array elements, using an index outside the bounds of your array will result in out-of-bounds errors.

Conditionals & Control Statements

Next, we’ll discuss conditionals (or sometimes called control statements), the first step into actually making program logic. As the name implies, conditionals are expressions (i.e. conditions) that are evaluated and determined to be either true or false. If the condition is met (true), then the program proceeds down a particular chain of logic. If it’s not met (false), then the program does something else depending on how the conditional is set up.

When creating these expressions/conditions, they are compatible with most of the operators we previously mentioned, so you can go about a number of ways crafting these conditionals. While there are a few styles of conditionals, we’re going to talk about the most basic in these examples: the if…else statement.

By specifying an if in our programming logic, we can tell our program to perform a certain action only if that condition is met. If the condition is not met, the program simply continues down the chain in the programming logic.

int firstNumber = 4;
int secondNumber = 2;

int myNumber;
int result;

// Here, we're test if firstNumber greater than secondNumber using the format below;
if (firstNumber > secondNumber) {

    myNumber = firstNumber; // If the above is true, we set myNumber to firstNumber
};

result = (myNumber == firstNumber);
firstNumber = 1;

if (firstNumber > secondNumber) {

    myNumber = firstNumber; // If the above is true, we set myNumber to firstNumber
};

result = (myNumber == firstNumber);

// Result: 
// In the first conditional, which is true (4 > 2), myNumber is set to 4.
// The program continues after this normally and sets result to true (1) since myNumber = firstNumber.
// Continuing, the program then sets firstNumber to 1.
// In the second conditional, which is false (1 > 2), myNumber is left as 4.
// The program continues and result is now false (0) since myNumber (4) DOES NOT EQUAL firstNumber (1) anymore.

However, what if there is something else we might want to perform only if the first condition is false? For this, we can use an else if statement to test for something else.

int firstNumber = 4; 
int secondNumber = 2; 

int myNumber;
int result;

// Here, we're test if firstNumber equals secondNumber using the format below; 
if (firstNumber == secondNumber) { 
    myNumber = firstNumber; // If the above is true, we set myNumber to firstNumber 
}
// Only if the above is false, we'll test this statement
else if (firstNumber > secondNumber)  {
    myNumber = secondNumber;
}

result = (firstNumber > myNumber);

// Result
// Our first if statement is false (4 = 2), so the program proceeds to check the else if statement in the chain
// Our else if statement is true (4 > 2), so myNumber is set to 2.
// Since the program continues running, result is set to true(1), since firstNumber (4) is greater than myNumber (2)

We can also use an¬†else¬†statement, which is a catchall that runs if all previous if and else if statements (if present) result in false. While not required, this is useful in situations where you need to make sure specific actions are taken (for our example, perhaps myNumber needs a value so an error isn’t thrown.

int firstNumber = 4; 
int secondNumber = 2; 

int myNumber; 
int result;

// Here, we're test if firstNumber equals secondNumber using the format below; 
if (firstNumber == secondNumber) {
    myNumber = firstNumber; // If the above is true, we set myNumber to firstNumber
}
// Only if the above is false, we'll test this statement
else if (firstNumber < secondNumber) {
    myNumber = secondNumber;
}
else {
    myNumber = 1;
}

result = (myNumber == 1);

// Result
// Our first if statement is false (4 = 2), so the program proceeds to check the else if statement in the chain
// Our else if statement is also false (4 < 2), so the programm proceeds to the next step in the chain.
// Since there are no further if or else if statements to run, the else statement is run and myNumber is set to 1.
// Result is set to true (1) since myNumber (1) does equal 1.
Screenshot of while loop and conditional code base
Loops

The next step in “program logic” is loops. Loops are closely tied to conditionals and used whenever you might need to run some block of code a few times. Essentially, with a loop, we check a condition, and if it’s true, we run a piece of code. Then, as the name implies, the condition is checked again. If the condition is true, the code runs again. If it’s false, the loop ends. You can have loops run as many times as you need, so they’re an incredibly powerful tool when used correctly.

When it comes to C, there are a few different types of loops. The first type, for loops, are great when you have a specific number of times you want to loop through your code. A for loop’s condition consists of three main parts (generally speaking): an optional initial variable to control the number of iterations, a conditional, and a¬†value of incrementation (This value is very important as it’s needed to prevent the loop from running indefinitely).

// Loop Structure
// for (initialVariable; conditionalExpression; increment) { Code }

int firstNumber = 1;

for (int i = 0; i < 10; i++) {
    firstNumber++;
}

// Result
// The above loop starts with an initial variable (i) of 0.
// Then it checks if i is < 10. Since it is, we add 1 to firstNumber.
// Then the increment is evaluated, and in this case we increase i by 1.
// The loop runs again. i is now 1, and since this is less than 10, we add another to 1.
// The above continues to happen until i is equal to or greater than 10, at which point the code continues down it's path normally.
// By the end, here, firstNumber will equal 11

The other types, which we’ll group together, are while loops and do… while loops. In some cases, you might not have any clue about the number of times you need to loop through a piece of code. This is where these two loop types come in, as they allow us to simply evaluate a conditional, and while¬†that conditional is true, the code will be run.

While these two loops are mostly functionally the same, there are two keys differences. First, both are formatted a bit differently, as we’ll explore in a minute. Second, and more importantly, a while loop only runs if a statement is true, so it’s possible it will run 0 times. A do… while loop, on the otherhand,¬†always¬†runs at least once, as it checks the conditional after running the first iteration of the statement, not before.

With that out of the way, let’s look at a brief example of a while loop.

// While Loop Structure 
// while (conditional) { code }

int firstNumber = 1;
int secondNumber = 10;

while (firstNumber < secondNumber) {
  firstNumber++;
}

// Result
// Our while loop starts by evaluating the conditional.
// Since firstNumber (1) is less than secondNumber (10), we add 1 to firstNumber.
// Since this is all our code, we restart the while loop and evaluate the conditional again.
// This loop will run until firstNumber = 10 in this case, at which point we exit out of the loop and continue.

Pretty simple, right? Well, fortunately, do… while loops are hardly less complicated.

// Do... While Loop Structure 
// do { code } while (conditional);

int firstNumber = 1; 
int secondNumber = 2;

do {
    firstNumber++;
}
while (firstNumber <= secondNumber);

// Result
// In this case, we immediately start by adding 1 to firstNumber, since this statement comes first.
// Next, the program tries to decide if the conditional is true. If it is, it will run again.
// In this case, firstNumber is 2, so equal to secondNumber. Thus, we add another 1 to firstNumber.
// firstNumber then becomes 3, making the while loop false. As such, the program continues on.
Functions

The last example we’re going to give is, well, the heart of the program logic. Functions are blocks of code that we can call at any time in our program to perform a specific task. And we do mean just about any task.

In fact, you’ve already seen two functions in action: int main() and printf(). As mentioned earlier, int main is the entry point for all functions, and printf() is a built-in function that comes with the stdio.h library and explains how to show output in the console.

However, you can declare your own functions in the program. This is fairly simple as long as you remember the following:

  • Every function needs a¬†return type, i.e. what is the expected output? If you specify an¬†int, for example, the function is waiting for a return of an int value. On the other hand, you can also use¬†void¬†which specifies there is no return expected.
  • While optional, many functions can take parameters (usually variable data). These parameters can then pass along data to that function to use.
  • Once defined, you can use the function name to call the function at any point.

Let’s first look at making a simple function with no returns or parameters.

// Function format: returnType functionName (parameters) { code }
#include <stdio.h> 

// Here we make a void (no return) type function called multiply
void multiply () {
  // We set result to this multiplication problem
  int result = 4 * 2;
  // And then we print the result
  printf("%d", result);
}

// Remember, this is where our program enters
int main() { 

// Here we call the function, and voila, we print out 8!
multiply();
}

While we only called the above example once, you can call functions multiple times. When you incorporate parameters, this makes them especially powerful.

#include <stdio.h> 

// In this example, we take in a single int parameter, then multiply that parameter to get our result
void multiply (int x) {
  int result = x * 2;
  printf("%d", result);
}

// Here we send 1 to our function, and it prints 2 (1 * 2)
int main() { 
int myNumber = 1;
multiply(myNumber);

// Here we change our myNumber data, send it to our function again, and it prints 8 (4 * 2)
myNumber = 4;
multiply(myNumber);
}

Of course, you can simplify things further by using return types to transfer data back and forth between various parts of your program.

#include <stdio.h> 

// This function returns an int, so we NEED to include the return statement
int multiply (int x) {
  return x * 2;
}

int main() { 
int myNumber = 4;
int result;

// Because we get a return from our function, we can store the value here
result = multiply((myNumber));
printf("%d", result); // As expected, our result prints 8
}

Man in front of green background at a computer

C Learning Materials

We’ve covered the most fundamental of the fundamentals, but there’s a lot more to learn – such as how to handle data structures for more complex C programs, how to use pointers, how to deal with user input, how to utilize memory management features, how to make custom data types, and so forth. However, with the basics above, you should be more than ready to dive further into C and learn both the coding fundamentals and language syntax!

Bonus: Learn C++ Too

C++ is closely related to C, and it’s often considered a standard language to know as a companion. As a bonus, we also wanted to include some learning resources for C++ so that you could further cement more programming knowledge for the future.

Ending Words

Overall, C is a fantastic computer programming language. It’s efficient, can help you learn other programming languages, and can have a wonderful impact on your career goals. Though it’s been around for nearly forever in terms of computers, it still continues to prove its worth even in the current day.

However, the learning doesn’t stop here, and there are more programming skills with C to learn. We recommend first by building your own simple C program, which is always one of the best ways to learn any sort of computer programming language. We also encourage you to explore more about computer science so you can learn why C was an important milestone for developing things like operating systems.

Whether you’ve just had a passing interest in it, or need to learn it to boost your job skillsets with newfound programming skills, we hope you’ve had a great experience learning about the language and now know where you can go next to start learning it. We wish you the best of luck in your programming adventures!

BUILD GAMES

FINAL DAYS: Unlock 250+ coding courses, guided learning paths, help from expert mentors, and more.