You are on page 1of 32

http://www.newinterviewquestions.

com/cat/C-interview-questions/
http://www.newinterviewquestions.com/cat/C-interview-questions/?&iType=40&iDBLoc=80
http://www.bestsamplequestions.com/technical-questions/c-sample-questions/c-sample-questions-5.html

1.What are the different storage classes in C ?(Automatic,allocated,static)

2. Can static variables be declared in a header file ? -You can’t declare a static variable without defining it as
well (this is because the storage class modifiers static and extern are mutually exclusive). A static variable
can be defined in a header file, but this would cause each source file that included the header file to have its
own private copy of the variable, which is probably not what was intended.

3. Can include files be nested?-Yes

4. What is a null pointer?

5. How to reduce a final size of executable ?-Size of the final executable can be reduced using dynamic
linking for libraries.

6. What is the difference between strings and character arrays ?- A major difference is: string will have
static storage duration, whereas as a character array will not, unless it is explicity specified by using the static
keyword.
Actually, a string is a character array with following properties:
* the multibyte character sequence, to which we generally call string, is used to initialize an array of static
storage duration. The size of this array is just sufficient to contain these characters plus the terminating NUL
character.
* it not specified what happens if this array, i.e., string, is modified.
* Two strings of same value[1] may share same memory area. For example, in the following declarations:
char *s1 = “Calvin and Hobbes”;
char *s2 = “Calvin and Hobbes”;
the strings pointed by s1 and s2 may reside in the same memory location. But, it is not true for the following:

char ca1[] = “Calvin and Hobbes”;


char ca2[] = “Calvin and Hobbes”;
[1] The value of a string is the sequence of the values of the contained characters, in order.

7. Write down the equivalent pointer expression for referring the same element a[i][j][k][l] ?- a[i] == *(a+i)
a[i][j] == *(*(a+i)+j)
a[i][j][k] == *(*(*(a+i)+j)+k)
a[i][j][k][l] == *(*(*(*(a+i)+j)+k)+l)

8. Does there exist any other function which can be used to convert an integer or a float to a string ?-itoa() or
sprint().

9.Difference between const char* p and char const* p-a)value is constant but b) pointer is contant.
10. What is the quickest sorting method to use ? -quick sort, merge sort, and radix sort. But we can’t say
which one is quickest. It depends on situation.

11. When should the register modifier be used? -The register modifier hints to the compiler that the variable
will be heavily used and should be kept in the CPU’s registers, if possible, so that it can be accessed faster.

12. When does the compiler not implicitly generate the address of the first element of an array ?- Whenever
an array name appears in an expression such as

 array as an operand of the sizeof operator


 array as an operand of & operator
 array as a string literal initializer for a character array
13. What is the benefit of using #define to declare a constant ?-One place

14. When should a type cast be used ?- There are two situations in which to use a type cast. The first use is
to change the type of an operand to an arithmetic operation so that the operation will be performed properly.

The second case is to cast pointer types to and from void * in order to interface with functions that expect or
return void pointers.

15. How can I convert a string to a number?-many functions atoi().

16. Is it possible to execute code even after the program exits the main() function ?- The standard C library
provides a function named atexit() that can be used to perform cleanup operations when your program
terminates.

You can set up a set of functions you want to perform automatically when your program exits by passing
function pointers to the at exit() function.

17. Can a file other than a .h file be included with #include?-Yes

18. What is the purpose of main( ) function ?- The function main( ) invokes other functions within it. It is the
first function to be called when the program starts execution.

 It is the starting function


 It returns an int value to the environment that called the program
 Recursive call is allowed for main( ) also.
 It is a user-defined function
 Program execution ends when the closing brace of the function main( ) is reached.
 It has two arguments 1)argument count and 2) argument vector (represents strings passed).
 Any user-defined name can also be used as parameters for main( ) instead of argc and argv.

19. Why n++ executes faster than n+1 ?-The expression n++ requires a single machine instruction such as INR to
carry out the increment operation whereas, n+1 requires more instructions to carry out this operation.

20. What is the benefit of using const for declaring constants over #define ?- The benefit of using the const
keyword is that the compiler might be able to make optimizations based on the knowledge that the value of
the variable will not change. In addition, the compiler will try to ensure that the values won’t be changed
inadvertently.

