Your browser doesn't support JavaScript c Archives - Page 2 of 2 - Windows Programming

Functions

A function is a unit of code grouped to perform a specific task.  Functions provide a way to compartmentalise and organise a program. Functions are identified by a name, enclosed within scope brackets and may be terminated by a return statement. On calling a function the execution of the program branches to the first statement in that function and continues until it reaches a return statement or the last statement of the function; at that point, execution resumes at the place where the function was called. A function can have multiple parameters separated by commas, but it can have only one return type. A function that does not need to return a value is declared void.  In C, one function cannot be embedded within another function.

Function Prototype

The function prototype declares a function before its definition and details its name, the list of parameters the function accepts and the return type of the function. The compiler needs to know this information before the function is called. A function defined before main() (forward declaration) does not need a function prototype. The variables passed to a function are called arguments, and are enclosed in parentheses following the function’s name. A function declaration inside main(), has its scope limited to within the main{} block, however, if you add it outside main, its scope is the entire source file. 

Function call

A program cannot execute the function statements until called by another part of the program. A function call is an expression that passes control and arguments (if any) to a function. When a function declaration contains parameters, the function call must send arguments. Arguments are values the function requests within its parameter list. Except for those functions with variable-length argument lists, the number of arguments in a function call must be the same as the number of parameters in the function definition. When the function is finished, execution control passes to the place from which the function was called.

Function Parameters

The purpose of parameters is to allow functions to receive arguments.  A comma separates multiple parameters. These parameters don’t have to be of the same data type. Any valid C expression can be a function parameter, including constants, logical expressions, and other functions that return a value. Parameter data can be passed into and out of methods and functions using pass-by-value or pass-by-reference.

Pass by Value – Using “pass by value”  means that the data associated with the actual parameter is copied into a separate storage location assigned to the function parameter.  The parameters passed to a function become local variables within that function, even if they have the same name as variables within the scope of the statement calling the function.  Any modifications to the function parameter variable inside the called function or method affect only the local parameter.  This is the default method for passing an argument to a function.

Pass by Reference – Using “pass by reference”, means that the function parameter will pass a reference (or pointer) to the variable in the calling environment. Any changes to the function parameter are reflected in the calling environment. actual parameter. 

The following code section demonstrates call-by-reference and call-by-value by passing two values to two functions and then swapping them. The x and y will only be changed by passing the values by reference.

#include <stdio.h>
void swapbyref(int *x, int *y); /* function declaration */
void swapbyval(int x, int y); /* function declaration */
 int main () {
   int a = 10,b=20;
   printf("Before swap by ref of a and b : %d %d\n", a,b );
   swapbyref(&a, &b);/*call swap function by ref*/
   printf("After swap by ref of a and b : %d %d\n", a,b );
   printf("Before swap by value of a and b : %d %d\n", a,b );
   swapbyval(a, b);/*call swap function by value*/
   printf("After swap by value of a and b : %d %d\n", a,b );
   return 0;
}
/*swap function by ref*/
void swapbyref(int *x, int *y) {
     int temp;
   temp = *x;    
   *x = *y;     
   *y = temp;    
    return;
}
/*swap function by value*/
void swapbyval(int x, int y) {
    int temp;
   temp = x;    
   x = y;      
   y = temp;  
   return;
}

Passing an Array of Values to a Function

When an array is passed to a function it is always treated as a pointer by that function.  Pointers to an array are passed as an argument by specifying the array’s name without an index. The argument represents the memory address of the first element of an array. Any changes in the function will therefore be reflected in the original array. To pass a single-dimension array as an argument in a function use one of the following.

void myFunction(int *param) array passed as pointer
void myFunction(int param[10]) array passed a sized array
void myFunction(int param[]) array passed as unsized array

All these variants are functionally identical. Each effectively tells the compiler that an integer pointer will be received.

The following simple function demonstrates how to pass a char array and int value to a procedure.

#include <stdio.h>
float total(float value[],int size);/*function prototype declaration containing parameter list*/
int main()
{
float avg, measurement[] = {223.1, 555, 22.63, 3.12, 31.5, 180};
printf("Total Values = %.2f", total(measurement,6));/*function call in printf statement*/
return 0;
}

float total(float value[],int size)/*start of function with 2 parameters*/
{
int i;
float total= 0.0;
for (i = 0; i < size; ++i) {
total += value[i];
}
return total;
}

Functions That Have a Variable Number of Arguments

