Introduction
By Shodan. December 9th, 2019. 2:26 PM
Check the guide's index here.
Welcome to World of Programming with C!
This guide will present you with all the characteristics of a real programming language - The C Programming Language.
Tips and tricks used by more experient programmers will also be presented through multiple explained and commented examples.
Although one of the main characteristics of C is its portability, there are, however, limitations associated to the different types of machines (hardware) existent in the market. It's not exactly the same thing to write code to execute on a microcomputer or to execute on a multi-user or multi-process machine. Either way, the examples presented in this guide will try to base themselves on ANSI C, as a way to guarantee it functions in any hardware architecture.
A Brief History of C
Although it has a somewhat weird name when compared to other 3rd generation languages, like Fortran, Pascal or Cobol, the C Language was created in 1972 at the Bell Telephone Laboratories by Dennis Ritchie and had the finality of allowing the writing of an operating system (Unix), utilizing a relatively high level language, avoiding he usage of Assembly.
Due to its abilities and through the spreading of the Unix system through U.S Universities, the C Language quickly left the doors of the Bell Laboratories, spread around and became known by all kinds of programmers, independently of the projects in which they were involved, having the book "The C Programming Language" by Kernighan & Ritchie the only common link existent between programmers.
This dispersion led to different organizations developing and utilizing different versions of C, creating some problems of portability and more. Standing before such as state of things, and since C had become a true phenomenon between programmers and organizations, the American National Standards Institute (ANSI) formed a comitee to the defining of a standard for the C Language, a standard which would allow similar function of all language compilers, with very precise specifications as to what the language should do or not, its limits, definitions, etc.
The name of the language (and the language itself) resulted of the evolution of another programming language, developed by Ken Thompson also in the Bell Laboratories, which was named B. This way, it's perfectly natural that the evolution of the B Language would become the CLanguage.
1001 Reasons to Program in C
Behind such a colossal deck of available programming languages in the market, you'd need one of them to contrast a lot from others in order to interest such a big slice of the whole programmer community.
Most languages have an objective to achieve:
- Cobol - Record Processing
- Pascal - Teaching of Programming Techniques
- FORTRAN - Scientific Calculations
- LISP and PROLOG - Made for the areas of Artificial Intelligence
- ...
As for C, which area of development does it walk towards?
The answer is - none in particular. It's what is usually called general purpose, and this is one its great advantages, because it adapts to the development of any project, like operating systems, graphical interfaces, record processing, etc. Incredibly, C is also used to write compilers for many other languages.
C is an extremely potent and flexible language.
Speed - With C, you can obtain similar performance as the one obtained from Assembly, using high level instructions, i.e., instructions similar to the ones used by languages like Pascal or COBOL even to acces low level mechanisms, like memory addressing or bit manipulation.
Simple - Its syntax is extremely simple, and the number of reserved words, basic data types and operators is diminished, reducing the quantity of time and effort needed to learn the language.
Portable - There's a standard (ANSI) that defines the characteristics of any compiler. This way, the code written in one machine can be transported to another machine and compiled without any alterations (or at least with a reduced number of changes).
Popular - It's internationally known and used. It's very well documented in books, specialty magazines, manuals, etc. There are compilers for all kinds of architectures and computers.
Modular - C allows the modular development of applications, making the seperation of projects in distinct and independent modules easier, recurring to the usage of specific functions inside of any module.
High Level - C is considered a 3rd Generation Language (like Pascal, COBOL, BASIC, etc.) - commonly called High Level when compared to Assembly. C also allows access to most of Assembly's functionalities, using high level expressions and instructions.
As an example: it is possible to manipulate memory directly, using the address of any object (be it a variable or a function), manipulating directly the memory without any kind of restrictions, which increases the language's flexibility.
Very powerful libraries - The fact that C contains a reduced number of keywords indicates that the abilities of C are very limited - and in fact, they are. Most of the language's functionalities are added by the usage of functions existent in additional libraries and that execute all kinds of tasks, from writing characters on the screen, to processing strings and more.
Macros - C has the possibility of using macros in the development of applications, reducing the necessity of writing distinct functions for usage in the same process, for different data types. Macros allow runtime to decrease without increasing code complexity.
Focus - The C Language allows a programmer to write code just the way he wants to. A program can be all written in one line or spread through numerous lines.
The way code is written depends unically from the programmer's taste. He only has to worry with the objective and the correction of the application he's developing, in order to obtain the desired result in the end. It doesn't require formatting the code from column x and the data from column y like what happens in other languages.
Evolution - C is a particularly stable language. The evolution of languages made C to also evolve in the way of Object Oriented Programming, originating the C++ Language, which keeps the C syntax and allows an additional set of caracteristics (encapsuling, inherity, polimorphing, overloading, etc.)
At the moment, Java presents itself as a new extended work base for programmers. It's also based on C and C++.
C Programming Philosophy
C is a language that reflects a bit of the Unix philosophy, incorporating some of its characteristics, like case sensitivity.
The Unix operating system has a wide set of commands, being each of them responsible for executing one only task.
If you need to execute some complex task, you can use a set of Unix commands, chaining them through pipes and other communication structures, this way obtaining the desired result.
This way, the chance of the task being accomplished with deficiencies is less than to be resolved with only one command, since a complex program's complexity is bigger than the sum of the complexities of the sum of all of the small programs that constitute it.
What I'm trying to say is that it's easier to implement small pieces of code that execute one unique function well than to produce big quantities of code that utilize a wide set of conditions, variables and exceptions in order to produce the same result.
This way, a project must be divided in modules.
Each module must be implemented in a way that makes it independent from other modules, reducing the preocupation we may have with the module we may be trying to implement at that moment.
Each module, at its turn, must be split in the diferent components that constitute it. Each component will be then subdivided in a way to ease its implementation until each one of them executes only one function, being easier to implement correctly and contributing to the whole, reducing development time and future maintenance.
C Versus C++
But the C Language's development didn't stop, and soon emerged the C++ Language (initially called C with Classes), with a completely diferent philosophy from the C Language, but using its basic characteristics - syntax, functions, data types, operators, etc.
The C Language is a subset from the C++ language. This means C++ contains all the characteristics from the C Language and an additional set of personal characteristics. Through this way, you can use a C++ compiler to test the examples present in this guide.
In any casy, it's adamant to be proficient in the C Language to be able to jump over to C++.
An Application's Development Cycle
Traditionally, an application's development cycle encompasses 4 distinct phases:
-
Writing the Source Code
In this phase, all of the work is executed by the programmer, who must write the code in files with the extension .c (i.e.: prog31.c).
-
Compiling the Program
Once the program's code is written, the first step to take is to verify if it was correctly written (if the instruction syntax is correct or not).
This process, called Compiling, is executed by the Compiler. In the case some error gets detected, the compiling process is terminated. The programmer must return to square one, to correct, in the code, the error found by the computer.
The compiler may also detect situations that are not erros, where the syntax is correct but raise some suspicions. In this case, it continues compiling, but emits a Warning to each suspicious situation.
In the case no errors are detected (independently of emitting Warnings or not, the compiler creates an object file , with the name of the program and an .OBJ (In DOS) or .o (in Unix).
To compile a program in the command line, you must write:
In Unix based systems:$ gcc 'filename'
In a DOS prompt:C:\exampleDir\> gcc 'filename_path' -
Linking the Objects
The compiling phase serves only for a syntax verification and to create the object file. The actual executable is created from the object file, obtained through the compiling phase and through libraries (.lib in DOS and .a in Unix), which contain pre-compiled code with C's own functions (like printf(), scanf(), etc.) that are necessary for the final executable to function properly (in DOS, they usually end in .exe - standing for executable. In Unix based systems, they have no extensions and are called binaries).
This phase allows to link everything in just one executable any object files it needs, even if they have come from different language compilers.
However, the linking phase will fail if some symbol or function used by the program isn't found by the linker either inside the object code or inside the libraries. In this case, the executable file is not created.
In general, when you compile a program with an external compiler (command line), this one does the entire Compiling and Linking processes in one go, producing the executable/binary in just one stroke. If you do not wish for the compiler to link it after compiling the code, it has options that allow you to only compile code into object files.
In the case of Unix environments, the executable file always has the name a.out by default, which results in each new compiling deleting the last project's binary.
To create a binary with a name other than a.out, you'll need to use the -o option, followed by the name you want to give your executable.
$ gcc 'filename' -o 'output' -
Executing the program
After the linking process successfully ends, we now have, available for us, the executable/binary file. If it's executable, we'll execute it. You can just type it's name in DOS
C:\exampleDir\> outputFile
For Unix, you'll need to give it permission to execute before actually running it.
# chmod 755 outputFile $ ./outputFileIf the program does not do what it's supposed to do, then that's because the weakest element of this whole process (the programmer) has made a mistake. So, dig back into your prefered text editor, check your source code, edit it and prepare to compile and link the code all over again.
Note: The App Development Cycle described above is true for most languages. However, C adds another phase before Compiling, whose objective is to expand all the macros and execute all of the code meant to be executed by the pre-processor. More information about this phase can be obtained in the Macros Chapter.
The Anatomy of a Guide
In this guide, I'll present multiple examples of small programs written in C.
At the start of every chapter, I'll leave a small summary of the set of topics I will mention in that chapter.
If it's possible, a program's code will always be present to exemplify the theory behind it. Each program will be named using the terminology prognnkk.c, in which nn represents the chapter to which the program belongs to, and kk the number of the program in said chapter.
For example, prog0305.c is the 5th program presented in the 3rd chapter of this guide, and vice-versa.
Programs will almost always be presented with the same look - the program's name being presented on its header.
prog0103.c
1: #include <stdio.h> 2: 3: int main(){ 4: printf("Hello World\n"); 5: return 0; 6: }
Before each line of code is the line number, just for reference. However, while writing a program, never write the line number. It'll be interpreted as useless garbage and cause a compile error.
The syntax for the various instructions presented throughout this guide will use the following format:
Example: Variables can be defined using the following syntax
The usage of square brackets in the syntax indicates the component inside is optional.
Every time I indicate you to press a certain key or set of keys, it'll be represented as <Key>.
Every time I want to represent the execution of a program, it will always be presented like it's being executed in a Unix environment.
Hello World
$
In the above example, the program prog0103 is executed, writing on the screen the message Hello World, leaving a new prompt.
As you go through some chapters, some definitions or important notes will be written and displayed with this aspect:
So if you're ready to use this guide and learn one of the most machine efficient languages out there, go to the next chapter, and learn how to make your first program!