Of course, the same benefits apply to #defined constants. The reason to use const rather than #define to
define a constant is that a const variable can be of any type (such as a struct, which can’t be represented by a
#defined constant).

Also, because a const variable is a real variable, it has an address that can be used, if needed, and it resides in
only one place in memory.

21. Is it better to use a macro or a function ?- The answer depends on the situation you are writing code for.
Macros have the distinct advantage of being more efficient (and faster) than functions, because their
corresponding code is inserted directly into your source code at the point where the macro is called.

There is no overhead involved in using a macro like there is in placing a call to a function. However, macros
are generally small and cannot handle large, complex coding constructs.

A function is more suited for this type of situation. Additionally, macros are expanded inline, which means
that the code is replicated for each occurrence of a macro. Your code therefore could be somewhat larger
when you use macros than if you were to use functions.

Thus, the choice between using a macro and using a function is one of deciding between the tradeoff of faster
program speed versus smaller program size. Generally, you should use macros to replace small, repeatable
code sections, and you should use functions for larger coding tasks that might require several lines of code.

22. Why a function cannot be declared with in another function?-1.structural pl so must be modular. local
and globle scope.

23. C Program to Get the Current System Time.

#include <stdio.h>
#include <dos.h>

int main(void)
{
struct time t;
gettime(&t);
printf(“The current time is: %2d:%02d:%02d\n”, t.ti_hour, t.ti_min, t.ti_sec); return 0;
}

24. Where does standard function declared and defined.-.h- declaration and code to invoke system call or
library calls. .lib-defination.

25. What will we get if we use printf in printf.-return value of inner printf.

26.where the auto variable is stored-Stacks.

27.where the register variable stored-CPU Registers.

28.What are defferent memory area in c and c++ lang. –const data, stack, free store, heap, globle/static

Memory Area Characteristics and Object Lifetimes


-------------- ------------------------------------------------

Const Data The const data area stores string literals and
other data whose values are known at compile
time. No objects of class type can exist in
this area. All data in this area is available
during the entire lifetime of the program.

Further, all of this data is read-only, and the


results of trying to modify it are undefined.
This is in part because even the underlying
storage format is subject to arbitrary
optimization by the implementation. For
example, a particular compiler may store string
literals in overlapping objects if it wants to.

Stack The stack stores automatic variables. Typically


allocation is much faster than for dynamic
storage (heap or free store) because a memory
allocation involves only pointer increment
rather than more complex management. Objects
are constructed immediately after memory is
allocated and destroyed immediately before
memory is deallocated, so there is no
opportunity for programmers to directly
manipulate allocated but uninitialized stack
space (barring willful tampering using explicit
dtors and placement new).

Free Store The free store is one of the two dynamic memory
areas, allocated/freed by new/delete. Object
lifetime can be less than the time the storage
is allocated; that is, free store objects can
have memory allocated without being immediately
initialized, and can be destroyed without the
memory being immediately deallocated. During
the period when the storage is allocated but
outside the object's lifetime, the storage may
be accessed and manipulated through a void* but
none of the proto-object's nonstatic members or
member functions may be accessed, have their
addresses taken, or be otherwise manipulated.

Heap The heap is the other dynamic memory area,


allocated/freed by malloc/free and their
variants. Note that while the default global
new and delete might be implemented in terms of
malloc and free by a particular compiler, the
heap is not the same as free store and memory
allocated in one area cannot be safely
deallocated in the other. Memory allocated from
the heap can be used for objects of class type
by placement-new construction and explicit
destruction. If so used, the notes about free
store object lifetime apply similarly here.

Global/Static Global or static variables and objects have


their storage allocated at program startup, but
may not be initialized until after the program
has begun executing. For instance, a static
variable in a function is initialized only the
first time program execution passes through its
definition. The order of initialization of
global variables across translation units is not
defined, and special care is needed to manage
dependencies between global objects (including
class statics). As always, uninitialized proto-
objects' storage may be accessed and manipulated
through a void* but no nonstatic members or
member functions may be used or referenced
outside the object's actual lifetime.

29. how to add 2 no without + operator?

a) binary convertion and | op.

b) using for loop.for(i=1;i<=b;i++,a++);

c) c=a^b;-bitwise operator.

d) a-(-b).

c) C= B-A; D=A-C; A=A*3-D;

30. how can i write a program without main?


atleast can i print a character without entering to main?-No Way.

31. what type of function is main()?


call by value/reference...Both.

32. Why C is called a portable language?what is platform independency?- portability means the programs done in
some system can be run on different systems provided they have same operating system.the property of the
programs not to depend on OS is called platform independency, C programs can be run on any platform like Fedora
Linux,Microsoft XP & any Other OS,Hence Its a Poratble as well as Platform Independent Langauge.

33. What is near, far and huge pointers? How many bytes are occupied by them?

34.what is dangling and wild pointer-Dangling pointers and wild pointers in computer programming are
pointers that do not point to a valid object of the appropriate type.

Dangling pointers arise when an object is deleted or deallocated, without modifying the value of the pointer,
so that the pointer still points to the memory location of the deallocated memory.

Wild pointers arise when a pointer is used prior to initialization to some known state, which is possible in
some programming languages. They show the same erratic behaviour as dangling pointers, though they are
less likely to stay undetected.

35. Are the expressions arr and &arr same for an array of integers? Yes since both will return the base
address but also No since arr gives value at base address and &arr gives base address of array. It depends
upon situation.

36. How would you dynamically allocate a one-dimensional and two-dimensional


array of integers?

37. How can you increase the size of a dynamically allocated array?

What would be the output of this program?


1.main()
{
int x=20;
{
int x=10;
printf(“%d”,x);
}
printf(“%d”,x);
}

2.main()
{
int x=5;
x=x++;
printf(“x=%d”,x);
}

3.main()
{
int x=10;
printf(“%d%d”,++x,++x);
}
4.main()
{
struct student
{
char name[20];
int age;
};
struct student s1={“anil”,28};
struct student s2=s1;
(s1==s2)?printf(“equal”):printf(“different”);
}