Variable length arguments is a feature that allows a function to receive any number of arguments.`

When a function is declared with a variable argument list, the fixed parameter must be declared first followed by ellipses at the end of the parameter list to indicate additional arguments as below

Macros and a pointer found within stdarg.h  are used to retrieve the arguments in the variable list. These arguments  are-

va_list() – A pointer data type used to access the individual arguments
va_start()  – A macro used to initialise the pointer arg_ptr to point at the first argument in the variable list.
va_arg() – A macro used to retrieve each argument, in sequence, from the variable list.
va_end() – When all the arguments in the variable list have been retrieved this macro is used to “clean up”.

#include <stdarg.h> 
#include <stdio.h> 
// this function sums 5 numbers
int sumvalues(int arg_value, ...) 
{ 
    int i,sum; 
    va_list ap; // va_list holds information about variable arguments 
    va_start(ap, arg_value);     // va_start must be called before accessing variable argument list 
    sum=va_arg(ap, int); // Initialise sum as first  argument in list 
    //iterate through arguments and add to total 
    for (i = 2; i <= arg_value; i++) 
    {
 sum=sum+va_arg(ap, int); 
    }     
    va_end(ap); // va_end executed before the function end
    return sum; 
} 
  int main() 
{ 
    int count = 5; 
    printf("sum of value is %d", sumvalues(count, 12, 67, 6, 7, 100)); 
    return 0; 
} 

Returning a Value from a Function

Functions can return a value or return nothing (void).  To return a value from a function, the keyword return is followed by the value to return.  A function’s return value is copied into a placeholder on the stack. The return value is popped off the stack and can be assigned as the value of the function. If the value of the function isn’t assigned to anything, no assignment takes place, and the value is lost.  A function can contain multiple return statements but only one return value.  Multiple return statements can be used to return different values from a function.  After a return statement, program execution continues immediately after the statement that called the function.

Recursion

A function that calls itself is known as a recursive function. The recursion proceeds until some condition is met which breaks the recursive cycle. The following simple recursion function demonstrates how a countdown procedure calls itself until the exit condition is met.

#include <stdio.h>
void printFun(int countp) 
{ 
 if (countp < 1) //exit function if value of countp is smaller than 1
 return; 
 else
 { 
 printf("Count value = %.i \n", countp);
 printFun(countp-1); //recursive function calls itself
 return; 
 } 
} 
 int main() 
{ 
 int count = 3; 
 printFun(count); //call recursive function
}

Input and Output

In C, Input sources and output destinations are collectively known as devices. All input and output to these devices are through streams. A stream is a device-independent sequence of characters in the form of bytes of data. A sequence of bytes flowing into a program is an input stream and a sequence of bytes flowing out of a program is an output stream. Every C stream is connected to a file acting as an intermediate step between the stream and the actual physical device used for input or output. 

Text Versus Binary Streams

C streams can be either text or binary.  Text streams are organised into lines of data terminated by a newline character. Certain characters in a text stream are used to convey functionality, such as the newline character however characteristics may vary from system to system and may have to be altered to conform to differing conventions for representing text in the host environment. In contrast, a binary stream can handle any data type since bytes of data in a binary stream aren’t interpreted or translated in any special way. This type of stream is generally most useful for non-textual data

Predefined Streams

The ANSI standard for C has three predefined streams –

typename
Standard inputstdin
Standard outputstdout
Standard errorstderr

C’s Stream Functions

The C language has standard libraries containing a variety of functions or methods that allow input and output in a program. By calling these library functions the user can manipulate the stream data. 

Unformatted output with putchar() , putc() , and fputc()

Unformatted I/O is the most basic form of data exchange between devices. Data is transferred in raw form or internal binary representation without any conversions. It is simple, efficient and compact.

putchar 

The putchar function writes a character to the standard output stream(stdout). The prototype for putchar is as follows:

putchar(int ch);

The value parameter ch may be a type char or type int thus a value of int c=89 or char c=’Y’ will produce the same output.

puts

The puts function writes a string str and a trailing newline to stream stdout. The prototype for this function is

puts(char* str)

where str is the C string to be written

fputs

The fputs() outputs a null-terminated string to any named output stream.  The prototype for fputs is as follows

int fputs(const char *str, FILE *stream)

The fput function takes two arguments: the first is the string to be written to the file and the second is the stream where the string will be written.

The code section below demonstrates the use of puchar, puts and fputs –

#include<stdio.h>
int main () {
int c=89;
char str[]="hello world";
putchar(c);//writes the character y (ascii 89)to stdout.
putchar('\n');//writes 'newline' to stdout.
putchar('Y');//writes the character y to stdout.
putchar('\n');//writes 'newline' to stdout.
puts(str); // writes the string str and a trailing newline to stdout.
fputs(str,stdout);// writes the string str and a trailing newline to stdout.
return(0);
}

Unformatted input with fgets() and getchar()

getchar

The getchar() function reads a single character from the terminal and returns it as an integer. You can use this method in a loop to read more than one character.  The short program below demonstrates the use of getchar by asking the user to enter a character and then echoing the character to the screen.

#include <stdio.h>
int main( )
{
int c;
printf("Enter a character followed by return ");
c = getchar();//prompts for screen input store ascii code of character
putchar(c);//writes character to stdout
}

fgets()

The fgets() function reads a specified number of characters from the input stream and stores it in a string. The prototype of fgets() is

fgets(string,size,stdin);

Here string is the name of a char array, size is the amount of text to input plus one (this must be no larger than the size of the char array), and stdin is the name of the standard input device, as defined in the stdio.h header file. 

The short program below demonstrates the use of the fgets() by asking the user to enter a string and then echoing the string to the screen.

#include<stdio.h>
int main()
{
char str[100];//declared character array of length 100 
printf("Enter a string followed by enter ");
fgets(str,100,stdin);//stores user input in chr array str
puts( str );//writes str to stdout
}

Formatted Input and output with the scanf() & printf() functions

In formatted I/O, binary data is converted to an internal standard, usually ASCII, before processing. Formatted I/O is portable and human-readable, but uses more space and carries more computational overhead because of the conversions between input and output. 

scanf 

Is a function that reads and stores formatted data from the standard input stream stdin. The prototype for scanf is

int scanf ( const char * format, ... );

Scanf() accepts a variable number of arguments but requires a minimum of two. The first argument is a format string that uses special characters to indicate how to interpret the input data. The second, and remaining arguments, are the addresses of the variable(s) to which the input data is assigned. 

printf 

Is a function that writes formatted data to the standard output stream stdout. The printf() function is part of the standard C library and is complementary to scanf.  The prototype for printf is

int printf ( const char * format, ... );

The printf() function can accept a variable number of arguments but requires a minimum of one.  The format string contains the text to be written to stdout and optional embedded format tags. These optional parameters are variables and expressions which describe further output formatting information. 

The following code shows the usage of both printf and scanf. When the code is compiled, it will ask the user to enter a name and age separated by a space. When a value is entered, it will be displayed on the screen.  The purpose of %d inside the scanf() and printf() functions is to provide string formatting information. 

#include<stdio.h>
int main()
{
 char name[20];
 int age;
 printf("Please enter your name & age - ");
 scanf("%20s %d", name,&age);//prompts for input max 20 characters and value.stores data in name and age
 printf( "Hello: %s %d years old", name,age);//writes name and age to stdout
}

some of the more common format parameters 

Format String Meaning
%d signed decimal number
%f floating point number
%u  decimal
%i integer as a signed number.
%c character
%s character string. The scanning ends at whitespace.
 %g%G floating-point number in either normal or exponential notation. %g uses lower-case letters and %G uses upper-case.
 %x, %X hexadecimal number. %x uses lower-case letters and %Xuses upper-case.
 %o Scan an integer as an octal number.

It is also possible to limit the number of digits or characters that can be input or output, by adding a number with the format string specifier such as “%1d” or “%4s”. The first specifier indicates a single numeric digit and the second specifier indicates 4 characters. Entering 99, while scanf() has “%1d”, means only one digit will be accepted regardless of how many digits are entered.

Expressions Statements and Operators

All C programs are made up of statements, which are commands given to the computer executed in sequence.  These statements are usually written one per line, although this is not a coding requirement. C statements always end with a semicolon except for preprocessor directives.

Whitespace

Whitespace refers to characters that are used for formatting purposes. In C, this refers primarily to spaces, tabs, and newlines. The C compiler generally ignores whitespace, with a few minor exceptions. Whitespace serves the purpose of making the code more readable to programmers.

Null Statements

A null statement is a semicolon on a line that performs no action. 

Compound Statements

A compound statement or block comprises one or more statements enclosed within a bracket.{}

Although every statement in a compound statement must end with a semicolon, the compound statement itself does not end with a semicolon. Variables declared within the statement are local to that compound statement.

Operators

An operator is a symbol that tells the compiler to perform a specific mathematical or logical operation.  C operators fall into several categories: assignment operators, mathematical operators, relational operators, and logical operators.

Assignment Operator – is used to assign a value to a variable. The Assignment Operator is denoted by equal to sign. An assignment Operator is a binary operator which operates on two operands. The following table lists the assignment operators supported by the C language –

Data typeNotes
charCan store -127 to 127 or 0 to 255. 8 bits. Usually used for holding ASCII characters.
char16_tUnsigned integer type. Usually 16 bits. Used for UTF-16 character representation
char32_tUnsigned integer type. Usually 32-bit bits. Used for UTF-32 character representation
wchar_tOccupies between 16 or 32 bits depending on the compiler being used. Used for Unicode character representation
signed char8 bits. Can store values between -128 to +127. Used for dealing with binary data
signed short intUsually at least 16 bits. Can store values between –32,768 to 32,767
signed intUsually at least 16 bits. Can store values between –32,768 to 32,767
signed long intUsually at least 32 bits. Can store values between –2,147,483,648 to 2,147,483,647
signed long long intusually at least 64 bits. Can store values between –9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
unsigned char8 bits. Can store values between 0 to 255
unsigned short intAt least 16 bits. Can store values between 0 to 65,535
unsigned intAt least 16 bits. Can store values between 0 to 65,535
unsigned long intAt least 32 bits. Can store values between –2,147,483,648 to 2,147,483,647
unsigned long long intAt least 64 bits. Can store values between 0 to 4,294,967,295
floatUsually 32 bits. Used for storing single precision floating point values.
doubleUsually 64 bits. Used for storing double precision floating point values
long doubleUsually 96 bites. Used for storing long double-precision floating-point values

The Mathematical Operators – C’s arithmetic operator performs mathematical operations such as addition, subtraction, and multiplication on numerical values

assuming a=2 and b=1

Postfix or Prefix? – In C the increment ++ operator increases the value of a variable by 1 and the use of decrement — operator decreases the value of a variable by 1. The operator placement has an important effect on the way the operations are evaluated

Placing the operator before the operand ie ++var causes the variable to be increased before it returns a value

Placing the operator after the operand ie var+ causes the value of the variable to be returned before it is incremented by 1

Relational Operators – checks if the values of two operands are equal. 

assuming a=2 and b=1

Operator Description Example
== returns true (1) if two operands have the same value otherwise returns false (0) (A == B) is not true.
!= returns true (1) if two operands don’t have the same value otherwise returns false (0) (A != B) is true.
> returns true (1) if the left operand is greater than the value of the right operand otherwise returns false (0) (A > B) is true.
< returns true (1) if the left operand is less than the value of the right operand otherwise returns false (0) (A < B) is false.
>= returns true (1) if the left operand is greater than or equal to the value of the right operand otherwise returns false (0) (A >= B) is true.
<= returns true (1) if the left operand is less than or equal to the value of the right operand otherwise returns false (0) (A <= B) is false.

Logical Operators – applies standard boolean algebra operations to their operands

Assume variable A holds 2 and variable B holds 1, then −

Operator Description Example
&& the logical AND operator evaluates two expressions. If both expressions are true, the logical AND expression is true. A==2 && B==1 result is TRUE
|| The logical OR operator evaluates two expressions. If either is true, the expression is true A==2 || B==1 result is TRUE
! A logical NOT statement reverses a normal expression, returning true if the expression is false and false if the expression is true. !(A==2) result is FALSE

Bitwise Operators – perform manipulations of data at the bit level. These operators also perform the shifting of bits from right to left. Bitwise operators are not applied to float or double.  The difference between logical and bitwise operators is that bitwise operators don’t return a boolean result but manipulate individual bits.

The Bitwise operators supported by the C language are listed in the following table. Assume variable A holds 50 and variable B holds 25, then −

A = 0011 0010

B = 000 11001

OperatorDescriptionExample
&Binary AND Operator copies a bit to the result if it exists in both operands.(A & B) will give 16 which is 0001 0000
|Binary OR Operator copies a bit if it exists in either operand.(A | B) will give 59 which is 0011 1011
^Binary XOR Operator copies the bit if it is set in one operand but not both.“>(A ^ B) will give 43 which is 00010 1011
~is a unary operator and has the effect of ‘flipping’ the bits.(~A ) will give -51 which is 1111111111001101 in 2’s complement form.
<<Binary Left Shift Operator. The left operand value is moved left by the number of bits specified by the right operand.A << 1 will give 100 which is 0110 0100
>>Binary Right Shift Operator. The left operand value is moved right by the number of bits specified by the right operand.A >> 2 will give 12 which is 0000 1100

Misc Operators

? or ternary operator – Can be used to replace if-else statements

example:y = (x > 10) ? 10 : 20;

Here, y is assigned the value of 10 if x is greater than 10 and 20 if not

. ->(dot and arrow) —- used to reference individual structures and unions.

&(ampersand) —- returns the address of a variable. For example, &x; returns the location of the variable x in memory

*(asterisk) —- Used to Declare and Dereference a pointer.

Operator Precedence in C++

Operator precedence is the order in which operators are evaluated in a compound expression. In C++, when the compiler encounters an expression, it must similarly analyse and determine how it should be evaluated. To assist with this, all operators are assigned a level of precedence. Those with the highest precedence are evaluated first.

Here, operators with the highest precedence appear at the top of the table, and those with the lowest appear at the bottom. Within an expression, higher precedence operators will be evaluated first.

for example

int myNumber = 20 * 50 + 25 – 25 * 25 << 2;

simplifies to 1000+25-625>>2

simplifies to 400>>2=100

RankNameOperator
1Scope resolution::
2Member selection, subscripting, increment, and decrement. ->
2Member selection, subscripting, increment, and decrement. ->()++ —
3sizeof, prefix increment and decrement, complement, and, not, unary minus and plus, address-of and dereference, new, new[], delete, delete[], casting, sizeof()++ –^ !- +& *()
4Member selection for a pointer.* ->*
5Multiply, divide, modulo* / %
6Add, subtract+ –
7Shift (shift left, shift right)<< = >>=
8Inequality relational== !=
9Equality, inequality== !=
10Bitwise AND&
11Bitwise exclusive OR^
12Bitwise OR |Rank Name Operator|
13Logical AND &&&&
14Logical OR||
15Conditional?:
16Assignment operators= *= /= %= += -= <<= >>= &= |= ^=
!7Comma

Constants

Constants or literals refer to fixed values that the program may not alter after they have been defined.  Constants can be of any basic data type such as an integer or character.

 C has two types of constants:

  • Literal Constants
  • Symbolic Constants 

Literal Constants

A literal constant is a hard code value that is typed directly into the source code such as a number, character, or string that may be assigned to a variable or symbolic constant.

Symbolic Constants

A symbolic constant is an identifier representing a constant value.  Whenever a constant value is required the constant name can be used in place of that value throughout the program thus the value of the symbolic constant only needs to be entered when it is first defined. Symbolic constants can be defined using the preprocessor directive #DEFINE or the const keyword.

Defining Constants Using #define – The #define directive enables a simple text substitution that replaces every instance of the name in the code with a specified value with the compiler only seeing the final result.  Since these constants don’t specify a type, the compiler cannot ensure that the constant has a proper value and their use is discouraged. The prototype of a define directive is –

#define PI 3.14

In the above example, every incidence of the constant directive PI will be replaced by 3.14

Defining Constants with the const Keyword prefix –  Variables declared const can’t be modified when the program is executed. A value is initialised at the time of declaration and is then prohibited from being changed. 

In the code sample below the value, PI is declared as both a const variable and a preprocessor directive

#include <stdio.h>
#define PI 3.14 //set value of constant directive
int main()
{
const float PIVALUE= 22.0 / 7; //set value of constant
printf( "\nValue of constand variable PI %f", PIVALUE);
printf( "\nValue of constant directive PI %f", PI);
return 0;
}

Constants are often fully capitalised by programmers to make them distinct from variables. This is not a requirement but the capitalisation of a constant must be consistent in any statement since all variables are case sensitive.

Variables

Variables are named locations in a computer’s memory used to store data. The value of this variable can be changed one or more times during the execution of a program. In C, all variables and the type of values that the variable can hold must be declared before they are used and must adhere to the following rules:

  • The variable name can contain letters (a to z and A to Z), digits (0 to 9), and the underscore character ( _ )
  • The first character of the name must be a letter. or underscore. A digit cannot be used as the first character.
  • C is case-sensitive.
  • C keywords are not acceptable as variable names. A keyword is a word that is part of the C language.

Variable Declarations

A variable declaration will specify to the compiler the name and type of a variable. When a variable is declared the compiler automatically allocates memory for it and this size can vary depending on the computer platform. Any attempt to use a variable that hasn’t been declared will result in the compiler generating an error message. A variable declaration will consist of the variable type followed by the variable name. Multiple single-line variable declarations are possible by separating each variable name with a comma –

int x //declares variable of type int
float x,y,z; //declares variables of type float
short int x,y,z; //declares variables of type short int
unsigned int x,y,z; //declares variables of type unsigned int
char xyz; //declares variable of type char

Initialising Variables by Assigning Values

A variable can be assigned an initial value when created after creation but these values must be in the correct format. In C, there are three ways to initialise a variable-

Using the assignment operator (=)

int value=10; //creates and initialises variable value of type int to 10

Using parenthesis ()

int value (20) ; //creates and initialises variable value of type int to 20

Using braces {}

int value{30} ; //creates and initialises variable value of type int to 30

An uninitialised variable is a variable that is declared but is not set to a definite known value. An uninitialised variable will have some unknown value known as a “garbage value”. This is due to the variable being assigned a memory location by the compiler and inheriting whatever value happens to be in that memory location. Using the value from an uninitialised variable can result in undefined behaviour and data corruption.

Smaller variables require less memory, and the computer can perform faster mathematical operations. In contrast, large integers and floating-point values require more storage space and thus more time for performing mathematical operations. Using the correct variable types ensures your program runs as efficiently as possible.

Variable Types

Data typeNotes
charCan store -127 to 127 or 0 to 255. 8 bits. Usually used for holding ASCII characters.
char16_tUnsigned integer type. Usually 16 bits. Used for UTF-16 character representation
char32_tUnsigned integer type. Usually 32-bit bits. Used for UTF-32 character representation
wchar_tOccupies between 16 or 32 bits depending on the compiler being used. Used for Unicode character representation
signed char8 bits. Can store values between -128 to +127. Used for dealing with binary data
signed short intUsually at least 16 bits. Can store values between –32,768 to 32,767
signed intUsually at least 16 bits. Can store values between –32,768 to 32,767
signed long intUsually at least 32 bits. Can store values between –2,147,483,648 to 2,147,483,647
signed long long intusually at least 64 bits. Can store values between –9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
unsigned char8 bits. Can store values between 0 to 255
unsigned short intAt least 16 bits. Can store values between 0 to 65,535
unsigned intAt least 16 bits. Can store values between 0 to 65,535
unsigned long intAt least 32 bits. Can store values between –2,147,483,648 to 2,147,483,647
unsigned long long intAt least 64 bits. Can store values between 0 to 4,294,967,295
floatUsually 32 bits. Used for storing single precision floating point values.
doubleUsually 64 bits. Used for storing double precision floating point values
long doubleUsually 96 bites. Used for storing long double-precision floating-point values

Variable Scope

A scope is a region of a program, and the scope of variables refers to the area of the program where a variable exists and can be accessed after its declaration.

In C, programming variables can be declared in three places:

  • Inside a function or a code block. These are known as local variables and are only valid inside the block they are defined.
  • Outside of all functions. These are known as global variables and can be accessed in any part of the program
  • In the function parameters (formal parameter)

When a local variable is defined, it is not initialised by the system and must be initialised by the program. Global variables are initialised automatically by the system.

Using Type Definitions

The typedef declaration provides a way to declare an identifier as an alias or shortcut for an existing variable type. When compiled, the compiler substitutes the identifier with the variable type. Typedef does not create a distinctive variable type but establishes a synonym for an existing variable type –

typedef int aliasint; //create an alias for int name aliasint
aliasint v=12; //creates int variable v and set to 12

Sizeof

The sizeof() operator returns the size in bytes of a variable or a type. Since the sizes of a variable or data types can differ between computing environments, knowing the size of a variable in all situations can be useful. The following program lists the size of the C variable types

#include <stdio.h>
int main(void)
{
printf( "\nA char is %d bytes", sizeof( char ));
printf( "\nAn int is %d bytes", sizeof( int ));
printf( "\nA short is %d bytes", sizeof( short ));
printf( "\nA long is %d bytes", sizeof( long ));
printf( "\nA long long is %d bytes\n", sizeof( long long));
printf( "\nAn unsigned char is %d bytes", sizeof( unsigned char ));
printf("\nAn unsigned int is %d bytes", sizeof( unsigned int ));
printf("\nAn unsigned short is %d bytes", sizeof( unsigned short ));
printf("\nAn unsigned long is %d bytes", sizeof( unsigned long ));
printf("\nAn unsigned long long is %d bytes\n",sizeof( unsigned long long));
printf( "\nA float is %d bytes", sizeof( float ));
printf( "\nA double is %d bytes\n", sizeof( double ));
printf( "\nA long double is %d bytes\n", sizeof( long double ));
return 0;
}

Enumerations

An enumeration is a user-defined data type that consists of integral constants called enumerators. An enum variable takes only one value out of many prescribed values and returns a numeric value corresponding to the selected enumeration. These constants can then be used anywhere that an integer can. Enumerations are defined using the keyword enum followed by the type-name and then the variable-list.

The enumeration list is a comma-separated list of names representing the enumeration values. The variable list is optional because variables may be declared later using the enumeration type name. Although enumerated constants are automatically converted to integers, integers are not automatically converted into enumerated constants

The following code declares an enumerator called month with the first enum variable value set to one. An enumerator variable is declared called now and set to the value jun. The value of 6 is then output to the screen.

#include <stdio.h>
enum month {Jan=1, Feb, Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec };
int main()
{
    // creating now variable of enum month type
    enum month now;
    now = Jun;
    printf("Day %d",now);
    return 0;
}

Extern

The extern keyword enables the programmer to declare a variable without defining it. In programs consisting of several files, each file must be aware of the global variables defined outside that file. The declaration informs the compiler that a variable by that name and type exists, but the compiler does not need to allocate memory since it is allocated elsewhere. The syntax is –

extern int x; //declares a int x value which has been defined elsewhere

The Basics

A simple piece of C code

#include <stdio.h>
int main()
{
/* my first program in C */
printf("Hello, World! \n");
return 0;
}

#include <stdio.h>

The first line of the program is a preprocessor directive which tells a C compiler to include the contents of file stdio.h. Include files contain additional information used by the program file during compilation. Stdio.h file stands for standard input-output header file and contains various prototypes and macros to perform input or output (I/O)

Main Function 

The main() function is where program execution begins and is required by every executable C program. Every function must include a pair of braces marking the beginning and end of the function. Within the braces are statements that make up the main body of the program

Program Comments

Any part of a program that starts with /* and ends with */ is called a comment and is ignored by the compiler.  Programmers use comments to explain their code but do these not affect the running of the code

Printf Statement

The printf() statement is a library function used to display information on-screen. In the example above, printf outputs the contents of the quotation marks followed by a new line \n.

The Return Statement

All functions in C can return values. The main() function returns a value and in this instance, the value 0 indicates that the program has terminated normally.  A nonzero value returned by the return statement tells the operating system that an error has occurred. 

Semicolons

In C, the semicolon acts as a statement terminator and indicates to the parser where a statement ends.  Several statements can be included on one line as long as each statement is terminated with a semicolon.

Pointers and References

Pointers

A pointer is a variable that stores a memory address. Pointers provide the capability to manipulate computer memory directly. Since a non-generic pointer directly references another variable value it is necessary to specify which data type a pointer is pointed to. This is known as the base type.

A general pointer variable is declared as follows –

type *var-name;

The base type is important because the compiler needs to know how many bytes make up the value pointed to. Pointers can have any legal variable name however, the standard naming convention is to start each pointer name with p and capitalize the second letter, as in pAge or pHeap.

Initialising a Pointer

When created, all pointers should be initialised. A pointer not initialised is called a wild pointer and will contain a random or junk value. Wild pointers are dangerous because they cause a program to access invalid memory locations leading to unpredictable results when the pointer is used.

To initialise the pointer use the nullptr keyword. In earlier versions of C++, a pointer was assigned a null value when created by using either 0 or NULL as the value however due to ambiguities with function overloading the nullptr is now preferred. Examples of pointer initialisation are listed below –

int *pPointer = 0; int *pPointer = NULL; int *pPointer = nullptr; //Superceeds the above two methods of initialisation

Setting a Pointer to store a Variable Address

To store the address of a variable in a pointer use the referencing operator &.  When placed in front of a variable the referencing operator will always return the address of that variable.

int a_value = 30;  //declares int variable to value 30 int * pTr= &a_value; //declares pointer name pTr of type int and sets it to address of variable a_value

Assigning and Accessing Values

The indirection operator or dereferencing operator (*) operates on a pointer and returns the value stored in the address kept in the pointer variable. For example, if pTr is an int pointer and the address contains 30, using *pTr returns that int value. The dereferencing operators can also assign a new value to an address. Using *pTr = 101 will assign the value of 101 to the address stored at pointer pTr.

Pointer Arithmetic

There are only four arithmetic operators that can be used on pointers: ++, – –, +, and –

An increment or decrement operation on a pointer will point to the next value in the memory. The new location will represent the location of the next variable value and not the next byte of memory. For instance, using the ++ on an int pointer instructs the compiler to point to the next consecutive integer. Decrementing pointers ( — ) has the opposite effect. The address in the pointer is incremented or decremented by the size of the type being pointed to. This ensures that the pointer points to the beginning of some valid data and not to some arbitrary memory location. In the case of character pointers, an increment or decrement will only change the pointer value by 1 since characters are one byte long. Every other type of pointer will increase or decrease by the length of its base type.

Integer values can also be added or subtracted to or from a pointer. For instance, adding 5 to a pointer value means pointing to the 6th element beyond the pointer’s current address. In the code section below, a pointer is used to display the contents of an int array together with the address of each element-

#include <iostream> 
int main() 
{
int myvalues[10]={1,2,3,4,5,6,7,8,9,10};//declare and initialise array of ints
int *iPtr=nullptr;//declare pointer and set to null
iPtr=myvalues;//set pointer to address of first element in array
std::cout << "The size of an int " << sizeof(int)<< "\n";
for (int aNum : myvalues) // range based for
{
std::cout << "The array elements are " << *iPtr <<" address "<<std::dec << iPtr<<"\n";
iPtr++;//increase pointer
}
}

Pointer Comparisons

Pointers can also be compared by using relational operators, such as ==, <, and >. however, the two pointers must be of the same type. Two pointers of the same type are equal if they are both null, point to the same function, or represent the same address

Using the Const Keyword on Pointers

If the address contained in the pointer is declared constant then it cannot be changed, however, the data at that address can be changed:

int valueofint = 1; int* const pTr = &valueofint; *pTr = 10; // allowed because value pointed to can be changed int valueofint1 = 21; pTr = &valueofint1; // not allowed because pointer address cannot be changed

If the Data pointed to is declared as constant then it cannot be changed, but the address contained in the pointer can be changed

int valueofint = 1; const int* pTr = &valueofint; *pTr = 10; // not allowed because value pointed to cannot be changed int valueofint1 = 21; pTr = &valueofint1; //allowed because pointer address can be changed

If the pointer address and the value being pointed are declared constant neither can be changed.

int valueofint = 1; const int* const pTr = &valueofint; *pTr = 10;//not allowed because value pointed to cannot be changed int valueofint1 = 21; pTr=&valueofint1;//not allowed because pointer address cannot be changed

Const variables are useful when passing pointers to functions. If function parameters are declared with the most restrictive access possible then a function cannot modify the values passed to them thereby preventing unwanted changes to pointer values or data.

Pointer to a Pointer

Normally, a pointer contains the address of a variable however when we define a pointer to a pointer, the first pointer contains the address of the second pointer, which points to the location that contains the actual value. A variable that is a pointer to a pointer is declared by placing an additional asterisk in front of its name

int **var;

Accessing the target value requires that the asterisk operator be applied twice

#include <iostream> 
int main() 
{
int i=10;
int *pInt=&i;
int **pPtr=&pInt;
int ***ppPtr=&pPtr;
/*output size of pointer to pointer*/
std::cout << "the size of ppPtr " << sizeof(ppPtr)<<"\n";
/*dereference pInt and show address*/
std::cout << "The integer value is " << *pInt <<" address of pointer"<< pInt<<"\n";
/*dereference pPtr and show address*/
std::cout << "The integer value is " << **pPtr <<" address "<< pPtr<<"\n";
/*dereference ppPtr and show address*/
std::cout << "The integer value is " << ***ppPtr <<" address "<< ppPtr<<"\n";
}

Cpp will permit n-pointer variables and those variables will be represented with n number of asterisks (**********)

Void Pointers

The void or generic pointer is a special pointer with no associated data type. A void pointer is declared like a normal pointer but the void keyword is used to declare the pointer’s type.

void *pTr; // ptr is a void pointer

Since a void pointer does not know what type of object it is pointing to, it cannot be dereferenced without explicitly casting it to the base type before dereferencing. The code section below illustrates how to implement and dereference a void pointer. Note any attempt to print a value of the pVoid pointer will generate an error – 

#include <iostream> 
int main() 
{
int i=10;
void *pVoid=&i;/*declare void pointer*/
int *pInt = static_cast<int*>(pVoid);/*cast void pointer*/
std::cout<< "The integer value is " << *pInt <<" address "<< pInt<<"\n";/*output ponter value*/
}

Pointer arithmetic is not possible on void pointers since the pointer is of an unknown base type and hence the compiler has no idea of its size in memory. In general, it is a good idea to avoid using void pointers as they bypass compiler type checking. Void pointers are used to implement generic functions.

Why use Pointers?

Pointers are useful because they allow the passing of data structures to functions more efficiently. Since there is no data duplication, passing by direct reference increases overall efficiency, especially regarding speed and memory usage. Pointers also allow the management of dynamically allocated memory.

Potential Problems with Pointers 

Since the misuse of pointers can be a major source of bugs, and security vulnerabilities and can make code unnecessarily complex, pointers are best avoided in C++ where possible. Some of the potential problems with the careless use of pointers are – 

  • uninitialised pointers – the value stored in an uninitialised pointer could be pointing to anywhere in memory.  Storing a value using an uninitialised pointer has the potential to overwrite anything in a program, including the program itself.  Therefore pointers should always be initialised
  • memory leaks – caused when pointers to a value allocated on the heap have been lost.
  • dangling pointers – a pointer pointing to an object that has been deleted.  Although the pointer still has the object address, the memory for that object will have been returned to the system.

References

A reference variable is an alias for an existing variable.  A reference, like a pointer, is also implemented by storing the address of an object however a reference differs from a pointer in that it cannot be null, cannot be reassigned, does not allow arithmetic operation, does not allow redirection, and  shares the same memory address with the original variable

A reference is declared using the reference operator ( & )

#include <iostream> 
int main() 
{
int i=10;
int &r=i;//create reference and set to address of variable i
std::cout << "value of variable i " << i<<"\n";// output value of variable i
std::cout << "value of reference r " << r<<"\n";//output value of ref f
r=20;//changing value of i using alias
std::cout << "new value of variable i " << i<<"\n";// output new value of variable igo

Using Keyword Const on References

One of the major advantages of references is that they allow a called function to work on parameters that have not been copied from the calling function. Since it’s often important to ensure that the called function cannot change the original variable value, declaring a const reference parameter prevents any attempts at assigning a new value.

const int& constReference = originalvalue ;