Keywords in C programming
Keywords are the reserved words in every programming language, which are basic building blocks of program statements. Keywords are as essential as understanding the structure or syntax of the programming language. One cannot master the programming language without learning the proper use of keywords.
In C programming, there are 32 keywords, which must be written in lowercase only. There are multiple resources on keywords, they are also mentioned in all books written on C Programming. But yet hard to remember all of them, thus, here I have written an easier way to explain each one of them and also organized them to help you to remember them.
These 32 keywords are as follows alphabetically
auto | double | int | struct |
break | enum | long | switch |
case | else | register | typedef |
char | extern | return | union |
const | float | short | unsigned |
continue | for | signed | void |
default | goto | sizeof | volatile |
do | if | static | while |
YES, absolutely they are difficult to remember in this order, here is how I organized these keywords to remember them
Fundamental Datatypes
Starting with five fundamental datatypes, the first program we write is Hello World!
, in which we have seen void main()
(or int main()
) as our first function, here, void
(or int
) is called a function return type, which can be also declared along with the variables as their datatype.
All these keywords follow the same format
datatype variable;
Type Modifiers, Qualifiers, and Size
allows modifying the range and size of the datatypes
Basic Collections
the primitive data structures, yet the collection of the variables
User-defined declarations
allows user to define their own declarations
Fucntion Return
all these data types, collections, and type defines are returned by
Storage class specifiers
allows declaring explicitly the scope and lifetime of variables
Conditional blocks
allows creating branches in code flow that are directed by conditions
Jumps
allows to jump out of the loop or jump back to the loop by skipping further statements inside the loop
Loops
allows execution of the block of code several times according to the condition given in the loop. In simple words, executing the same code multiple times is called a loop
Now, let's go through them one by one
void
- It means nothing or no value
- Often used to specify the type of a function that doesn't return any value to the calling function
void fun(int a) {
// returns no value
// or returns nothing
}
- We cannot declare a variable as
void
, as it will throw an error - Can also be used as a function parameter at the time of declaration, when there is no argument passed to a function
int fun(void) {
int a = 5;
return (a + a);
}
int main(void) {
int x = fun();
}
char
- Single character datatype, which consumes 8-bits (1-byte) only
- Ranging from -128 to 127 when
signed
and from 0 to 255 whenunsigned
- All characters in an ASCII table can be displayed with this datatype
char alpha = `A`
- Can be assigned integer values ranging from -128 to 127
(signed)
or from 0 to 255(unsigned)
, stores respective ASCII character
char alpha = 23;
unsigned char beta = 200;
printf("%c, %c", alpha, beta);
int
- Used to declare the whole number
- Consumes 16-bits (2 bytes) on 16-bit processors/machines or 32-bits (4 bytes) on 32-bit processors/machines
- Ranging from -32768 to 32767 when
signed
and from 0 to 65535 whenunsigned
- Range can be extended, which is explained later
int i = 56;
unsigned int j = 51983;
- Can be assigned character values as well, stores respective ASCII number
int ch = 'E';
printf("%d", ch);
float
- Used to declare floating-point (or real) number
- Consumes 32-bits (4 bytes) with 6 digits of precision
- Ranging from 3.4E-38 to 3.4E+38
signed
by default,unsigned
is not permitted
float num = 34.67153982;
printf("%f", num);
output:
34.671539
double
- The extended version of
float
, also denoted as double precision numbers - Consumes 64-bits (8 bytes) with 14 digits of precision
- Ranging from 1.7E-308 to 1.7E+308
- Range can be extended further, which is explained later
double extNum = 1467.7987543022;
printf("%lf\n", extNum); // print value normally
printf("%.12lf\n", extNum); // force to print value for 12 decimal places
output:
1467.798754
1476.798754302200
short, long, signed, and unsigned
- Called as a qualifier, which can be assigned to
int
,char
, ordouble
datatypes as a type modifiers signed
uses one bit (MSB) for the sign (+/-) and other remaining bits for the magnitude of the number, whereasunsigned
uses all bits for the magnitude of the numbersigned
is the default to all data types, there is no need to specify it, whereasunsigned
can be used forint
andchar
onlyshort
andlong
are used to specify the storage of a variable datatype, whereshort
can be used forint
to specify 16-bit (2 bytes) integerslong
extends the range and storage capacity further forint
anddouble
datatypes, wherelong int
consumes 64-bit (8 bytes) on all processors/machines, ranging from -2147483648 to 2147483647long double
consumes 80-bits (10 bytes) (some machines consume 128-bits (16 bytes)) along with extending the precision further, ranging from 3.4E-4932 to 3.4E+4932
char // signed char
unsigned char
int // signed int
unsigned int
short int // signed short int
unsigned short int
long int // signed long int
unsigned long int
float
double
long double
struct
- As we know Array cannot be defined with different datatypes inside it, so structures are created to resolve the limitation of grouping variables with different data types together
- Structures are the constructed datatypes in C, their general syntax is as follows
struct tag_name {
datatype member1;
datatype member2;
...
datatype membern;
};
- The keyword
struct
defines the structure format - The
tag_name
can be used to declare structure variables of its type, later in the program - Variables defined inside the structure are
structure elements
ormembers
- The structure format is called a
template
, note that it has not declared any variables - Even if the entire definition is considered as a
statement
, each member is declared independently for its name and type in a separate statement inside the template - The following example will help us to understand this better
book: author(char), title(char), price(float), year(int)
struct book {
char author[20];
char title[15];
float price;
int year;
};
- I have written the detailed guide on Structures here
union
- Union is the same as Structures, hence, follows the same syntax. However, there is a major distinction between them in terms of storage.
union tag_name {
datatype member1;
datatype member2;
...
datatype membern;
};
- Each member in the structure has its own storage location, where all the members of a union use the same memory location
- It can handle only one member at a time, as only one memory location is allocated to the union
struct book_struct {
char author[20];
char title[15];
float price;
int year;
} var_book_struct;
union book_union {
char author[20];
char title[15];
float price;
int year;
} var_book_union;
int main() {
printf("Size of Structure: %ld\nSize of Union: %ld\n",
sizeof(var_book_struct), sizeof(var_book_union));
return 0;
}
output:
Size of Structure: 44
Size of Union: 20
- The detailed guide on Unions shall be uploaded along with structures, I shall update the link here
enum
- User-defined data type called enumerated datatype
enum identifier {value1, vlaue2, ..., valuen};
- Can be used to declare variables that can have values enclosed within the braces known as
enumeration constants
enumeration constants
has a default data type ofint
identifier
is a user-defined enumerated datatype andvalue1
,value2
,...
, andvaluen
areenumeration constants
- The default value assigned to the
enumeration constants
starts from0 (zero)
if not specified and follows the order
enum days {
sunday, // value = 0
monday, // value = 1
tuesday, // value = 2
wednesday, // value = 3
thursday, // value = 4
friday, // value = 5
saturday, // value = 6
};
// enumerated constants can be assigned
// directly to the integer variables
int day = tuesday;
printf("day: %d\n", day);
output:
day: 2
- After defining
enum
we can declare the variables of this new datatype
enum days {
sunday, // value = 0
monday, // value = 1
tuesday, // value = 2
wednesday, // value = 3
thursday, // value = 4
friday, // value = 5
saturday, // value = 6
};
// declare the variable with the enumerated datatype
enum days weekend = 6;
if (weekend == saturday)
printf("it's the weekend!\n");
output:
it's the weekend!
- However, values can be assigned manually to the enumeration constants
enum days {
monday = 1, // value = 1
tuesday, // value = 2
wednesday, // value = 3
thursday, // value = 4
friday, // value = 5
saturday, // value = 6
sunday = 0, // value = 0
};
printf("Day: %d\n", sunday);
output:
Day: 0
- The definition and declaration of variables can be combined into one statement
enum days {
sunday, // value = 0
monday, // value = 1
tuesday, // value = 2
wednesday, // value = 3
thursday, // value = 4
friday, // value = 5
saturday, // value = 6
} weekend = 6, weekbeg; // enumerated variables
weekbeg = monday; // value can be assigned individually
enums
are better than#define
macros, as they are type-safe and define a syntactical element
// don't prefer this
#define success 1
#define failure 0
// prefer this
enum bools {
failure, // value 0
success, // value 1
};
typedef
- Allows users to define their own datatype which can be declared with the existing datatype and later can be used to declare the variables with the defined type
typedef type identifier;
- Type refers to an existing datatype and
identifier
refers to the new name given to the datatype. - Creates the reference to an existing datatype, doesn't create a new type
// declare color as a new datatype to easily understand
typedef char color;
// declare variables of datatype color
color red = 'r', green;
green = 'g';
- Advantageous in creating some new datatype names for easiness in readability
- Can also be used for
struct
andunion
, which helps to write more organized code
return
- Specifies the return value of the function with the return type
- Can also be used to terminate the function in conditional statements
- Optional for
void
functions
void fun(int x) {
// statements
return; // optional
}
or
void fun(int x) {
// statements
}
sizeof
- Evaluates the size of a variable or a constant
sizeof(variable/const/type);
- It is also applicable to the existing data types as well as user-defined
- Returns the value which indicates the total bytes consumed by a variable or a constant
- The return type is generally
long unsigned int
, which can be different in different processors/machines
#include <stdio.h>
enum month {
jan,
feb,
};
int main() {
float fl = 3.45;
printf("%u bytes\n", sizeof(char)); // read size of a datatype
printf("%ld bytes\n", sizeof(jan)); // read size of a constant
printf("%ld bytes\n", sizeof(fl)); // read size of a variable
return 0;
}
output:
1 bytes
4 bytes
4 bytes
auto
- Used to declare a local variable within a function, which has its scope within a function
auto type variable;
auto
is assigned to all local variables by default, without specifying it
int fun(char ch) {
int x; // storage class auto assigned automatically or by default
// memory assigned to x automatically
x = (int )ch;
return x;
// memory destroyed assigned to x as its scope has ended
}
- A variable with
auto
keyword initialized to undefined or garbage value, until and unless assigned manually
void fun() {
auto int x;
printf("x: %d\n", x);
}
int main()
{
fun();
return 0;
}
output:
x: 22047 (garbage value)
static
- Declares a variable, which remains in the memory until the end of the program
static type variable = value;
static
variables are automatically initialized to zero
void fun() {
static int x; // automatically assigned value 0
printf("x: %d\n", x);
}
int main()
{
fun();
return 0;
}
output:
x: 0
- A local variable with
static
keyword exists and retains its value even after the control is transferred to the calling function
int fun() {
static int count = 0;
count++; // increment the variable
return count;
// memory assigned to static variable not destroyed
}
int main() {
printf("%d ", fun());
printf("%d ", fun());
return 0;
}
output:
1 2
static
keyword can also be assigned to the user-defined functions, to limit their access within the file, as functions are by default global- This can be also useful to reuse the same function name in other files
// file_1.c
static void display(void) {
printf("displaying display function\n");
}
// file_2.c
int main() {
display();
return 0;
}
- The above code will throw an error of
undefined reference to display
- Assigning
static
keyword to structure elements is not permitted
extern
- Allows extending the visibility of a variable or a function, this means a variable must be defined somewhere in the program, and declaring it as
extern
will make it global - When
extern
is used with a variable, it's only declared, not defined
int x; // declaration and definition, memory allocated
extern int x; // declaration only, memory not allocated
- Generally used when a particular file needs to access a variable from another file
- To declare a variable as an extern it must be defined somewhere in the program
#include <stdio.h>
extern int x; // declared x as extern but no memory allocated
int main() {
// display x
printf("x: %d\n", x);
return 0;
}
output:
undefined reference to `x'
#include <stdio.h>
extern int x; // declared x as extern but no memory allocated
int main() {
int x = 45; // declared and defined, memory allocated
// display x
printf("x: %d\n", x);
return 0;
}
output:
x: 45
- As an exception, declaring an
extern
variable with initialization is permitted, yet it throws a warning and is not recommended
extern int x = 45;
int main()
{
printf("x: %d\n", x);
return 0;
}
output:
warning: ‘x’ initialized and declared ‘extern’
| extern int x = 45;
| ^
x: 45
- Declaring
extern
keyword without defining, accessing, or initializing it also works fine
extern int x; // only declaration, no memory allocated
int main()
{
printf("Hello World!");
return 0;
}
output:
Hello World!
- Since the functions are global by default, the use of extern keyword for functions doesn't needed
register
- Allows storing variables inside CPU register instead of memory
- Variables that are used frequently can be stored inside the register so that they can be accessed faster
- Register variables have scope until execution of block they are declared inside
int main() {
register int x = 10; // declared and defined inside register with value 10
printf("x: %d\n", x);
return 0;
}
output:
x: 10
- Using
time
command in Linux for the programs without and with register variable shows the difference between execution time
without register keyword
$ time ./test_register_variable
x: 10
real 0m0.001s
user 0m0.002s
sys 0m0.000s
with register keyword
$ time ./test_register_variable
x: 10
real 0m0.001s
user 0m0.001s
sys 0m0.000s
- Register variables cannot be declared globally
register int x = 10;
int main() {
printf("x: %d\n", x);
return 0;
}
output:
error: register name not specified for ‘x’
- Register variables are initialized to a garbage value by default
- Most modern compilers store frequently used variables as register automatically, so even if you don't create any register variable, compilers will do it by themselves
const
- Allows declaring a variable as a constant, this means the value of the variable will not be changed throughout the program execution
- Can be written even after the datatype
const int a = 5; // allowed
int const a = 5; // allowed
- If we try to change the value manually it will throw compile error, this is also applicable to value modification by any other function or operations like increment/decrement
const int a = 5;
int main()
{
a = 10; // or a++ or --a
return 0;
}
output:
error: assignment of read-only variable ‘a’
- Assigned value
0
(zero) as default if not initialized manually at the time of declaration
const int a;
int main() {
printf("a: %d\n", a);
return 0;
}
output:
a: 0
- However, the pointing value can be modified and assigned to a constant pointer
int a = 10; // non-constant integer variable
const int * ptr = &a; // pointer is assigned address of a
int main()
{
printf("*ptr: %d\n", *ptr);
++a;
printf("*ptr: %d\n", *ptr);
return 0;
}
output:
*ptr: 10
*ptr: 11
- In the case of pointer to constant works little different
int a = 10;
int b = 20;
int * const ptr = &a;
int main()
{
*ptr = b;
printf("*ptr: %d\n", *ptr);
++a;
printf("*ptr: %d\n", *ptr);
return 0;
}
output:
*ptr: 20
*ptr: 21
volatile
The volatile keyword is used for creating volatile objects. A volatile object can be modified in an unspecified way by the hardware.
- Used to tell explicitly the compiler that a variable's value may be changed at any time by some external sources (from outside the program)
- As the value can be modified of a volatile variable even by its own program, we can add
const
keyword to keep the value unchanged by its own program but can be altered by some other process/external program
const volatile number;
Here, a number is a volatile object.
Since a number is a constant, the program cannot change it. However, hardware can change it since it is a volatile object.
if and else
- Everyone's favorite, a powerful decision-making statement and used to control the flow of execution of statements
if (expression)
if
allows the computer to evaluate the expression first and then, depending on whether the value of the expression (relation or condition) istrue (or non-zero)
orfalse (zero)
, it transfers control to a particular statementelse
is the keyword used along withif
when the mentioned expression doesn't satisfy then there should be something for thefalse
condition of it
if (if this is true) {
// true block statements
} else {
// false block statements
}
- One cannot write
else
without pairingif
, or beforeif
if (i == 1) {
printf("i is 1");
} else {
printf("i is not 1");
}
If the value of i
is other than 1, the output will be:
i is not 1
-
Can be implemented in the following forms
- Simple
if
statement - Nested
if
statement if
ladderif ... else
statement- Nested
if ... else
statement if ... else
ladder
- Simple
-
De Morgan's rule is applicable to
if
expressions
if (!x) // if x is false then execute the statement
true
switch, case, and default
The switch and case statement is used when a block of statements has to be executed among many blocks.
- Sometimes complexity of
if
ladder increases dramatically when the number of alternatives increases, in terms of following and reading the program. Thus, theswitch
statement makes it more accessible. switch
statement tests the value of a given variable (or expression) against a list of case values and when a match is found, a block of statements associated with that case is executed
switch (expression) {
case value1:
// statement block 1
break;
case value2:
// statement block 2
break;
...
...
default:
// default statement block
break;
}
- The expression must be an integer or characters, whereas
value1
,value2
,...
are constants or constant expressions known ascase
labels (must be unique) - The
default
is optional, when present, it will be executed if the value of the expression does not match with any of the case values.
switch (expression) {
case '1':
// some statements to execute when 1
break;
case `5`:
// some statements to execute when 5
break;
default:
// some statements to execute when default
}
- Expression must be an integral type
break
statement transfers the control out of theswitch
block- Nesting of
switch
is permitted
break, goto, and continue
break
andgoto
keywords are used for jumping out of a loop, accomplishing an early exit- Whereas
continue
keyword is used for skipping a part of a loop
while (1) { // infinite while loop
// continue keyword will transfer the control here
for (---) {
if (---) {
// breaks the current loop and executes
// statements under the statement block
goto situation;
} else if (---) {
// if the condition is true then
// break the loop to transfer the
// control out of it
break;
} else if (---) {
// if the condition is true then
// skip all other remaining part of the loop
// and transfer the control at the start of
// the loop again
continue;
}
// continue will skip all these statements in the loop
---
---
}
// break keyword will transfer the control here
}
// goto keyword will transfer the control here
situation:
// statements
- When the
break
statement is encountered inside a loop, the loop is immediately exited and the program continues with the statement immediately following the loop break
only exits from one loopgoto
requires a label in order to identify the place where the branch is to be made- Unlike
break
which causes the loop to be terminated, thecontinue
, causes the loop to be continued with the next iteration after skipping any statements in between - It is always good practice to avoid
goto
, as it affects efficiency, complications, and readability - One can also use the
exit()
function instead ofbreak
for exiting out of the loop, along with the inclusion of<stdlib.h>
- The use of
break
andcontinue
statements in any of the loops is considered unstructured programming
for (int i = 1; i < 10; ++i) {
if (i == 3)
continue;
if (i == 7)
break;
printf("%d ", i);
}
output:
1 2 4 5 6
When i
is equal to 3
, the continue
statement comes into effect and skips 3
. When i
is equal to 7
, the break
statement comes into effect and terminates the for
loop
while
- Simplest and easy-to-understand loop statement
while (test condition) {
// body of the loop
}
- The while is an entry-controlled loop statement
- The test condition is evaluated and if the condition is
true
, then the body of the loop is executed - This flow continues until land unless the test condition becomes
false
, and control is transferred out of the loop - Can be used for infinite execution of a program
do
- On some occasions, it might be necessary to execute the body of the loop before the test is performed
do {
// body of the loop
} while (test condition);
- On reaching the
do
statement, the program proceeds to evaluate the body of the loop first. At the end of the loop, the test condition in thewhile
statement is evaluated - If the condition is
true
, the program continues to evaluate the body of the loop once again. This process continues as long as the condition istrue
. - When the condition becomes
false
, the loop will be terminated and the control goes to the statement that appears immediately after thewhile
statement. - Since the test condition is evaluated at the bottom of the loop, the
do...while
construct provides an exit-controlled loop, and therefore the body of the loop is always executed at least once.
do {
printf("Input a number\n");
number = getnum();
} while (number > 0);
for
- Entry controlled loop that provides a more concise loop control structure
for (initialization; test-condition; increment) {
// body of the loop
}
- Initialization of the control variables is done first, using assignment statements such as
i = 1
andcount = 0
, the variablesi
andcount
are known as loop control variables - The value of the control variable is tested using the test condition. the test condition is a relational expression, such as
i < 10
that determines when the loop will exit. - If the condition is
true
, the loop's body is executed; otherwise, the loop is terminated and the execution continues with the statement that immediately follows the loop - When the loop body is executed, the control is transferred back to the
for
statement after evaluating the last statement in the loop. - Now, the control variable is incremented using an assignment statement such as
i = i + 1
, and the new value of the control variable is again tested to see whether it satisfies the loop condition, if the condition is satisfied, the body of the loop is again executed. This process continues till the value of the control variable fails to satisfy the test condition.
Additional features
- More than one variable can be initialized
for (int p = 1, n = 0; n < 17; ++n) {
// block statement
}
- Infinite
for
loop
for (; ; ) {
// block
}
- Nested
for
loops
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < columns; ++j) {
// block
}
}