5.main()
{
char s1[]={”anil”};
char s2[]={“anil”};
if(s1==s2)?printf(“equal”):printf(“different”);
}
6.main()
{
int a=-3,b=2,c=0,d;
d=++a&&++b||++c;
printf(“a=%db=%dc=%dd=%d”,a,b,c,d);
}
7. void main()
{
int const * p=5;
printf("%d",++(*p));
}
//error can’t change contant value.
8. main()
{
char s[ ]="man";
int i;
for(i=0;s[ i ];i++)
printf("\n%c%c%c%c",s[ i ],*(s+i),*(i+s),i[s]);
}
mmmm
aaaa
nnnn
9. main()
{
float me = 1.1;
double you = 1.1;
if(me==you)
printf("I love U");
else
printf("I hate U");
}
I hate U
10.main()
{
static int var = 5;
printf("%d ",var--);
if(var)
main();
}
Answer:

54321
11. #include‹stdio.h›
main()
{
char s[]={'a','b','c','\n','c','\0'};
char *p,*str,*str1;
p=&s[3];
str=p;
str1=s;
printf("%d",++*p + ++*str1-32);
}

Answer:

77(11+98-32) //\n=10 which is increamented to 11,a=97 which is ++ so 98 or b


12. #include‹stdio.h›
main()
{
struct xx
{
int x=3;
char name[]="hello";
};
struct xx *s;
printf("%d",s->x);
printf("%s",s->name);

compiler error.
13. main()
{
int i=5;
printf("%d%d%d%d%d%d",i++,i--,++i,--i,i);
}

Answer:

45545

Explanation:
The arguments in a function call are pushed into the stack from left to right. The evaluation is by popping out
from the stack. and the evaluation is from right to left, hence the result.
13.main()
{
printf("%p",main);
}

Answer:

Some address will be printed.

Explanation:

Function names are just addresses (just like array names are addresses).
14. enum colors {BLACK,BLUE,GREEN}
main()
{

printf("%d..%d..%d",BLACK,BLUE,GREEN);

return(1);
}

0..1..2

15. main()
{
int i=400,j=300;
printf("%d..%d");
}

Answer:

400..300

Explanation:

printf takes the values of the first two assignments of the program. Any number of printf's may be given. All
of them take only the first two values. If more number of assignments given in the program,then printf will
take garbage values.
16. main()
{
int i;
printf("%d",scanf("%d",&i)); // value 10 is given as input here
}

Answer:

Memory Areas in C Language

When we come across memory segments in C program these are the questions that comes to our mind.

 What happens when a c program is loaded into memory?


 Where are the different types of variables allocated?
 Why do we need two data sections, initialized and un-initialized?
 If we initialize a static or global variable with 0 where will it be stored?
Even though the scope of global and static variables are different, why are they stored in same section i.e.,
data segment?

Let’s look at some of these interesting under hood details here. We know that a C program which is compiled
to an executable and loaded into memory for execution has 4 main segments in memory. They are data, code,
stack, and heap segments.
The data and code segments are of fixed size. When a program is compiled, at that point itself, the sizes
required for the segments are fixed and known. Hence they are known as static segments. The sizes of the
stack and heap areas are not known when the program gets compiled. Also it is possible to change or
configure the sizes of these areas (i.e., increase or decrease). So, these are called dynamic segments.
Let’s look at each of these segments in detail.

Data segment:- the data segment is to hold the value of those variables that need to be available throughout
the life time of the program. So it is obvious that global variables should be allocated in the data segment.
How about local variables declared as static? Yes, they are also allocated in the data area because their values
should be available across function calls. If they are allocated in the stack frame itself, they will get destroyed
once the function returns. The only option is to allocate them in a global area. Hence, they are allocated in
this segment. So, the life time of a local static variable is that of the life time of the program.

There are two parts in this segment. The initialized data segment and u-initialized data segment.
When variables are initialized to some value (other than 0 or which is different value), they are allocated in
the initialized segment. When the variables are un initialized they get allocated in the un-initialized data
segment. This segment is usually referred to with cryptic acronym called BSS. It stands for block starting
with symbol and gets its name from old IBM systems which had that segments initialized to zero.
The data area is separated into two based on explicit initialization, because the variables that are need to be
initialized need not be initialized with zeros one by one. However the variables that are not initialized need
not to be explicitly initialized with zeros one by one. Instead the job of initialization of variables to zero is
left to the operating system to take care of. This bulk initialization can greatly reduce the time required to
load.

When we want to run an executable program, the OS starts a program known as loader. When this loads the
file into memory, it takes the BSS segment and initializes the whole thing to zeros. That is why the un-
initialized global data and static data always get the default value of zero.

The layout of data segment is in the control of the underlying OS. However some loaders give partial control
to the users. This information may be useful in applications such as embedded systems.
The data area can be addressed and accessed using pointers from the code. Automatic variables have an
overhead in initializing the variables each time they are required, and code is required to do that
initialization. However, variables in the data area do not have such runtime overhead, because the
initialization is done only once and that too at loading time.

Code segment:- the program code is where the executable code is available for execution. This area is also
known as the text segment and is of fixed size. This can be accessed only by function pointers and not by
other data pointers. Another important piece of information to take note of here is that the system may
consider this area as a read only memory area and any attempt to write in this area can lead to undefined
behavior.

Stack and heap segments:- to execute the program two major parts of the memory used are stack and heap.
Stack frames area created in the stack for functions and in the heap for dynamic memory allocation. The
stack and heap are un-initialized areas. Therefore whatever happens to be in the memory becomes the initial
(garbage) value for the objects created in that space.

The local variable and function arguments are allocated in the stack. For the local variables that have an
initialization value, code is generated by the compiler to initialize them explicitly to those values when the
stack frames are created. For function parameters the compiler generates code to copy the actual arguments
to the space allocated for the parameters in the stack frame.

Here, we will take a small program and see where different program elements are stored when that program
executes. The comments explain where the variables get stored.

int bss1;
static double bss2;
char *bss3;
// these are stored in initialized to zero segment also known as un-initialized data segment(BSS)
int init1=0;
float init2=10.0f
char *init3=”hello world”;
// these are stored in initialized data segment
// the code for main function gets stored in the code segment
int main
{
int local1=10; // this variable is stored in the stack and initialization code is generated by compiler.
int local2; //this variable is not initialized hence it has garbage value. It does not get initialized to zero.
static int local3; // this is allocated in the BSS segment and gets initialized to zero
static int local4=100; //this gets allocated in initialed data segment
int (*local-foo) (const char* —)= printf; // printf is in a shared library (libc or c runtime library)
// load-foo is a local variable(function pointer) that points to the printf function local-foo(“hello world”); this
function call results in the creation of stack frame in stack area
int *loacl5=malloc(sizeof(int));
// allocated in stack however it points to dynamically allocated block in heap.
return 0;
// stack frame for the main function gets destroyed after executing main
}

There several tools to check where a variable gets stored in the memory. But the easy to use tool is nm.

The main function is allocated in the text/code segment.

THE C STORAGE CLASSES, SCOPE AND MEMORY


ALLOCATION 1
  Z.1  INTRODUCTION
 The storage class determines the part of memory where storage is allocated for an object
(particularly variables and functions) and how long the storage allocation continues to exist.
 A scope specifies the part of the program which a variable name is visible, that is the
accessibility of the variable by its name.  In C program, there are four storage classes:
automatic, register, external, and static.
 Keep in mind that in the hardware terms we have primary storage such as registers, cache,
memory (Random Access Memory) and secondary storage such as magnetic and optical
disk.
Z.1.1  AUTOMATIC VARIABLE - auto
 They are declared at the start of a program’s block such as in the curly braces ( { } ). 
Memory is allocated automatically upon entry to a block and freed automatically upon exit
from the block.
 The scope of automatic variables is local to the block in which they are declared, including
any blocks nested within that block. For these reasons, they are also called local
variables.
 No block outside the defining block may have direct access to automatic variables (by
variable name) but, they may be accessed indirectly by other blocks and/or functions using
pointers.
 Automatic variables may be specified upon declaration to be of storage class auto. 
However, it is not required to use the keyword auto because by default, storage class
within a block is auto.
 
 Automatic variables declared with initializers are initialized every time the block in which
they are declared is entered or accessed.
Z.1.2  REGISTER VARIABLE - register

 Automatic variables are allocated storage in the main memory of the computer; however,
for most computers, accessing data in memory is considerably slower than processing
directly in the CPU.
 Registers are memory located within the CPU itself where data can be stored and
accessed quickly.  Normally, the compiler determines what data is to be stored in the
registers of the CPU at what times.
 However, the C language provides the storage class register so that the programmer can
suggest to the compiler that particular automatic variables should be allocated to CPU
registers, if possible and it is not an obligation for the CPU to do this.
 Thus, register variables provide a certain control over efficiency of program execution.
 Variables which are used repeatedly or whose access times are critical may be declared to
be of storage class register.
 Variables can be declared as a register as follows:
register  int  var;
 

Z.1.3  EXTERNAL VARIABLE - extern


 All variables we have seen so far have had limited scope (the block in which they are
declared) and limited lifetimes (as for automatic variables).
 However, in some applications it may be useful to have data which is accessible from within
any block and/or which remains in existence for the entire execution of the program.  Such
variables are called global variables, and the C language provides storage classes which
can meet these requirements; namely, the external (extern) and static (static) classes.
 Declaration for external variable is as follows:
extern int var;
 External variables may be declared outside any function block in a source code file the
same way any other variable is declared; by specifying its type and name (extern keyword
may be omitted).
 Typically if declared and defined at the beginning of a source file, the extern keyword can be
omitted.  If the program is in several source files, and a variable is defined in let say file1.c
and used in file2.c and file3.c then the extern keyword must be used in file2.c and file3.c.
 But, usual practice is to collect extern declarations of variables and functions in a separate
header file (.h file) then included by using #include directive.
 Memory for such variables is allocated when the program begins execution, and remains
allocated until the program terminates.  For most C implementations, every byte of memory
allocated for an external variable is initialized to zero.
 The scope of external variables is global, i.e. the entire source code in the file following the
declarations. All functions following the declaration may access the external variable by
using its name.  However, if a local variable having the same name is declared within a
function, references to the name will access the local variable cell.

 The following program example demonstrates storage classes and scope.
/* storage class and scope */

#include <stdio.h>

void funct1(void);

void funct2(void);

 /* external variable, scope is global to main(), funct1() and funct2(), extern keyword is omitted here,
coz just one file */

int globvar = 10;

 int main()

    printf("\n****storage classes and scope****\n");

    /* external variable */

    globvar = 20;


    

    printf("\nVariable globvar, in main() = %d\n", globvar);

    funct1();

    printf("\nVariable globvar, in main() = %d\n", globvar);

    funct2();

    printf("\nVariable globvar, in main() = %d\n", globvar);

    return 0;

/* external variable, scope is global to funct1() and funct2() */

int globvar2 = 30;

void funct1(void)

    /* auto variable, scope local to funct1() and funct1() cannot access the external globvar */

    char globvar;

   

    /* local variable to funct1() */

    globvar = 'A';

    /* external variable */

    globvar2 = 40;

   

    printf("\nIn funct1(), globvar = %c and globvar2 = %d\n", globvar, globvar2);

 
void funct2(void)

    /* auto variable, scope local to funct2(), and funct2() cannot access the external globvar2 */

    double globvar2;

    /* external variable */

    globvar =  50;

    /* auto local variable to funct2() */

    globvar2 = 1.234;

    printf("\nIn funct2(), globvar = %d and globvar2 = %.4f\n", globvar, globvar2);

}
 

