Basics of C
Basics of C
History of C language is interesting to know. Here we are going to discuss a brief history of the
c language.
It was developed to overcome the problems of previous languages such as B, BCPL, etc.
Initially, C language was developed to be used in UNIX operating system. It inherits many
features of previous languages such as B and BCPL.
Let's see the programming languages that were developed before C language.
1. Simple
5. Rich Library
6. Memory Management
7. Fast Speed
8. Pointers
9. Recursion
10. Extensible
1) Simple
C is a simple language in the sense that it provides a structured approach (to break the problem
into parts), the rich set of library functions, data types, etc.
Unlike assembly language, c programs can be executed on different machines with some
machine specific changes. Therefore, C is a machine independent language.
C is a structured programming language in the sense that we can break the program into parts
using functions. So, it is easy to understand and modify. Functions also provide code reusability.
5) Rich Library
6) Memory Management
It supports the feature of dynamic memory allocation. In C language, we can free the allocated
memory at any time by calling the free() function.
7) Speed
The compilation and execution time of C language is fast since there are lesser inbuilt functions
and hence the lesser overhead.
8) Pointer
C provides the feature of pointers. We can directly interact with the memory by using the
pointers. We can use pointers for memory, structures, functions, array, etc.
9) Recursion
In C, we can call the function within the function. It provides code reusability for every
function. Recursion enables us to use the approach of backtracking.
10) Extensible
1. Documentation
2. Preprocessor Section
3. Definition
4. Global Declaration
5. Main() Function
6. Sub Programs
1. Documentation
This section consists of the description of the program, the name of the program, and the
creation date and time of the program. It is specified at the start of the program in the form of
comments. Documentation can be represented as:
Or
/*
*/
Anything written as comments will be treated as documentation of the program and this will
not interfere with the given code. Basically, it gives an overview to the reader of the program.
2. Preprocessor Section
All the header files of the program will be declared in the preprocessor section of the
program. Header files help us to access other’s improved code into our code. A copy of these
multiple files is inserted into our program before the process of compilation.
Example
#include<stdio.h>
#include<conio.h>
3. Definition
Preprocessors are the programs that process our source code before the process of
compilation. There are multiple steps which are involved in the writing and execution of the
program. Preprocessor directives start with the ‘#’ symbol. The #define preprocessor is used
to create a constant throughout the program. Whenever this name is encountered by the
compiler, it is replaced by the actual piece of defined code.
Example:
#define long long 11
4. Global Declaration
The global declaration section contains global variables, function declaration, and static
variables. Variables and functions which are declared in this scope can be used anywhere in
the program.
Example:
Int a=5;
5. Main() Function
Every C program must have a main function. The main() function of the program is written in
this section. Operations like declaration and execution are performed inside the curly braces
of the main program. The return type of the main() function can be int as well as void too.
void() main tells the compiler that the program will not return any value. The int main() tells
the compiler that the program will return an integer value.
Example:
Void main()
Or
int main()
6. Sub Programs
User-defined functions are called in this section of the program. The control of the program is
shifted to the called function whenever they are called from the main or outside the main()
function. These are specified as per the requirements of the programmer.
Example:
Int sum(int x,int y)
Return x+y;
// Link
#include <stdio.h>
// Definition
#define X 20
// Global Declaration
int sum(int y);
// Main() Function
int main(void)
{
int y = 55;
printf("Sum: %d", sum(y));
return 0;
}
// Subprogram
int sum(int y)
{
return y + X;
}
Programming Errors in C
Errors are the problems or the faults that occur in the program, which makes the behavior of the
program abnormal, and experienced developers can also make these faults. Programming errors
are also known as the bugs or faults, and the process of removing these bugs is known
as debugging.
These errors are detected either during the time of compilation or execution. Thus, the errors
must be removed from the program for the successful execution of the program.
o Syntax error
o Run-time error
o Linker error
o Logical error
o Semantic error
Syntax error
Syntax errors are also known as the compilation errors as they occurred at the compilation time,
or we can say that the syntax errors are thrown by the compilers. These errors are mainly
occurred due to the mistakes while typing or do not follow the syntax of the specified
programming language. These mistakes are generally made by beginners only because they are
new to the language. These errors can be easily debugged or corrected.
For example:
In the above output, we observe that the code throws the error that 'a' is undeclared. This error is
nothing but the syntax error only.
There can be another possibility in which the syntax error can exist, i.e., if we make mistakes in
the basic construct. Let's understand this scenario through an example.
1. #include <stdio.h>
2. int main()
3. {
4. int a=2;
5. if(.) // syntax error
6. printf("a is greater than 1");
7. return 0;
8. }
In the above code, we put the (.) instead of condition in 'if', so this generates the syntax error.
Run-time error
Sometimes the errors exist during the execution-time even after the successful compilation
known as run-time errors. When the program is running, and it is not able to perform the
operation is the main cause of the run-time error. The division by zero is the common example of
the run-time error. These errors are very difficult to find, as the compiler does not point to these
errors.
1. #include <stdio.h>
2. int main()
3. {
4. int a=2;
5. int b=2/0;
6. printf("The value of b is : %d", b);
7. return 0;
8. }
Output
In the above output, we observe that the code shows the run-time error, i.e., division by zero.
Linker error
Linker errors are mainly generated when the executable file of the program is not created. This
can be happened either due to the wrong function prototyping or usage of the wrong header file.
For example, the main.c file contains the sub() function whose declaration and definition is done
in some other file such as func.c. During the compilation, the compiler finds the sub() function
in func.c file, so it generates two object files, i.e., main.o and func.o. At the execution time, if
the definition of sub() function is not found in the func.o file, then the linker error will be
thrown. The most common linker error that occurs is that we use Main() instead of main().
Let's understand through a simple example.
1. #include <stdio.h>
2. int Main()
3. {
4. int a=78;
5. printf("The value of a is : %d", a);
6. return 0;
7. }
Logical error
The logical error is an error that leads to an undesired output. These errors produce the incorrect
output, but they are error-free, known as logical errors. These types of mistakes are mainly done
by beginners. The occurrence of these errors mainly depends upon the logical thinking of the
developer. If the programmers sound logically good, then there will be fewer chances of these
errors.
1. #include <stdio.h>
2. int main()
3. {
4. int sum=0; // variable initialization
5. int k=1;
6. for(int i=1;i<=10;i++); // logical error, as we put the semicolon after loop
7. {
8. sum=sum+k;
9. k++;
10. }
11. printf("The value of sum is %d", sum);
12. return 0;
13. }
Output
In the above code, we are trying to print the sum of 10 digits, but we got the wrong output as we
put the semicolon (;) after the for loop, so the inner statements of the for loop will not execute.
This produces the wrong output.
Semantic error
Semantic errors are the errors that occurred when the statements are not understandable by the
compiler.
o Type compatibility
int b = "java";
o Errors in expressions
int a, b, c;
a+b = c;
1. #include <stdio.h>
2. int main()
3. {
4. int a,b,c;
5. a=2;
6. b=3;
7. c=1;
8. a+b=c; // semantic error
9. return 0;
10. }
In the above code, we use the statement a+b =c, which is incorrect as we cannot use the two
operands on the left-side.
Compilation process in c
What is a compilation?
The compilation is a process of converting the source code into object code. It is done with the
help of the compiler. The compiler checks the source code for the syntactical or structural errors,
and if the source code is error-free, then it generates the object code.
The c compilation process converts the source code taken as input into the object code or
machine code. The compilation process can be divided into four steps, i.e., Pre-processing,
Compiling, Assembling, and Linking.
The preprocessor takes the source code as an input, and it removes all the comments from the
source code. The preprocessor takes the preprocessor directive and interprets it. For example,
if <stdio.h>, the directive is available in the program, then the preprocessor interprets the
directive and replace this directive with the content of the 'stdio.h' file.
The following are the phases through which our program passes before being transformed into an
executable form:
o Preprocessor
o Compiler
o Assembler
o Linker
Preprocessor
The source code is the code which is written in a text editor and the source code file is given an
extension ".c". This source code is first passed to the preprocessor, and then the preprocessor
expands this code. After expanding the code, the expanded code is passed to the compiler.
Compiler
The code which is expanded by the preprocessor is passed to the compiler. The compiler
converts this code into assembly code. Or we can say that the C compiler converts the pre-
processed code into assembly code.
Assembler
The assembly code is converted into object code by using an assembler. The name of the object
file generated by the assembler is the same as the source file. The extension of the object file in
DOS is '.obj,' and in UNIX, the extension is 'o'. If the name of the source file is 'hello.c', then the
name of the object file would be 'hello.obj'.
Linker
Mainly, all the programs written in C use library functions. These library functions are pre-
compiled, and the object code of these library files is stored with '.lib' (or '.a') extension. The
main working of the linker is to combine the object code of library files with the object code of
our program. Sometimes the situation arises when our program refers to the functions defined in
other files; then linker plays a very important role in this. It links the object code of these files to
our program. Therefore, we conclude that the job of the linker is to link the object code of our
program with the object code of the library files and other files. The output of the linker is the
executable file. The name of the executable file is the same as the source file but differs only in
their extensions. In DOS, the extension of the executable file is '.exe', and in UNIX, the
executable file can be named as 'a.out'. For example, if we are using printf() function in a
program, then the linker adds its associated code in an output file.
hello.c
1. #include <stdio.h>
2. int main()
3. {
4. printf("Hello");
5. return 0;
6. }
o Firstly, the input file, i.e., hello.c, is passed to the preprocessor, and the preprocessor
converts the source code into expanded source code. The extension of the expanded
source code would be hello.i.
o The expanded source code is passed to the compiler, and the compiler converts this
expanded source code into assembly code. The extension of the assembly code would
be hello.s.
o This assembly code is then sent to the assembler, which converts the assembly code into
object code.
o After the creation of an object code, the linker creates the executable file. The loader will
then load the executable file for the execution.
Hence, for bigger programs, the debugging can be done by inserting some print() statements in
between the code that tells us about the intermediate results. Once done with the debugging,
the printf() statements can be deleted.
But, after some time once again if it needs to debug the program, then it will be required to
insert all those printf() statements again which will be again a tedious task. Hence to avoid
this problem, preprocessor directives #define and #undef are used where the program can be
debugged at any time as per our needs.
Using preprocessor directives, the debugging statements can be enabled or disabled as per our
needs.
Example:
int main()
{
int a = 5, b = 10, sum = 0;
sum = a + b;
#ifdef DEBUG
printf("At this point,\nsum of a and b = %d \n", sum);
#endif
a++;
b--;
#ifdef DEBUG
printf("\nAt this point,\nvalue of a = %d\n", a);
printf("value of b = %d", b);
#endif
}
Output
At this point,
sum of a and b = 15
At this point,
value of a = 6
value of b = 9
After the completion of the debugging process, we can remove the macro DEBUG by simply
replacing the #define with #undef directive.
By such replacement, no debug statements will be compiled as all the #ifdef condition
becomes false. In this way, the debugging process is done for the large programs using
preprocessor directives.
The use of #ifdef and #endif for each debug statement seems to be lengthier. Hence to make
the process more concise, we can use of another macro SHOW.
The macro SHOW is defined in such a way that when macro DEBUG is defined then
this SHOW will be replaced by a printf() statement and if DEBUG is not defined
then SHOW is not replaced by anything.
Example:
// C program to demonstrating the debugging process using
// preprocessor directive '#define' and macro 'SHOW'.
#include <stdio.h>
#define DEBUG
#ifdef DEBUG
#define SHOW printf
#else
#define SHOW // macros
#endif
int main()
{
int a = 5, b = 10, sum = 0;
sum = a + b;
Output
At this point,
sum of a and b = 15
At this point,
value of a = 6
Pseudo code in C
Programmers frequently utilize pseudo code, a high-level language that is simpler to read and
comprehend than actual programming code, to convey algorithms and program logic. C is
a high-level, general-purpose programming language that is frequently used for creating
system software, and it is one common implementation of pseudo code.
We'll discuss the idea of pseudo code and how it's used in the C programming language in this
blog post.
Software engineers frequently use pseudo-code as a design technique since it enables them to
work out the specifics of a program's logic before writing any actual code. Because errors are
considerably simpler to rectify in the pseudo-code than they are in the actual code, this can
reduce errors and save time.
Although there isn't a dedicated programming language for pseudo code but C is a good choice
for implementation. C is a general-purpose, high-level programming language that is
frequently used to create system software. It is a structured programming language, which
implies that it controls the flow of the program using a few predefined programming constructs.
C programming language simply translates the plain language description of the program logic
into C syntax to construct pseudo-code. The C programming language directly corresponds to the
fundamental programming features found in pseudo-code, such as loops, conditionals,
and function calls.
Example:
Let's consider an example of implementing a simple program that calculates the average of three
numbers using pseudo code in C:
Pseudo code:
1. Start
2. Input three numbers
3. Calculate the sum of the three numbers
4. Divide the sum by 3 to get the average
5. Display the average
6. End