Output:
 

 External variables may be initialized in declarations just as automatic variables; however,


the initializers must be constant expressions. The initialization is done only once at
compile time, i.e. when memory is allocated for the variables.
 In general, it is a good programming practice to avoid using external variables as they
destroy the concept of a function as a 'black box' or independent module.
 The black box concept is essential to the development of a modular program with modules. 
With an external variable, any function in the program can access and alter the variable,
thus making debugging more difficult as well.  This is not to say that external variables
should never be used.
 There may be occasions when the use of an external variable significantly simplifies the
implementation of an algorithm.  Suffice it to say that external variables should be used
rarely and with caution.
 Z.1.4  STATIC VARIABLE - static
 As we have seen, external variables have global scope across the entire program (provided
extern declarations are used in files other than where the variable is defined), and have a
lifetime over the entire program run.
 Similarly, static storage class provides a lifetime over the entire program, however; it
provides a way to limit the scope of such variables, and static storage class is declared with
the keyword static as the class specifier when the variable is defined.
 These variables are automatically initialized to zero upon memory allocation just as
external variables are.  Static storage class can be specified for automatic as well as
external variables such as:
static extern varx;
 Static automatic variables continue to exist even after the block in which they are defined
terminates. Thus, the value of a static variable in a function is retained between repeated
function calls to the same function.
 The scope of static automatic variables is identical to that of automatic variables, i.e. it is
local to the block in which it is defined; however, the storage allocated becomes permanent
for the duration of the program.
 Static variables may be initialized in their declarations; however, the initializers must be
constant expressions, and initialization is done only once at compile time when memory is
allocated for the static variable.
/* static storage class program example */

#include <stdio.h>

#define MAXNUM 3

void sum_up(void);

int main()

    int count;

    

    printf("\n*****static storage*****\n");

    printf("Key in 3 numbers to be summed ");

    for(count = 0; count < MAXNUM; count++)

        sum_up();

    printf("\n*****COMPLETED*****\n");

    return 0;

void sum_up(void)
{

    /* at compile time, sum is initialized to 0 */

    static int sum = 0;

    int num;

   

    printf("\nEnter a number: ");

    scanf("%d", &num);

    sum += num;

    printf("\nThe current total is: %d\n", sum);

}
 

 While the static variable, sum, would be automatically initialized to zero, it is better to do so
explicitly.
 In any case, the initialization is performed only once at the time of memory allocation by the
compiler.  The variable sum retains its value during program execution.
 Each time the sum_up() function is called, sum is incremented by the next integer read.  To
see the different you can remove the static keyword, re-compile and re-run the program.
Z.2  DYNAMIC MEMORY ALLOCATION  
 In the previous section we have described the storage classes which determined how
memory for variables is allocated by the compiler.
 When a variable is defined in the source program, the type of the variable determines
how much memory the compiler allocates.
 When the program executes, the variable consumes this amount of memory regardless of
whether the program actually uses the memory allocated. This is particularly true for
arrays.
 However, in many situations, it is not clear how much memory the program will actually
need.  For example, we may have declared arrays to be large enough to hold the
maximum number of elements we expect our application to handle.
 If too much memory is allocated and then not used, there is a waste of memory.  If not
enough memory is allocated, the program is not able to fully handle the input data.
 We can make our program more flexible if, during execution, it could allocate initial and
additional memory when needed and free up the memory when it is no more needed.
 Allocation of memory during execution is called dynamic memory allocation.  C provides
library functions to allocate and free up memory dynamically during program execution. 
Dynamic memory is allocated on the heap by the system.
 It is important to realize that dynamic memory allocation also has limits.  If memory is
repeatedly allocated, eventually the system will run out of memory.
Z.3  PROCESS MEMORY LAYOUT
 A running program is called a process and when a program is run, its executable image is
loaded into memory area that normally called a process address space in an organized
manner.
 This is a physical memory space and do not confuse yourself with the virtual address space
explained in Module W.
 Process address space is organized into three memory areas, called segments: the text
segment, stack segment, and data segment (bss and data) and can be illustrated below.

 
Figure: z.1

 The text segment (also called a code segment) is where the compiled code of the program
itself resides.
 The following Table summarizes the segments in the memory address space layout as
illustrated in the previous Figure.
Segment Description

Code - Often referred to as the text segment, this is the area in which the
text executable or binary image instructions reside.  For example,
segmen Linux/Unix arranges things so that multiple running instances of the
t same program share their code if possible.  Only one copy of the
instructions for the same program resides in memory at any time. 
The portion of the executable file containing the text segment is the
text section.

Statically allocated and global data that are initialized with nonzero
values live in the data segment.  Each process running the same
Initialized data – data segment
program has its own data segment.  The portion of the executable file
containing the data segment is the data section.

BSS stands for ‘Block Started by Symbol’.  Global and statically


allocated data that initialized to zero by default are kept in what is
called the BSS area of the process.  Each process running the same
program has its own BSS area.  When running, the BSS, data are
Uninitialized data – bss segment
placed in the data segment.  In the executable file, they are stored in
the BSS section.  For Linux/Unix the format of an executable, only
variables that are initialized to a nonzero value occupy space in the
executable’s disk file.

The heap is where dynamic memory (obtained by malloc(), calloc(),


realloc() and new – C++) comes from.  Everything on a heap is
anonymous, thus you can only access parts of it through a pointer.
As memory is allocated on the heap, the process’s address space
grows.  Although it is possible to give memory back to the system
and shrink a process’s address space, this is almost never done
because it will be allocated to other process again.   Freed memory
(free() and delete – C++) goes back to the heap, creating what is
Heap
called holes.   It is typical for the heap to grow upward.  This means
that successive items that are added to the heap are added at
addresses that are numerically greater than previous items.  It is also
typical for the heap to start immediately after the BSS area of the
data segment.  The end of the heap is marked by a pointer known as
the break. You cannot reference past the break. You can, however,
move the break pointer (via brk() and sbrk() system calls) to a new
position to increase the amount of heap memory available.

Stack The stack segment is where local (automatic) variables are


allocated.  In C program, local variables are all variables declared
inside the opening left curly brace of a function's body including the
main() or other left curly brace that aren’t defined as static.  The data
is popped up or pushed into the stack following the Last In First
Out (LIFO) rule.  The stack holds local variables, temporary
information, function parameters, return address and the like.  When
a function is called, a stack frame (or a procedure activation record)
is created and PUSHed onto the top of the stack. This stack frame
contains information such as the address from which the function
was called and where to jump back to when the function is finished
(return address), parameters, local variables, and any other
information needed by the invoked function. The order of the
information may vary by system and compiler.  When a function
returns, the stack frame is POPped from the stack.  Typically the
stack grows downward, meaning that items deeper in the call chain
are at numerically lower addresses and toward the heap.

Table z.1

 In the disk file (object files) the segments were called sections.
 By using a C program, the segments can be illustrated below.
 

Figure z.2

Z.4  SOME TERMS


 In C language memory allocation through the variables in C programs is supported by two
kinds of memory allocation as listed in the following Table.
Memory Allocation
Description
Type
Static allocation This allocation happens when you declare a static or global
variable.  Each static or global variable defines one block of
space, of a fixed size.  The space is allocated once, when your
program is started, and is never freed.  In memory address
space, for uninitialized variables are stored in bss segment
while an initialized variables stored in data segment.

This allocation happens when you declare an automatic


variable, such as a function argument or a local variable. The
space for an automatic variable is allocated when the
Automatic allocation
compound statement containing the declaration is entered, and
is freed when that compound statement is exited.  As
discussed before this allocation done in the stack segment.

Table z.2

 Dynamic allocation is not supported by C variables; there is no storage class called


‘dynamic’, and there can never be a C variable whose value is stored in dynamically
allocated space. All must be done manually using related functions.
 The only way to refer to dynamically allocated space is through a pointer.  Because it is
less convenient, and because the actual process of dynamic allocation requires more
computation time, programmers generally use dynamic allocation only when neither static
nor automatic allocation will serve.
 The dynamic allocation done by using functions and the memory used is heap area.
Z.5  STACK AND HEAP
 The stack is where memory is allocated for automatic variables within functions.  A stack is
a Last In First Out (LIFO) storage where new storage is allocated and de-allocated at only
one end, called the top of the stack.  Every function call will create a stack (normally called
stack frame) and when the function exit, the stack frame will be destroyed.
 By referring the following program example and Figure z.3, when a program begins
execution in the function main(), stack frame is created, space is allocated on the stack for
all variables declared within main().
 Then, when main() calls a function, a(), new stack frame is created for the variables in a() at
the top of the main() stack.  Any parameters passed by main() to a() are stored on this
stack.
 If a() were to call any additional functions such as b() and c(), new stack frames would be
allocated at the new top of the stack.  Notice that the order of the execution happened in the
sequence.
 When c(), b() and a() return, storage for their local variables are de-allocated, the stack
frames are destroyed and the top of the stack returns to the previous condition.  The order
of the execution is in the reverse.
 As can be seen, the memory allocated in the stack area is used and reused during program
execution.  It should be clear that memory allocated in this area will contain garbage values
left over from previous usage.
#include <stdio.h>

int a();

int b();

int c();

int a()

b();

c();

return 0;

int b()

{ return 0; }

int c()

{ return 0; }

int main()

a();

return 0;
}

 By taking just the stack area, the following Figure illustrates what had happened to the stack
when the above program is run.  At the end there should be equilibrium.

Figure z.3:  Stack frame and function call

 
Z.5.1  FUNCTION CALLING CONVENTION
 It has been said before, for every function call there will be a creation of a stack frame.  It is
very useful if we can study the operation of the function call and how the stack frame for
function is constructed and destroyed.
 For function call, compilers have some convention used for calling them.  A convention is a
way of doing things that is standardized, but not a documented standard.
 For example, the C/C++ function calling convention tells the compiler things such as:
1. The order in which function arguments are pushed onto the stack.
2. Whether the caller function or called function (callee) responsibility to remove the arguments
from the stack at the end of the call that is the stack cleanup process.
3. The name-decorating convention that the compiler uses to identify individual functions.
 Examples for calling conventions are __stdcall, __pascal, __cdecl and __fastcall (for
Microsoft Visual C++).
 The calling convention belongs to a function's signature, thus functions with different calling
convention are incompatible with each other.
 There is currently no standard for C/C++ naming between compiler vendors or even
between different versions of a compiler for function calling scheme.
 That is why if you link object files compiled with other compilers may not produce the same
naming scheme and thus causes unresolved externals.  For Borland and Microsoft
compilers you specify a specific calling convention between the return type and the
function's name as shown below.
void __cdecl TestFunc(float a, char b, char c); // Borland and Microsoft
 For the GNU GCC you use the __attribute__ keyword by writing the function definition
followed by the keyword __attribute__ and then state the calling convention in double
parentheses as shown below.
void TestFunc(float a, char b, char c) __attribute__((cdecl)); // GNU GCC
 As an example, Microsoft Visual C++ compiler has three function calling conventions used
as listed in the following table.
Stack
keyword Parameter passing
cleanup
Pushes parameters on the stack, in reverse order (right to left).  Caller
cleans up the stack.  This is the default calling convention for C language
that supports variadic functions (variable number of argument or type list
__cdecl caller such as printf()) and also C++ programs.  The cdecl calling convention
creates larger executables than __stdcall, because it requires each function
call (caller) to include stack cleanup code.

Also known as __pascal.  Pushes parameters on the stack, in reverse order


(right to left).  Functions that use this calling convention require a function
__stdcall callee prototype.  Callee cleans up the stack.  It is standard convention used in
Win32 API functions.

Parameters stored in registers, then pushed on stack.  The fastcall calling


__fastcal convention specifies that arguments to functions are to be passed in
callee
l registers, when possible.  Callee cleans up the stack.

Table z.3:  Function calling conventions

 Basically, C function calls are made with the caller pushing some parameters onto the stack,
calling the function and then popping the stack to clean up those pushed arguments.  For
__cdecl assembly example:
/* example of __cdecl */
push   arg1
push   arg2
call      function
add     ebp, 12   ;stack cleanup
 And for __stdcall example:
/* example of __stdcall */
push   arg1
push   arg2
call      function
/* no stack cleanup, it will be done by callee */
 It is a long story if we want to go into the details of the function calls, but this section
provides a good introduction :o).
Z.5.2  DYNAMIC ALLOCATION – THE FUNCTIONS
 The heap segment provides more stable storage of data for a program; memory allocated in
the heap remains in existence for the duration of a program.
 Therefore, global variables (external storage class), and static variables are allocated on the
heap.  The memory allocated in the heap area, if initialized to zero at program start, remains
zero until the program makes use of it.  Thus, the heap area need not contain garbage.
 In ANSI C (ISO/IEC C), there is a family of four functions which allow programs to
dynamically allocate memory on the heap.
 In order to use these functions you have to include the stdlib.h header file in your program. 
Table z.4 summarized these functions.
 Keep in mind that there are other functions you will find for dynamic memory allocation, but
they are implementation dependant.
Function Prototype and Description
malloc() void * malloc (size_t nbytes);
nbytes is the number of bytes that to be assigned to the pointer.  The function returns a pointer of type
void*.  When allocating memory, malloc() returns a pointer which is just a byte address.  Thus, it does
not point to an object of a specific type.  A pointer type that does not point to a specific data type is
said to point to void type, that is why we have to type cast the value to the type of the destination
pointer, for example:
 
char * test;
test = (char *) malloc(10);
 
This assigns test a pointer to a usable block of 10 bytes.
 
calloc() void * calloc (size_t nelements, size_t size);
calloc() is very similar to malloc() in its operation except its prototype have two parameters.  These
two parameters are multiplied to obtain the total size of the memory block to be assigned. Usually the
first parameter (nelements) is the number of elements and the second one (size) serves to specify the
size of each element. For example, we could define test with calloc():
 
int * test;
test = (int *) calloc(5, sizeof(int));
 
Another difference between malloc() and calloc() is that calloc() initializes all its elements to 0.
 
realloc() void * realloc (void * pointer, size_t elemsize);
It changes the size of a memory block already assigned to a pointer.  pointer parameter receives a
pointer to the already assigned memory block or a null pointer (if fail), and size specifies the new size
that the memory block shall have.  The function assigns size bytes of memory to the pointer.  The
function may need to change the location of the memory block so that the new size can fit; in that
case the present content of the block is copied to the new one.  The new pointer is returned by the
function and if it has not been possible to assign the memory block with the new size it returns a null
pointer.
 
free() void free (void * pointer);
It releases a block of dynamic memory previously assigned using malloc(), calloc() or realloc().  This
function must only be used to release memory assigned with functions malloc(), calloc() and realloc().
 
NULL is a defined constant used to express null
pointers, that is, an unassigned pointer (pointing to
NULL
the address 0) or a pointer that points to something
but not useful.
 
Defined type used as arguments for some functions
that require sizes or counts specifications.  This
size_t represents an unsigned value generally defined in
header files as unsigned int or by using typedef,
typedef unsigned int size_t;

Table z.4

 In practice, one must always verify whether the pointer returned is NULL.  If malloc() is
successful, objects in dynamically allocated memory can be accessed indirectly by
dereferencing the pointer, appropriately cast to the type of required pointer.
 The size of the memory to be allocated must be specified, in bytes, as an argument to
malloc().   Since the memory required for different objects is implementation dependent, the
best way to specify the size is to use the sizeof operator.  Recall that the sizeof operator
returns the size, in bytes, of the operand.
 For example, if the program requires memory allocation for an integer, then the size
argument to malloc() would be sizeof(int).
 However, in order for the pointer to access an integer object, the pointer returned by
malloc() must be cast to an int *.
 The typical code example may be in the following form:
int *theptr;
theptr = (int *)malloc(sizeof(int));
 Now, if the pointer returned by malloc() is not NULL, we can make use of it to access the
memory indirectly.  For example:
if (theptr != NULL)
*theptr = 23;
 Or, simply:
if (theptr)
*theptr = 23;
printf("Value stored is %d\n", *theptr);
 Later, when the memory allocated above may no longer be needed we have to free up the
memory using:
free((void *) theptr);
 This will de-allocate the previously allocated block of memory pointed to by theptr or simply,
we could write:
free(theptr);
 theptr is first converted to void * in accordance with the function prototype, and then the
block of memory pointed to by theptr is freed.
 It is possible to allocate a block of memory for several elements of the same type by giving
the appropriate value as an argument.  Suppose, we wish to allocate memory for 200 float
numbers.  If fptr is a:
float *
 Then the following statement does the job:
fptr = (float *) malloc(200 * sizeof(float));
 fptr pointer points to the beginning of the memory block allocated, that is the first object of
the block of 200 float objects, fptr + 1 points to the next float object, and so on.
 In other words, we have a pointer to an array of float type.  The above approach can be
used with data of any type including structures.
 In C++ the equivalent construct used are new for memory allocation and delete for de-
allocation.
-----------------------------------o0o -----------------------------------

*ABOUT near,far and huge pointer-A near pointer is a 16 bit pointer to an object contained in the current
segment, be it code segment, data segment, stack segment, or extra segment. The compiler can generate code
with a near pointer and does not have to concern itself with segment addressing, so using near pointers is
fastest, and generates smallest code. The limitation is that you can only access 64kb of data at a time, because
that is the size of a segment - 64kb. A near pointer contains only the 16 bit offset of the object within the
currently selected segment.

A far pointer is a 32 bit pointer to an object anywhere in memory. In order to use it, the compiler must
allocate a segment register, load it with the segment portion of the pointer, and then reference memory using
the offset portion of the pointer relative to the newly loaded segment register. This takes extra instructions
and extra time, so it is the slowest and largest method of accessing memory, but it can access memory that is
larger than 64kb, sometimes, such as when dealing with video memory, a needful thing. A far pointer
contains a 16 bit segment part and a 16 bit offset part. Still, at any one instant of time, without "touching"
segment registers, the program only has access to four 64kb chunks, or segments of memory. If there is a
100kb object involved, code will need to be written to consider its segmentation, even with far pointers.

Now, segments overlap. Each segment is 64kb in length, but each one overlaps the next and the prior by
65520 bytes. That means that every address in memory can be addressed by 64kb-1 different combinations of
segment:offset pairs. The result is that the total addressible memory was only 1mb, and the total usable
memory address space was 500kb to 600kb. That sounds odd, but Intel built it, Microsoft wrote it, and
DOS/Windows 3.1 grew up around it. I still have that computer, and it still works just fine, thank you. :-)>

Now the huge pointer. The far pointer suffers because you can not just add one to it and have it point the the
next item in memory - you have to consider segment:offset rules, because of the 16 byte offset issue. The
huge pointer is a monolithic pointer to some item with a large chunk of memory, and there are no
segment:offset boundaries.
Beautiful - huhh?? - well, in order to get that, the pointer to segment:offset calculation has to be done every
time you reference the pointer. It does allow you to create and manipulate a single monolithic object that is
greater than 64kb, but it has its costs.  

You might also like