Some very Cool Easy Technical aptitude
A copy constructor is called whenever an object is copied. This happens in
the following cases:
* When an object is create from another object during initialization (Class a
= b)
* When an object is created from another object as a parameter to a
constructor (Class a(b))
* When an object is passed by value as an argument to a function
(function(Class a))
* When an object is return from a function (Class a; … return a;)
* When an exception is thrown using this object type (Class a; …. throw
a;)
Whenever an object copying scenario like the ones above is encountered, the
copy constructor is invoked. A copy constructor can be either user defined or
compiler defined. If the user does not define a copy constructor, then the
default compiler defined copy constructor will be invoked during object copy
scenarios. The default copy constructor is a bit-by-bit (member wise) copy. But
often you will encounter situations where this is not desirable since this is
just a shallow copy & sometimes you do not want an exact copy or you may
want to do some custom resource management.
Class t1;
Class t2=t1; // Copy Constructor is invoked
Class t3;
t3=t1;. //
Assignment Operator is invoked
In the Code snippet above, the constructor is invoked twice, during the
creation of objects t1 & t3. (Creation of t2 invokes the copy constructor).
The destructor is invoked 3 times though. In cases like these, if the
constructor allocates memory & the destructor frees it, you will see the
t2's destructor will try to delete already deleted memory, if t1 is destroyed
before t2 or vice-versa. Meaning, you are hosed. To prevent this, a user defined
copy constructor needs to be provided. which doesn't do a simple bit-by-bit but
rather assigns memory specifically for the object & does a deep copy if
required.
To define a copy constructor for a class T, a constructor of the following
format needs to be defined.
Class T
{
…
T(const T& t)
….
}
You need a reference because if it were T(T t), it would end in a infinite
recursion. (Was that an oxymoron?). const because you are not changing the
object in the constructor, you are just copying its contents
Some Important Rules for technical C/C++ questions:
* Don't write a copy constructor if a bit-by-bit copy works for the
class
* If you defined your own copy constructor, it probably because you needed a
deep copy or some special resource management, in which case, you will need to
release these resources at the end, which means you probably need to define a
destructor & you may also want to think of overloading the assignment
operator (beware of self-assignment)
Q Does C have boolean variable type?
No, C does not have a boolean variable type.
One can use ints, chars, #defines or enums to achieve the same in
C.
#define TRUE 1
#define FALSE 0
enum bool {false, true};
An enum may be good if the debugger shows the
names of enum constants when examining variables.
Q Where may
variables be defined in C?
Outside a function definition (global scope,
from the point of definition downward in the source code). Inside a block before
any statements other than variable declarations (local scope with respect to the
block).
Q What does the typedef
keyword do?
This keyword provides a short-hand way to write
variable declarations. It is not a true data typing mechanism, rather, it is
syntactic "sugar coating".
For example
typedef struct node
{
int
value;
struct node *next;
}mynode;
This can later be used to declare variables
like this
mynode *ptr1;
& not by the lengthy
expression
struct node *ptr1;
There are three main reasons for using
typedefs:
* It makes the writing of complicated declarations a lot
easier. This helps in eliminating a lot of clutter in the code.
*
It helps in achieving portability in programs. That is, if we use typedefs for
data types that are machine dependent, only the typedefs need to change when the
program is ported to a new platform.
* It helps in providing better
documentation for a program. For example, a node of a doubly linked list is
better understood as ptrToList than just a pointer to a complicated
structure.
Q What is the difference between constants defined
through #define & the constant keyword?
A constant is similar to a variable in the
sense that it represents a memory location (or simply, a value). It is different
from a normal variable, in that it cannot change it's value in the proram - it
must stay for ever stay constant. In general, constants are a useful because
they can prevent program bugs & logical errors(errors are explained later).
Unintended modifications are prevented from occurring. The compiler will catch
attempts to reassign new values to constants.
Constants may be defined
using the preprocessor directive #define. They may also be defined using the
const keyword.
So whats the difference between these
two?
#define ABC 5
&
const int
abc = 5;
There are two main advantages of the second one
over the first technique. First, the type of the constant is defined. "pi" is
float. This allows for some type checking by the compiler. Second, these
constants are variables with a definite scope. The scope of a variable relates
to parts of your program in which it is defined.
There is also one good
use of the important use of the const keyword. Suppose you want to make use of
some structure data in some function. You will pass a pointer to that structure
as argument to that function. But to make sure that your structure is readonly
inside the function you can declare the structure argument as const in function
prototype. This will prevent any accidental modification of the structure values
inside the function.
Q What are Trigraph
characters?
These are used when you keyboard does not
support some special characters
??= #
??( [
??) ]
??< {
??> }
??!
|
??/ \
??' ^
??-
~
Q How are floating point numbers stored? Whats the IEEE
format?
IEEE Standard 754 floating point is the most
common representation today for real numbers on computers, including Intel-based
PC's, Macintoshes, & most Unix platforms.
IEEE floating point
numbers have three basic components: the sign, the exponent, & the mantissa.
The mantissa is composed of the fraction & an implicit leading digit
(explained below). The exponent base(2) is implicit & need not be
stored.
The following figure shows the layout for single (32-bit) &
double (64-bit) precision floating-point values. The number of bits for each
field are shown (bit ranges are in square brackets):
Sign Exponent Fraction
Bias
--------------------------------------------------
Single Precision 1 [31] 8 [30-23] 23 [22-00] 127
Double Precision 1
[63] 11 [62-52] 52 [51-00] 1023
The sign bit is as simple as it gets. 0 denotes
a positive number; 1 denotes a negative number. Flipping the value of this bit
flips the sign of the number.
The exponent field needs to represent
both positive & negative exponents. To do this, a bias is added to the
actual exponent in order to get the stored exponent. For IEEE single-precision
floats, this value is 127. Thus, an exponent of zero means that 127 is stored in
the exponent field. A stored value of 200 indicates an exponent of (200-127), or
73. For reasons discussed later, exponents of -127 (all 0s) & +128 (all 1s)
are reserved for special numbers. For double precision, the exponent field is 11
bits, & has a bias of 1023.
The mantissa, also known as the
significand, represents the precision bits of the number. It is composed of an
implicit leading bit & the fraction bits. To find out the value of the
implicit leading bit, consider that any number can be expressed in scientific
notation in many different ways. For example, the number five can be represented
as any of these:
5.00 × 100
0.05 × 10 ^
2
5000 × 10 ^ -3
In order to maximize the quantity of
representable numbers, floating-point numbers are typically stored in normalized
form. This basically puts the radix point after the first non-zero digit. In
normalized form, five is represented as 5.0 × 100. A nice little optimization is
available to us in base two, since the only possible non-zero digit is 1. Thus,
we can just assume a leading digit of 1, & don't need to represent it
explicitly. As a result, the mantissa has effectively 24 bits of resolution, by
way of 23 fraction bits.
So, to sum up:
1. The sign bit is 0 for positive, 1 for
negative.
2. The exponent's base is two.
3. The exponent
field contains 127 plus the true exponent for single-precision, or 1023 plus
the true exponent for double precision.
4. The first bit of the
mantissa is typically assumed to be 1.f, where f is the field of fraction
bits.
Q. When should the register modifier be
used?
The register modifier hints to the compiler
that the variable will be heavily used & should be kept in the CPU?s
registers, if possible, so that it can be accessed faster. There are several
restrictions on the use of the register modifier.
First, the variable
must be of a type that can be held in the CPU?s register. This usually means a
single value of a size less than or equal to the size of an integer. Some
machines have registers that can hold floating-point numbers as well. Second,
because the variable might not be stored in memory, its address cannot be taken
with the unary & operator. An attempt to do so is flagged as an error by the
compiler. Some additional rules affect how useful the register modifier is.
Because the number of registers is limited, & because some registers can
hold only certain types of data (such as pointers or floating-point numbers),
the number & types of register modifiers that will actually have any effect
are dependent on what machine the program will run on. Any additional register
modifiers are silently ignored by the compiler. Also, in some cases, it might
actually be slower to keep a variable in a register because that register then
becomes unavailable for other purposes or because the variable isn?t used enough
to justify the overhead of loading & storing it. So when should the register
modifier be used? The answer is never, with most modern compilers. Early C
compilers did not keep any variables in registers unless directed to do so,
& the register modifier was a valuable addition to the language. C compiler
design has advanced to the point, however, where the compiler will usually make
better decisions than the programmer about which variables should be stored in
registers. In fact, many compilers actually ignore the register modifier, which
is perfectly legal, because it is only a hint & not a directive.
Q. 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 & from void * in order to
interface with functions that expect or return void pointers. For example, the
following line type casts the return value of the call to malloc() to be a
pointer to a foo structure.
struct foo *p = (struct foo *)
malloc(sizeof(struct foo));
A type cast should not be used to override a
const or volatile declaration. Overriding these type modifiers can cause the
program to fail to run correctly. A type cast should not be used to turn a
pointer to one type of structure or data type into another. In the
rare
events in which this action is beneficial, using a union to hold the values
makes the programmer?s intentions clearer.
Q. Can structures be assigned to
variables & passed to & from functions?
Yes, they can!
But note that when
structures are passed, returned or assigned, the copying is done only at one
level (The data pointed to by any pointer fields is not copied!.
Q What is the difference between the
declaration & the definition of a variable?.
The definition is the one that actually
allocates space, & provides an initialization value, if any.
There
can be many declarations, but there must be exactly one definition. A definition
tells the compiler to set aside storage for the variable. A declaration makes
the variable known to parts of the program that may wish to use it. A variable
might be defined & declared in the same statement.
Q Do Global variables start out as
zero?
Q To what does the term storage class refer?
What are auto, static, extern, volatile, const classes?
This is a part of a variable declaration that
tells the compiler how to interpret the variable's symbol. It does not in itself
allocate storage, but it usually tells the compiler how the variable should be
stored. Storage class specifiers help you to specify the type of storage used
for data objects. Only one storage class specifier is permitted in a declaration
this makes sense, as there is only one way of storing things & if you omit
the storage class specifier in a declaration, a default is chosen. The default
depends on whether the declaration is made outside a function (external
declarations) or inside a function (internal declarations). For external
declarations the default storage class specifier will be extern & for
internal declarations it will be auto. The only exception to this rule is the
declaration of functions, whose default storage class specifier is always
extern.
Here are C's storage classes & what they
signify:
* auto - local variables.
* static -
variables are defined in a nonvolatile region of memory such that they retain
their contents though out the program's execution.
* register -
asks the compiler to devote a processor register to this variable in order to
speed the program's execution. The compiler may not comply & the variable
looses it contents & identity when the function it which it is defined
terminates.
* extern - tells the compiler that the variable is
defined in another module.
In C, const & volatile are type qualifiers.
The const & volatile type qualifiers are completely independent. A common
misconception is to imagine that somehow const is the opposite of volatile &
vice versa. This is wrong. The keywords const & volatile can be applied to
any declaration, including those of structures, unions, enumerated types or
typedef names. Applying them to a declaration is called qualifying the
declaration?that's why const & volatile are called type qualifiers, rather
than type specifiers.
* const means that something is not
modifiable, so a data object that is declared with const as a part of its type
specification must not be assigned to in any way during the run of a program.
The main intention of introducing const objects was to allow them to be put into
read-only store, & to permit compilers to do extra consistency checking in a
program. Unless you defeat the intent by doing naughty things with pointers, a
compiler is able to check that const objects are not modified explicitly by the
user. It is very likely that the definition of the object will contain an
initializer (otherwise, since you can't assign to it, how would it ever get a
value?), but this is not always the case. For example, if you were accessing a
hardware port at a fixed memory address & promised only to read from it,
then it would be declared to be const but not initialized.
*
volatile tells the compiler that other programs will be modifying this variable
in addition to the program being compiled. For example, an I/O device might need
write directly into a program or data space. Meanwhile, the program itself may
never directly access the memory area in question. In such a case, we would not
want the compiler to optimize-out this data area that never seems to be used by
the program, yet must exist for the program to function correctly in a larger
context. It tells the compiler that the object is subject to sudden change for
reasons which cannot be predicted from a study of the program itself, &
forces every reference to such an object to be a genuine reference.
* const volatile - Both constant & volatile.
The "volatile" modifier
The volatile
modifier is a directive to the compiler?s optimizer that operations involving
this variable should not be optimized in certain ways. There are two special
cases in which use of the volatile modifier is desirable. The first case
involves memory-mapped hardware (a device such as a graphics adaptor that
appears to the computer?s hardware as if it were part of the computer?s memory),
& the second involves shared memory (memory used by two or more programs
running simultaneously). Most computers have a set of registers that can be
accessed faster than the computer?s main memory. A good compiler will perform a
kind of optimization called ?redundant load & store removal.? The compiler
looks for places in the code where it can either remove an instruction to load
data from memory because the value is already in a register, or remove an
instruction to store data to memory because the value can stay in a register
until it is changed again anyway.
If a variable is a pointer to
something other than normal memory, such as memory-mapped ports on a
peripheral, redundant load & store optimizations might be detrimental. For
instance, here?s a piece of code that might be used to time some
operation:
time_t time_addition(volatile const struct
timer *t, int a)
{
int n;
int x;
time_t then;
x = 0;
then = t->value;
for
(n = 0; n < 1000; n++)
{
x = x + a;
}
return t->value - then;
}
In this code, the variable t->value is
actually a hardware counter that is being incremented as time passes. The
function adds the value of a to x 1000 times, & it returns the amount the
timer was incremented by while the 1000 additions were being performed. Without
the volatile modifier, a clever optimizer might assume that the value of t does
not change during the execution of the function, because there is no statement
that explicitly changes it. In that case, there?s no need to read it from memory
a second time & subtract it, because the answer will always be 0. The
compiler might therefore ?optimize? the function by making it always return 0.
If a variable points to data in shared memory, you also don?t want the compiler
to perform redundant load & store optimizations. Shared memory is normally
used to enable two programs to communicate with each other by having one program
store data in the shared portion of memory & the other program read the same
portion of memory. If the compiler optimizes away a load or store of shared
memory, communication between the two programs will be
affected.
No, C does not have a boolean variable type.
One can use ints, chars, #defines or enums to achieve the same in
C.
#define TRUE 1
#define FALSE 0
enum bool {false, true};
An enum may be good if the debugger shows the
names of enum constants when examining variables.
Q Where may
variables be defined in C?
Outside a function definition (global scope,
from the point of definition downward in the source code). Inside a block before
any statements other than variable declarations (local scope with respect to the
block).
Q What does the typedef
keyword do?
This keyword provides a short-hand way to write
variable declarations. It is not a true data typing mechanism, rather, it is
syntactic "sugar coating".
For example
typedef struct node
{
int
value;
struct node *next;
}mynode;
This can later be used to declare variables
like this
mynode *ptr1;
& not by the lengthy
expression
struct node *ptr1;
There are three main reasons for using
typedefs:
* It makes the writing of complicated declarations a lot
easier. This helps in eliminating a lot of clutter in the code.
*
It helps in achieving portability in programs. That is, if we use typedefs for
data types that are machine dependent, only the typedefs need to change when the
program is ported to a new platform.
* It helps in providing better
documentation for a program. For example, a node of a doubly linked list is
better understood as ptrToList than just a pointer to a complicated
structure.
Q What is the difference between constants defined
through #define & the constant keyword?
A constant is similar to a variable in the
sense that it represents a memory location (or simply, a value). It is different
from a normal variable, in that it cannot change it's value in the proram - it
must stay for ever stay constant. In general, constants are a useful because
they can prevent program bugs & logical errors(errors are explained later).
Unintended modifications are prevented from occurring. The compiler will catch
attempts to reassign new values to constants.
Constants may be defined
using the preprocessor directive #define. They may also be defined using the
const keyword.
So whats the difference between these
two?
#define ABC 5
&
const int
abc = 5;
There are two main advantages of the second one
over the first technique. First, the type of the constant is defined. "pi" is
float. This allows for some type checking by the compiler. Second, these
constants are variables with a definite scope. The scope of a variable relates
to parts of your program in which it is defined.
There is also one good
use of the important use of the const keyword. Suppose you want to make use of
some structure data in some function. You will pass a pointer to that structure
as argument to that function. But to make sure that your structure is readonly
inside the function you can declare the structure argument as const in function
prototype. This will prevent any accidental modification of the structure values
inside the function.
Q What are Trigraph
characters?
These are used when you keyboard does not
support some special characters
??= #
??( [
??) ]
??< {
??> }
??!
|
??/ \
??' ^
??-
~
Q How are floating point numbers stored? Whats the IEEE
format?
IEEE Standard 754 floating point is the most
common representation today for real numbers on computers, including Intel-based
PC's, Macintoshes, & most Unix platforms.
IEEE floating point
numbers have three basic components: the sign, the exponent, & the mantissa.
The mantissa is composed of the fraction & an implicit leading digit
(explained below). The exponent base(2) is implicit & need not be
stored.
The following figure shows the layout for single (32-bit) &
double (64-bit) precision floating-point values. The number of bits for each
field are shown (bit ranges are in square brackets):
Sign Exponent Fraction
Bias
--------------------------------------------------
Single Precision 1 [31] 8 [30-23] 23 [22-00] 127
Double Precision 1
[63] 11 [62-52] 52 [51-00] 1023
The sign bit is as simple as it gets. 0 denotes
a positive number; 1 denotes a negative number. Flipping the value of this bit
flips the sign of the number.
The exponent field needs to represent
both positive & negative exponents. To do this, a bias is added to the
actual exponent in order to get the stored exponent. For IEEE single-precision
floats, this value is 127. Thus, an exponent of zero means that 127 is stored in
the exponent field. A stored value of 200 indicates an exponent of (200-127), or
73. For reasons discussed later, exponents of -127 (all 0s) & +128 (all 1s)
are reserved for special numbers. For double precision, the exponent field is 11
bits, & has a bias of 1023.
The mantissa, also known as the
significand, represents the precision bits of the number. It is composed of an
implicit leading bit & the fraction bits. To find out the value of the
implicit leading bit, consider that any number can be expressed in scientific
notation in many different ways. For example, the number five can be represented
as any of these:
5.00 × 100
0.05 × 10 ^
2
5000 × 10 ^ -3
In order to maximize the quantity of
representable numbers, floating-point numbers are typically stored in normalized
form. This basically puts the radix point after the first non-zero digit. In
normalized form, five is represented as 5.0 × 100. A nice little optimization is
available to us in base two, since the only possible non-zero digit is 1. Thus,
we can just assume a leading digit of 1, & don't need to represent it
explicitly. As a result, the mantissa has effectively 24 bits of resolution, by
way of 23 fraction bits.
So, to sum up:
1. The sign bit is 0 for positive, 1 for
negative.
2. The exponent's base is two.
3. The exponent
field contains 127 plus the true exponent for single-precision, or 1023 plus
the true exponent for double precision.
4. The first bit of the
mantissa is typically assumed to be 1.f, where f is the field of fraction
bits.
Q. When should the register modifier be
used?
The register modifier hints to the compiler
that the variable will be heavily used & should be kept in the CPU?s
registers, if possible, so that it can be accessed faster. There are several
restrictions on the use of the register modifier.
First, the variable
must be of a type that can be held in the CPU?s register. This usually means a
single value of a size less than or equal to the size of an integer. Some
machines have registers that can hold floating-point numbers as well. Second,
because the variable might not be stored in memory, its address cannot be taken
with the unary & operator. An attempt to do so is flagged as an error by the
compiler. Some additional rules affect how useful the register modifier is.
Because the number of registers is limited, & because some registers can
hold only certain types of data (such as pointers or floating-point numbers),
the number & types of register modifiers that will actually have any effect
are dependent on what machine the program will run on. Any additional register
modifiers are silently ignored by the compiler. Also, in some cases, it might
actually be slower to keep a variable in a register because that register then
becomes unavailable for other purposes or because the variable isn?t used enough
to justify the overhead of loading & storing it. So when should the register
modifier be used? The answer is never, with most modern compilers. Early C
compilers did not keep any variables in registers unless directed to do so,
& the register modifier was a valuable addition to the language. C compiler
design has advanced to the point, however, where the compiler will usually make
better decisions than the programmer about which variables should be stored in
registers. In fact, many compilers actually ignore the register modifier, which
is perfectly legal, because it is only a hint & not a directive.
Q. 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 & from void * in order to
interface with functions that expect or return void pointers. For example, the
following line type casts the return value of the call to malloc() to be a
pointer to a foo structure.
struct foo *p = (struct foo *)
malloc(sizeof(struct foo));
A type cast should not be used to override a
const or volatile declaration. Overriding these type modifiers can cause the
program to fail to run correctly. A type cast should not be used to turn a
pointer to one type of structure or data type into another. In the
rare
events in which this action is beneficial, using a union to hold the values
makes the programmer?s intentions clearer.
Q. Can structures be assigned to
variables & passed to & from functions?
Yes, they can!
But note that when
structures are passed, returned or assigned, the copying is done only at one
level (The data pointed to by any pointer fields is not copied!.
Q What is the difference between the
declaration & the definition of a variable?.
The definition is the one that actually
allocates space, & provides an initialization value, if any.
There
can be many declarations, but there must be exactly one definition. A definition
tells the compiler to set aside storage for the variable. A declaration makes
the variable known to parts of the program that may wish to use it. A variable
might be defined & declared in the same statement.
Q Do Global variables start out as
zero?
Un initialized variables declared with the
"static" keyword are initialized to zero. Such variables are implicitly
initialized to the null pointer if they are pointers, & to 0.0F if they are
floating point numbers.
Local variables start out containing garbage,
unless they are explicitly initialized.
Memory obtained with malloc()
& realloc() is likely to contain junk, & must be initialized. Memory
obtained with calloc() is all-bits-0, but this is not necessarily useful for
pointer or floating-point values (This is in contrast to Global pointers &
Global floating point numbers, which start as zeroes of the right
type).
Q To what does the term storage class refer?
What are auto, static, extern, volatile, const classes?
This is a part of a variable declaration that
tells the compiler how to interpret the variable's symbol. It does not in itself
allocate storage, but it usually tells the compiler how the variable should be
stored. Storage class specifiers help you to specify the type of storage used
for data objects. Only one storage class specifier is permitted in a declaration
this makes sense, as there is only one way of storing things & if you omit
the storage class specifier in a declaration, a default is chosen. The default
depends on whether the declaration is made outside a function (external
declarations) or inside a function (internal declarations). For external
declarations the default storage class specifier will be extern & for
internal declarations it will be auto. The only exception to this rule is the
declaration of functions, whose default storage class specifier is always
extern.
Here are C's storage classes & what they
signify:
* auto - local variables.
* static -
variables are defined in a nonvolatile region of memory such that they retain
their contents though out the program's execution.
* register -
asks the compiler to devote a processor register to this variable in order to
speed the program's execution. The compiler may not comply & the variable
looses it contents & identity when the function it which it is defined
terminates.
* extern - tells the compiler that the variable is
defined in another module.
In C, const & volatile are type qualifiers.
The const & volatile type qualifiers are completely independent. A common
misconception is to imagine that somehow const is the opposite of volatile &
vice versa. This is wrong. The keywords const & volatile can be applied to
any declaration, including those of structures, unions, enumerated types or
typedef names. Applying them to a declaration is called qualifying the
declaration?that's why const & volatile are called type qualifiers, rather
than type specifiers.
* const means that something is not
modifiable, so a data object that is declared with const as a part of its type
specification must not be assigned to in any way during the run of a program.
The main intention of introducing const objects was to allow them to be put into
read-only store, & to permit compilers to do extra consistency checking in a
program. Unless you defeat the intent by doing naughty things with pointers, a
compiler is able to check that const objects are not modified explicitly by the
user. It is very likely that the definition of the object will contain an
initializer (otherwise, since you can't assign to it, how would it ever get a
value?), but this is not always the case. For example, if you were accessing a
hardware port at a fixed memory address & promised only to read from it,
then it would be declared to be const but not initialized.
*
volatile tells the compiler that other programs will be modifying this variable
in addition to the program being compiled. For example, an I/O device might need
write directly into a program or data space. Meanwhile, the program itself may
never directly access the memory area in question. In such a case, we would not
want the compiler to optimize-out this data area that never seems to be used by
the program, yet must exist for the program to function correctly in a larger
context. It tells the compiler that the object is subject to sudden change for
reasons which cannot be predicted from a study of the program itself, &
forces every reference to such an object to be a genuine reference.
* const volatile - Both constant & volatile.
The "volatile" modifier
The volatile
modifier is a directive to the compiler?s optimizer that operations involving
this variable should not be optimized in certain ways. There are two special
cases in which use of the volatile modifier is desirable. The first case
involves memory-mapped hardware (a device such as a graphics adaptor that
appears to the computer?s hardware as if it were part of the computer?s memory),
& the second involves shared memory (memory used by two or more programs
running simultaneously). Most computers have a set of registers that can be
accessed faster than the computer?s main memory. A good compiler will perform a
kind of optimization called ?redundant load & store removal.? The compiler
looks for places in the code where it can either remove an instruction to load
data from memory because the value is already in a register, or remove an
instruction to store data to memory because the value can stay in a register
until it is changed again anyway.
If a variable is a pointer to
something other than normal memory, such as memory-mapped ports on a
peripheral, redundant load & store optimizations might be detrimental. For
instance, here?s a piece of code that might be used to time some
operation:
time_t time_addition(volatile const struct
timer *t, int a)
{
int n;
int x;
time_t then;
x = 0;
then = t->value;
for
(n = 0; n < 1000; n++)
{
x = x + a;
}
return t->value - then;
}
In this code, the variable t->value is
actually a hardware counter that is being incremented as time passes. The
function adds the value of a to x 1000 times, & it returns the amount the
timer was incremented by while the 1000 additions were being performed. Without
the volatile modifier, a clever optimizer might assume that the value of t does
not change during the execution of the function, because there is no statement
that explicitly changes it. In that case, there?s no need to read it from memory
a second time & subtract it, because the answer will always be 0. The
compiler might therefore ?optimize? the function by making it always return 0.
If a variable points to data in shared memory, you also don?t want the compiler
to perform redundant load & store optimizations. Shared memory is normally
used to enable two programs to communicate with each other by having one program
store data in the shared portion of memory & the other program read the same
portion of memory. If the compiler optimizes away a load or store of shared
memory, communication between the two programs will be
affected.
Answer the questions based on the following program:
STRUCT DOUBLELIST
{ DOUBLE CLINKED
INT DET; LIST VOID
STRUCT PREVIOUS; (BE GIVEN AND A PROCEDURE TO
DELETE)
STRUCT NEW; (AN ELEMENT WILL BE
GIVEN)
}
DELETE(STRUCT NODE)
{NODE-PREV-NEXT NODE-NEXT;
NODE-NEXT-PREV NODE-PREV;
IF(NODE==HEAD)
NODE
}
Q. In what case the prev was
(a) All cases
(b) It does not work for the last element
(c) It does not for the first element
(d) None of these
Answer the questions based on the following program
VOID FUNCTION(INT KK)
{KK+=20;
}
VOID FUNCTION (INT K)
INT MM,N=&M
KN = K
KN+-=10;
}
Q. What is the output of the following program
main()
{ int var=25,varp;
varp=&var;
varp p = 10;
fnc(varp)
printf("%d%d,var,varp);
}
(a) 20,55
(b) 35,35
(c) 25,25
(d)55,55
1. a=2, b=3, c=6
Find the value of c/(a+b)-(a+b)/c
2. What does the hexanumber E78 in radix 7.
(a) 12455
(b) 14153
(c) 14256
(d) 13541
(e) 131112
Ans. (d)
3. 10 : 4 seconds :: ? : 6 minutes
Ans. 900
4. Q is not
equal to zero and k = (Q x n - s)/2.What is n?
(a) (2 x k + s)/Q
(b) (2 x s x k)/Q
(c) (2 x k - s)/Q
(d) (2 x k + s x Q)/Q
(e) (k + s)/Q
5. From the following statements determing the order of ranking
M has double the amount as D
Y has 3 rupess more than half the amount of D
Ans. Data insuffiecient
Questions 6 - 10 are to be answered on the following data
A causes B or C, but not both
F occurs only if B occurs
D occurs if B or C occurs
E occurs only if C occurs
J occurs only if E or F occurs
D causes G,H or both
H occurs if E occurs
G occurs if F occurs
6. If A occurs which of the following must occurs
I. F and G
II. E and H
III. D
(a) I only
(b) II only
(c) III only
(d) I,II, & III
(e) I & II (or) II & III but not both
Ans. (e)
7. If B occurs which must occur
(a) D
(b) D and G
(c) G and H
(d) F and G
(e) J
Ans. (a)
8.If J occurs which must have occured
(a) E
(b) either B or C
(c) both E & F
(d) B
(e) both B & C
Ans. (b)
9. Which may occurs as a result of cause not mentioned
I. D
II. A
III. F
(a) I only
(b) II only
(c) I & II
(d) II & III
(e) I,II & III
Ans. (c)
10. E occurs
which one cannot occurs
(a) A
(b) F
(c) D
(d) C
(e) J
Ans. (b)
STRUCT DOUBLELIST
{ DOUBLE CLINKED
INT DET; LIST VOID
STRUCT PREVIOUS; (BE GIVEN AND A PROCEDURE TO
DELETE)
STRUCT NEW; (AN ELEMENT WILL BE
GIVEN)
}
DELETE(STRUCT NODE)
{NODE-PREV-NEXT NODE-NEXT;
NODE-NEXT-PREV NODE-PREV;
IF(NODE==HEAD)
NODE
}
Q. In what case the prev was
(a) All cases
(b) It does not work for the last element
(c) It does not for the first element
(d) None of these
Answer the questions based on the following program
VOID FUNCTION(INT KK)
{KK+=20;
}
VOID FUNCTION (INT K)
INT MM,N=&M
KN = K
KN+-=10;
}
Q. What is the output of the following program
main()
{ int var=25,varp;
varp=&var;
varp p = 10;
fnc(varp)
printf("%d%d,var,varp);
}
(a) 20,55
(b) 35,35
(c) 25,25
(d)55,55
1. a=2, b=3, c=6
Find the value of c/(a+b)-(a+b)/c
2. What does the hexanumber E78 in radix 7.
(a) 12455
(b) 14153
(c) 14256
(d) 13541
(e) 131112
Ans. (d)
3. 10 : 4 seconds :: ? : 6 minutes
Ans. 900
4. Q is not
equal to zero and k = (Q x n - s)/2.What is n?
(a) (2 x k + s)/Q
(b) (2 x s x k)/Q
(c) (2 x k - s)/Q
(d) (2 x k + s x Q)/Q
(e) (k + s)/Q
5. From the following statements determing the order of ranking
M has double the amount as D
Y has 3 rupess more than half the amount of D
Ans. Data insuffiecient
Questions 6 - 10 are to be answered on the following data
A causes B or C, but not both
F occurs only if B occurs
D occurs if B or C occurs
E occurs only if C occurs
J occurs only if E or F occurs
D causes G,H or both
H occurs if E occurs
G occurs if F occurs
6. If A occurs which of the following must occurs
I. F and G
II. E and H
III. D
(a) I only
(b) II only
(c) III only
(d) I,II, & III
(e) I & II (or) II & III but not both
Ans. (e)
7. If B occurs which must occur
(a) D
(b) D and G
(c) G and H
(d) F and G
(e) J
Ans. (a)
8.If J occurs which must have occured
(a) E
(b) either B or C
(c) both E & F
(d) B
(e) both B & C
Ans. (b)
9. Which may occurs as a result of cause not mentioned
I. D
II. A
III. F
(a) I only
(b) II only
(c) I & II
(d) II & III
(e) I,II & III
Ans. (c)
10. E occurs
which one cannot occurs
(a) A
(b) F
(c) D
(d) C
(e) J
Ans. (b)
1 .In a selectionsort of n elements, how many times is the swap function called
in the complete execution of the algorithm?
A. 1
B. n - 1
C. n log
n
D. n^2
Solution: B.
n-1
2 .Selectionsort and quicksort both fall into the same category
of sorting algorithms. What is this category?
* A. O(n log n) sorts
*
B. Divide-and-conquer sorts
* C. Interchange sorts
* D. Average time is
quadratic.
Solution: C.Interchange
sorts reason:Selection sort is not O(n log n) and not a Divide-conquer sort too
and Average time of quicksort is not quadratic.
3 . Suppose that a selectionsort of 100 items has
completed 42 iterations of the main loop. How many items are now guaranteed to
be in their final spot (never to be moved again)?
* A. 21
* B. 41
*
C. 42
* D. 43
Solution: C. 42
4 .Suppose we are
sorting an array of ten integers using a some quadratic sorting algorithm. After
four iterations of the algorithm's main loop, the array elements are ordered as
shown here:
1 2 3 4 5 0 6 7 8 9
Which statement is correct? (Note:
Our selection sort picks largest items first.)
* A. The algorithm might
be either selection sort or insertion sort.
* B. The algorithm might be
selectionsort, but could not be insertionsort.
* C. The algorithm might be
insertionsort, but could not be selectionsort.
* D. The algorithm is neither
selectionsort nor insertionsort.
Solution: C. The algorithm might be insertion
sort, but could not be selection sort.
5 .Suppose we are sorting an array
of eight integers using a some quadratic sorting algorithm. After four
iterations of the algorithm's main loop, the array elements are ordered as shown
here:
2 4 5 7 8 1 3 6
Which statement is correct? (Note: Our
selectionsort picks largest items first.)
* A. The algorithm might be
either selectionsort or insertionsort.
* B. The algorithm might be
selectionsort, but it is not insertionsort.
* C. The algorithm is not
selectionsort, but it might be insertionsort.
* D. The algorithm is neither
selectionsort nor insertionsort.
Solution: C. The algorithm is not
selectionsort, but it might be insertionsort.
6 .When is insertionsort a
good choice for sorting an array?
* A. Each component of the array
requires a large amount of memory.
* B. Each component of the array requires
a small amount of memory.
* C. The array has only a few items out of
place.
* D. The processor speed is fast.
Solution: C. The array has only a few items out
of place.
7 What is the worst-case time for mergesort to sort an array of
n elements?
* A. O(log n)
* B. O(n)
* C. O(n log n)
* D.
O(n^2)
Solution : C. O(n log
n)
8 What is the worst-case time for quicksort to sort an array of n
elements?
* A. O(log n)
* B. O(n)
* C. O(n log n)
* D.
O(n^2)
Solution: D.
O(n^2)
9 .Mergesort makes two recursive calls. Which statement is true
after these recursive calls finish, but before the merge step?
* A. The
array elements form a heap.
* B. Elements in each half of the array are
sorted amongst themselves.
* C. Elements in the first half of the array are
less than or equal to elements in the second half of the array.
* D. None of
the above.
Solution: B. Elements
in each half of the array are sorted amongst themselves.
10 .Suppose we
are sorting an array of eight integers using quicksort, and we have just
finished the first partitioning with the array looking like this:
2 5 1 7
9 12 11 10
Which statement is correct?
* A. The pivot could be
either the 7 or the 9.
* B. The pivot could be the 7, but it is not the
9.
* C. The pivot is not the 7, but it could be the 9.
* D. Neither the 7
nor the 9 is the pivot.
Solution:
A. The pivot could be either the 7 or the 9.
11 .What is the worst-case
time for heapsort to sort an array of n elements?
* A. O(log n)
* B.
O(n)
* C. O(n log n)
* D. O(n^2)
Solution: C. O(n log n)
12.Suppose you
are given a sorted list of N elements followed by f(N) randomly ordered
elements.How would you sort the entire list if
* A. f(N)=O(1)
* B.
f(N)=O(logN)
* C. f(N)=O(N^1/2)
* D. How large can f(N) be for the entire
list still to be sortable in O(N) time?
Solution:
A. f(N)=O(1) In this case
insertion sort would be the best ,giving the time complexity of O(N)
B.
f(N)=O(log N) Merge sort is the best option with a time complexity of
O(N)
C.f(N)=O(N^1/2) Merge sort is the best option with a time complexity
of O(N)
D.complexity = f(N)log f(N) + N +f(N)
Clearly f(N) is O(N) for
the complexity to be of O(N)
Now O(N) is an over estimate on the upper
bound of f(N) ,which is quite clear from the first term in the above
expression.
Now let f(N) is of the form k.N^(1/p ).Then with some
simplification we get
f(N)log(f(N)) is O(N ^(2/p)) and now to restrict
the whole expression to O(N)
we need to restrict p to p >= 2
But
f(N)is O(N^(1/p)) which means f(N) can at most be of size N^1/2
.
13.Prove that any algorithm that find an element X in a sorted list of
N elements requires Omega(log N) comparisons.
Solution:The search essentially becomes a
search for X in a binary decision tree and this requires Omega(log N)
comparisons.
14.Prove that sorting N elements with integer keys in the
range 1 < style="font-weight: bold;">Solution: Putting the elements
in to their corresponding buckets is of O(N).Then iteration of the buckets and
printing the corresponding keys as many times as their frequency is of
O(M+N).Hence the total complexity.
15.Suppose you have an array of N
elements,containing only 2 distinct keys, true and false.Give an O(N) algorithm
to sort the array.
Solution:Use
bucket sort with 2 buckets.
16.Prove that any comparison based algorithm
to sort 4 elements requires at least 3 comparisons and at the max
comparisons
Solution:The binary
decision tree has maximum distance of 3 and a maximum distance of 5 ,from the
root to the leaf.As each edge corresponds to a comparison,we need minimum of 3
and maximum of 5 comparisons to sort 4 elements.
17. In how many ways can
2 sorted arrays of combined size N be merged?
Solution:Still up for
debate.Any answers? :)
18.Show that binary insertion may reasonably be
expected to be an O(n log n) sort.
Solution:Binary insertion sort employs
binary search to find the right place to insert new elements, and therefore
performs ceil (log(n!)) comparisons in the worst case, which is Θ(n log n). The
algorithm as a whole still takes Θ(n2) time on average due to the series of
swaps required for each insertion, and since it always uses binary search, the
best case is no longer Ω(n) but Ω(n log n).
19.You are given two sets
of numbers Xi and Yj , where i and j run from 1 to N.
Devise an algorithm to
find the M largest values of Xi −Yj . This algorithm should
not be quadratic
in N, though it is permitted to be quadratic in M.
You should regard N as
being of the order of 20,000 and M as being of the order
of 1,000.
Solution:Use an order-statistic algorithm to
find the Mth largest number in X,partition around that number and sort the M
largest numbers.Repeat this for Y but sorting the M smallest numbers.This can be
done in O(N+M log(M))Now with each of these sub-arrays having M elements,find
the difference between each element of X and Y.We have M difference elements for
each Xi in sorted order and in total M^2 differences.Use merge sort repeatedly
to merge these portions .This is of complexity M^2.Hence the
procedure.
20.If 1024 numbers are drawn randomly in the range 0–127 and
sorted by binary
insertion, about how many compares would you
expect?
Solution:We have 3 comparisons
coming in to the picture ab, a=b.The overall number of comparisons won't change
and it is still of the O(N log N). strictly speaking log(N!)
comparisons.
in the complete execution of the algorithm?
A. 1
B. n - 1
C. n log
n
D. n^2
Solution: B.
n-1
2 .Selectionsort and quicksort both fall into the same category
of sorting algorithms. What is this category?
* A. O(n log n) sorts
*
B. Divide-and-conquer sorts
* C. Interchange sorts
* D. Average time is
quadratic.
Solution: C.Interchange
sorts reason:Selection sort is not O(n log n) and not a Divide-conquer sort too
and Average time of quicksort is not quadratic.
3 . Suppose that a selectionsort of 100 items has
completed 42 iterations of the main loop. How many items are now guaranteed to
be in their final spot (never to be moved again)?
* A. 21
* B. 41
*
C. 42
* D. 43
Solution: C. 42
4 .Suppose we are
sorting an array of ten integers using a some quadratic sorting algorithm. After
four iterations of the algorithm's main loop, the array elements are ordered as
shown here:
1 2 3 4 5 0 6 7 8 9
Which statement is correct? (Note:
Our selection sort picks largest items first.)
* A. The algorithm might
be either selection sort or insertion sort.
* B. The algorithm might be
selectionsort, but could not be insertionsort.
* C. The algorithm might be
insertionsort, but could not be selectionsort.
* D. The algorithm is neither
selectionsort nor insertionsort.
Solution: C. The algorithm might be insertion
sort, but could not be selection sort.
5 .Suppose we are sorting an array
of eight integers using a some quadratic sorting algorithm. After four
iterations of the algorithm's main loop, the array elements are ordered as shown
here:
2 4 5 7 8 1 3 6
Which statement is correct? (Note: Our
selectionsort picks largest items first.)
* A. The algorithm might be
either selectionsort or insertionsort.
* B. The algorithm might be
selectionsort, but it is not insertionsort.
* C. The algorithm is not
selectionsort, but it might be insertionsort.
* D. The algorithm is neither
selectionsort nor insertionsort.
Solution: C. The algorithm is not
selectionsort, but it might be insertionsort.
6 .When is insertionsort a
good choice for sorting an array?
* A. Each component of the array
requires a large amount of memory.
* B. Each component of the array requires
a small amount of memory.
* C. The array has only a few items out of
place.
* D. The processor speed is fast.
Solution: C. The array has only a few items out
of place.
7 What is the worst-case time for mergesort to sort an array of
n elements?
* A. O(log n)
* B. O(n)
* C. O(n log n)
* D.
O(n^2)
Solution : C. O(n log
n)
8 What is the worst-case time for quicksort to sort an array of n
elements?
* A. O(log n)
* B. O(n)
* C. O(n log n)
* D.
O(n^2)
Solution: D.
O(n^2)
9 .Mergesort makes two recursive calls. Which statement is true
after these recursive calls finish, but before the merge step?
* A. The
array elements form a heap.
* B. Elements in each half of the array are
sorted amongst themselves.
* C. Elements in the first half of the array are
less than or equal to elements in the second half of the array.
* D. None of
the above.
Solution: B. Elements
in each half of the array are sorted amongst themselves.
10 .Suppose we
are sorting an array of eight integers using quicksort, and we have just
finished the first partitioning with the array looking like this:
2 5 1 7
9 12 11 10
Which statement is correct?
* A. The pivot could be
either the 7 or the 9.
* B. The pivot could be the 7, but it is not the
9.
* C. The pivot is not the 7, but it could be the 9.
* D. Neither the 7
nor the 9 is the pivot.
Solution:
A. The pivot could be either the 7 or the 9.
11 .What is the worst-case
time for heapsort to sort an array of n elements?
* A. O(log n)
* B.
O(n)
* C. O(n log n)
* D. O(n^2)
Solution: C. O(n log n)
12.Suppose you
are given a sorted list of N elements followed by f(N) randomly ordered
elements.How would you sort the entire list if
* A. f(N)=O(1)
* B.
f(N)=O(logN)
* C. f(N)=O(N^1/2)
* D. How large can f(N) be for the entire
list still to be sortable in O(N) time?
Solution:
A. f(N)=O(1) In this case
insertion sort would be the best ,giving the time complexity of O(N)
B.
f(N)=O(log N) Merge sort is the best option with a time complexity of
O(N)
C.f(N)=O(N^1/2) Merge sort is the best option with a time complexity
of O(N)
D.complexity = f(N)log f(N) + N +f(N)
Clearly f(N) is O(N) for
the complexity to be of O(N)
Now O(N) is an over estimate on the upper
bound of f(N) ,which is quite clear from the first term in the above
expression.
Now let f(N) is of the form k.N^(1/p ).Then with some
simplification we get
f(N)log(f(N)) is O(N ^(2/p)) and now to restrict
the whole expression to O(N)
we need to restrict p to p >= 2
But
f(N)is O(N^(1/p)) which means f(N) can at most be of size N^1/2
.
13.Prove that any algorithm that find an element X in a sorted list of
N elements requires Omega(log N) comparisons.
Solution:The search essentially becomes a
search for X in a binary decision tree and this requires Omega(log N)
comparisons.
14.Prove that sorting N elements with integer keys in the
range 1 < style="font-weight: bold;">Solution: Putting the elements
in to their corresponding buckets is of O(N).Then iteration of the buckets and
printing the corresponding keys as many times as their frequency is of
O(M+N).Hence the total complexity.
15.Suppose you have an array of N
elements,containing only 2 distinct keys, true and false.Give an O(N) algorithm
to sort the array.
Solution:Use
bucket sort with 2 buckets.
16.Prove that any comparison based algorithm
to sort 4 elements requires at least 3 comparisons and at the max
comparisons
Solution:The binary
decision tree has maximum distance of 3 and a maximum distance of 5 ,from the
root to the leaf.As each edge corresponds to a comparison,we need minimum of 3
and maximum of 5 comparisons to sort 4 elements.
17. In how many ways can
2 sorted arrays of combined size N be merged?
Solution:Still up for
debate.Any answers? :)
18.Show that binary insertion may reasonably be
expected to be an O(n log n) sort.
Solution:Binary insertion sort employs
binary search to find the right place to insert new elements, and therefore
performs ceil (log(n!)) comparisons in the worst case, which is Θ(n log n). The
algorithm as a whole still takes Θ(n2) time on average due to the series of
swaps required for each insertion, and since it always uses binary search, the
best case is no longer Ω(n) but Ω(n log n).
19.You are given two sets
of numbers Xi and Yj , where i and j run from 1 to N.
Devise an algorithm to
find the M largest values of Xi −Yj . This algorithm should
not be quadratic
in N, though it is permitted to be quadratic in M.
You should regard N as
being of the order of 20,000 and M as being of the order
of 1,000.
Solution:Use an order-statistic algorithm to
find the Mth largest number in X,partition around that number and sort the M
largest numbers.Repeat this for Y but sorting the M smallest numbers.This can be
done in O(N+M log(M))Now with each of these sub-arrays having M elements,find
the difference between each element of X and Y.We have M difference elements for
each Xi in sorted order and in total M^2 differences.Use merge sort repeatedly
to merge these portions .This is of complexity M^2.Hence the
procedure.
20.If 1024 numbers are drawn randomly in the range 0–127 and
sorted by binary
insertion, about how many compares would you
expect?
Solution:We have 3 comparisons
coming in to the picture ab, a=b.The overall number of comparisons won't change
and it is still of the O(N log N). strictly speaking log(N!)
comparisons.
Declarations & Initializations:
Q How do you decide that integer type to use?
A: If you might need large values (above 32,767 or below -32,767), use long.
Otherwise, if space is very important (i.e. if there are large arrays or many
structures), use short. Otherwise, use int. If well-defined overflow
characteristics are important & negative values are not, or if you want to
steer clear of sign- extension problems when manipulating bits or bytes, use one
of the corresponding unsigned types. (Beware when mixing signed & unsigned
values in expressions, though.) Although character types (especially unsigned
char) can be used as "tiny" integers, doing so is sometimes more trouble than
it's worth, due to unpredictable sign extension & increased code
size.
A similar space/time tradeoff applies when deciding between float &
double. None of the above rules apply if the address of a variable is taken
& must have a particular type. If for some reason you need to declare
something with an *exact* size (usually the only good reason for doing so is
when attempting to conform to some externally-imposed storage layout, but see
question 20.5), be sure to encapsulate the choice behind an appropriate
typedef.
Q What should the 64-bit type on a machine that can support
it?
A: The forthcoming revision to the C Standard (C9X) specifies type long long
as effectively being at least 64 bits, & this type has been implemented by a
number of compilers for some time. (Others have implemented extensions such as
__longlong.) On the other hand, there's no theoretical reason why a compiler
couldn't implement type short int as 16, int as 32, & long int as 64 bits,
& some compilers do indeed choose this arrangement.
Q What is the best way to declare & define global variables &
functions?
A: First, though there can be many "declarations" (& in many translation
units) of a single "global" (strictly speaking, "external") variable or
function, there must be exactly one "definition". (The definition is the
declaration that actually allocates space, & provides an initialization
value, if any.) The best arrangement is to place each definition in some
relevant .c file, with an external declaration in a header (".h") file, that is
#included wherever the declaration is needed. The .c file containing the
definition should also #include the same header file, so that the compiler can
check that the definition matches the declarations. This rule promotes a high
degree of portability: it is consistent with the requirements of the ANSI C
Standard, & is also consistent with most pre-ANSI compilers & linkers.
(Unix compilers & linkers typically use a "common model" that allows
multiple definitions, as long as at most one is initialized; this behavior is
mentioned as a "common extension" by the ANSI Standard, no pun intended. A few
very odd systems may require an explicit initializer to distinguish a definition
from an external declaration.) It is possible to use preprocessor tricks to
arrange that a line like DEFINE(int, i); need only be entered once in one header
file, & turned into a definition or a declaration depending on the setting
of some macro, but it's not clear if this is worth the trouble. It's especially
important to put global declarations in header files if you want the compiler to
catch inconsistent declarations for you. In particular, never place a prototype
for an external function in a .c file: it wouldn't generally be checked for
consistency with the definition, & an incompatible prototype is worse than
useless.
Q What does extern mean in a function declaration?
A: It can be used as a stylistic hint to indicate that the function's
definition is probably in another source file, but there is no formal difference
between extern int f(); & int f();
Q What is the auto keyword good for?
A: Nothing; it's archaic.
Q Define a linked list & tried typedef struct { char *item;
NODEPTR next; } *NODEPTR; but the compiler give to error messages. Can't a
structure in C contain a pointer to itself?
A: Structures in C can certainly contain pointers to themselves; the
discussion & example in section 6.5 of K&R make this clear. The problem
with the NODEPTR example is that the typedef has not been defined at the point
where the "next" field is declared. To fix this code, first give the structure a
tag ("struct node"). Then, declare the "next" field as a simple "struct node *",
or disentangle the typedef declaration from the structure definition, or both.
One corrected version would be struct node { char *item; struct node *next; };
typedef struct node *NODEPTR; & there are at least three other equivalently
correct ways of arranging it. A similar problem, with a similar solution, can
arise when attempting to declare a pair of typedef'ed mutually referential
structures.
Q How do you declare an array of N pointers to functions returning
pointers to functions returning pointers to characters?
A: The first part of this question can be answered in at least three
ways:
1. char *(*(*a[N])())(); 2. Build the declaration up incrementally, using
typedefs: typedef char *pc; /* pointer to char */ typedef pc fpc(); /* function
returning pointer to char */ typedef fpc *pfpc; /* pointer to above */ typedef
pfpc fpfpc(); /* function returning... */ typedef fpfpc *pfpfpc; /* pointer
to... */ pfpfpc a[N]; /* array of... */ 3. Use the cdecl program, that turns
English into C & vice versa: cdecl> declare a as array of pointer to
function returning pointer to function returning pointer to char char
*(*(*a[])())() cdecl can also explain complicated declarations, help with casts,
& indicate that set of parentheses the arguments go in (for complicated
function definitions, like the one above). Any good book on C should explain how
to read these complicated C declarations "inside out" to understand them
("declaration mimics use"). The pointer-to-function declarations in the examples
above have not included parameter type information. When the parameters have
complicated types, declarations can *really* get messy.
Q How you declare a function that can return a pointer to a function
of the same type? you will building a state machine with one function for each
state, each of that returns a pointer to the function for the next state. But
you can't find a way to declare the functions.
A: We can't quite do it directly. Either have the function return a generic
function pointer, with some judicious casts to adjust the types as the pointers
are passed around; or have it return a structure containing only a pointer to a
function returning that structure.
Q Some compiler is complaining about an invalid redeclaration of a
function, but you only define it once & call it once.
A: Functions that are called without a declaration in scope (perhaps because
the first call precedes the function's definition) are assumed to be declared as
returning int (& without any argument type information), leading to
discrepancies if the function is later declared or defined Or. Non-int functions
must be declared before they are called. Another possible source of this problem
is that the function has the same name as another one declared in some header
file.
Q. What is the right declaration for main()? Is void main()
correct?
A: But no, it's not correct
Q. What are you allowed to assume about the initial values of
variables that are not explicitly initialized? If global variables start out as
"zero", is that good enough for null pointers & floating-point
zeroes?
A: Uninitialized variables with "static" duration (that is, those declared
outside of functions, & those declared with the storage class static), are
guaranteed to start out as zero, as if the programmer had typed "= 0".
Therefore, such variables are implicitly initialized to the null pointer (of the
correct type; see also section 5) if they are pointers, & to 0.0 if they are
floating-point. Variables with "automatic" duration (i.e. local variables
without the static storage class) start out containing garbage, unless they are
explicitly initialized. (Nothing useful can be predicted about the garbage.)
Dynamically-allocated memory obtained with malloc() & realloc() is also
likely to contain garbage, & must be initialized by the calling program, as
appropriate. Memory obtained with calloc() is all-bits-0, but this is not
necessarily useful for pointer or floating-point values
Q How do you decide that integer type to use?
A: If you might need large values (above 32,767 or below -32,767), use long.
Otherwise, if space is very important (i.e. if there are large arrays or many
structures), use short. Otherwise, use int. If well-defined overflow
characteristics are important & negative values are not, or if you want to
steer clear of sign- extension problems when manipulating bits or bytes, use one
of the corresponding unsigned types. (Beware when mixing signed & unsigned
values in expressions, though.) Although character types (especially unsigned
char) can be used as "tiny" integers, doing so is sometimes more trouble than
it's worth, due to unpredictable sign extension & increased code
size.
A similar space/time tradeoff applies when deciding between float &
double. None of the above rules apply if the address of a variable is taken
& must have a particular type. If for some reason you need to declare
something with an *exact* size (usually the only good reason for doing so is
when attempting to conform to some externally-imposed storage layout, but see
question 20.5), be sure to encapsulate the choice behind an appropriate
typedef.
Q What should the 64-bit type on a machine that can support
it?
A: The forthcoming revision to the C Standard (C9X) specifies type long long
as effectively being at least 64 bits, & this type has been implemented by a
number of compilers for some time. (Others have implemented extensions such as
__longlong.) On the other hand, there's no theoretical reason why a compiler
couldn't implement type short int as 16, int as 32, & long int as 64 bits,
& some compilers do indeed choose this arrangement.
Q What is the best way to declare & define global variables &
functions?
A: First, though there can be many "declarations" (& in many translation
units) of a single "global" (strictly speaking, "external") variable or
function, there must be exactly one "definition". (The definition is the
declaration that actually allocates space, & provides an initialization
value, if any.) The best arrangement is to place each definition in some
relevant .c file, with an external declaration in a header (".h") file, that is
#included wherever the declaration is needed. The .c file containing the
definition should also #include the same header file, so that the compiler can
check that the definition matches the declarations. This rule promotes a high
degree of portability: it is consistent with the requirements of the ANSI C
Standard, & is also consistent with most pre-ANSI compilers & linkers.
(Unix compilers & linkers typically use a "common model" that allows
multiple definitions, as long as at most one is initialized; this behavior is
mentioned as a "common extension" by the ANSI Standard, no pun intended. A few
very odd systems may require an explicit initializer to distinguish a definition
from an external declaration.) It is possible to use preprocessor tricks to
arrange that a line like DEFINE(int, i); need only be entered once in one header
file, & turned into a definition or a declaration depending on the setting
of some macro, but it's not clear if this is worth the trouble. It's especially
important to put global declarations in header files if you want the compiler to
catch inconsistent declarations for you. In particular, never place a prototype
for an external function in a .c file: it wouldn't generally be checked for
consistency with the definition, & an incompatible prototype is worse than
useless.
Q What does extern mean in a function declaration?
A: It can be used as a stylistic hint to indicate that the function's
definition is probably in another source file, but there is no formal difference
between extern int f(); & int f();
Q What is the auto keyword good for?
A: Nothing; it's archaic.
Q Define a linked list & tried typedef struct { char *item;
NODEPTR next; } *NODEPTR; but the compiler give to error messages. Can't a
structure in C contain a pointer to itself?
A: Structures in C can certainly contain pointers to themselves; the
discussion & example in section 6.5 of K&R make this clear. The problem
with the NODEPTR example is that the typedef has not been defined at the point
where the "next" field is declared. To fix this code, first give the structure a
tag ("struct node"). Then, declare the "next" field as a simple "struct node *",
or disentangle the typedef declaration from the structure definition, or both.
One corrected version would be struct node { char *item; struct node *next; };
typedef struct node *NODEPTR; & there are at least three other equivalently
correct ways of arranging it. A similar problem, with a similar solution, can
arise when attempting to declare a pair of typedef'ed mutually referential
structures.
Q How do you declare an array of N pointers to functions returning
pointers to functions returning pointers to characters?
A: The first part of this question can be answered in at least three
ways:
1. char *(*(*a[N])())(); 2. Build the declaration up incrementally, using
typedefs: typedef char *pc; /* pointer to char */ typedef pc fpc(); /* function
returning pointer to char */ typedef fpc *pfpc; /* pointer to above */ typedef
pfpc fpfpc(); /* function returning... */ typedef fpfpc *pfpfpc; /* pointer
to... */ pfpfpc a[N]; /* array of... */ 3. Use the cdecl program, that turns
English into C & vice versa: cdecl> declare a as array of pointer to
function returning pointer to function returning pointer to char char
*(*(*a[])())() cdecl can also explain complicated declarations, help with casts,
& indicate that set of parentheses the arguments go in (for complicated
function definitions, like the one above). Any good book on C should explain how
to read these complicated C declarations "inside out" to understand them
("declaration mimics use"). The pointer-to-function declarations in the examples
above have not included parameter type information. When the parameters have
complicated types, declarations can *really* get messy.
Q How you declare a function that can return a pointer to a function
of the same type? you will building a state machine with one function for each
state, each of that returns a pointer to the function for the next state. But
you can't find a way to declare the functions.
A: We can't quite do it directly. Either have the function return a generic
function pointer, with some judicious casts to adjust the types as the pointers
are passed around; or have it return a structure containing only a pointer to a
function returning that structure.
Q Some compiler is complaining about an invalid redeclaration of a
function, but you only define it once & call it once.
A: Functions that are called without a declaration in scope (perhaps because
the first call precedes the function's definition) are assumed to be declared as
returning int (& without any argument type information), leading to
discrepancies if the function is later declared or defined Or. Non-int functions
must be declared before they are called. Another possible source of this problem
is that the function has the same name as another one declared in some header
file.
Q. What is the right declaration for main()? Is void main()
correct?
A: But no, it's not correct
Q. What are you allowed to assume about the initial values of
variables that are not explicitly initialized? If global variables start out as
"zero", is that good enough for null pointers & floating-point
zeroes?
A: Uninitialized variables with "static" duration (that is, those declared
outside of functions, & those declared with the storage class static), are
guaranteed to start out as zero, as if the programmer had typed "= 0".
Therefore, such variables are implicitly initialized to the null pointer (of the
correct type; see also section 5) if they are pointers, & to 0.0 if they are
floating-point. Variables with "automatic" duration (i.e. local variables
without the static storage class) start out containing garbage, unless they are
explicitly initialized. (Nothing useful can be predicted about the garbage.)
Dynamically-allocated memory obtained with malloc() & realloc() is also
likely to contain garbage, & must be initialized by the calling program, as
appropriate. Memory obtained with calloc() is all-bits-0, but this is not
necessarily useful for pointer or floating-point values
Q What is an
attribute?
It is a particular property, which describes the entity.
Q
What is a Relation Schema & a Relation?
A relation Schema denoted by
R(A1, A2, …, An) is made up of the relation name
R & the list of
attributes Ai that it contains. A relation is defined as a set of tuples. Let
r
be the relation which contains set tuples (t1, t2, t3, ..., tn). Each tuple
is an ordered list of n-values t=(v1,v2, ..., vn).
It is the number of
attribute of its relation schema.
Q What is an Extension
of entity type?
The collections of entities of a particular entity type are
grouped together into an
entity set.
Q What is Weak Entity set?
An
entity set may not have sufficient attributes to form a primary key, &
its
primary key compromises of its partial key & primary key of its
parent entity, then it is
said to be Weak Entityset
Q What is
Relationship?
It is an association among two or more entities.
Q What
is Relationship set?
The collection (or set) of similar
relationships.
Q What is Relationship type?
Relationship type defines
a set of associations or a relationship set among a given
set of entity
types.
QWhat is an Entity?
It
is a 'thing' in the real world with an independent existence.
Q What is
an Entity type?
It is a collection (set) of entities that have same
attributes.
Q What is an Entity set?
It is a collection of all
entities of particular entity type in the database.
attribute?
It is a particular property, which describes the entity.
Q
What is a Relation Schema & a Relation?
A relation Schema denoted by
R(A1, A2, …, An) is made up of the relation name
R & the list of
attributes Ai that it contains. A relation is defined as a set of tuples. Let
r
be the relation which contains set tuples (t1, t2, t3, ..., tn). Each tuple
is an ordered list of n-values t=(v1,v2, ..., vn).
It is the number of
attribute of its relation schema.
Q What is an Extension
of entity type?
The collections of entities of a particular entity type are
grouped together into an
entity set.
Q What is Weak Entity set?
An
entity set may not have sufficient attributes to form a primary key, &
its
primary key compromises of its partial key & primary key of its
parent entity, then it is
said to be Weak Entityset
Q What is
Relationship?
It is an association among two or more entities.
Q What
is Relationship set?
The collection (or set) of similar
relationships.
Q What is Relationship type?
Relationship type defines
a set of associations or a relationship set among a given
set of entity
types.
QWhat is an Entity?
It
is a 'thing' in the real world with an independent existence.
Q What is
an Entity type?
It is a collection (set) of entities that have same
attributes.
Q What is an Entity set?
It is a collection of all
entities of particular entity type in the database.
Q. What is the use of the DROP option in the
ALTER TABLE comm&?
It is used to drop constraints specified on the table.
Q. What is the value of ‘comm’ & ‘sal’
after executing the following query if the initial
value of ‘sal’ is 10000?
UPDATE EMP SET SAL = SAL + 1000, COMM = SAL*0.1;
sal = 11000, comm = 1000 .
Q. Why does the following comm& give a
compilation error?
DROP TABLE &TABLE_NAME;
Variable names should start with an alphabet. Here the table name starts with
an '&' symbol.
Q. What is the advantage of specifying WITH
GRANT OPTION in the GRANT comm& in sql?
The privilege receiver can further grant the privileges he/she has obtained
from the owner to any other user.
Q. What is the use of DESC in SQL?
Answer :
DESC has two purposes. It is used to describe a schema as well as to retrieve
rows from table in descending order.
Explanation :
The query SELECT * FROM EMP ORDER BY ENAME DESC will display the output
sorted on ENAME in descending order.
Q. What is the use of CASCADE CONSTRAINTS?
When this clause is used with the DROP comm&, a parent table can be
dropped even when a child table exists.
ALTER TABLE comm&?
It is used to drop constraints specified on the table.
Q. What is the value of ‘comm’ & ‘sal’
after executing the following query if the initial
value of ‘sal’ is 10000?
UPDATE EMP SET SAL = SAL + 1000, COMM = SAL*0.1;
sal = 11000, comm = 1000 .
Q. Why does the following comm& give a
compilation error?
DROP TABLE &TABLE_NAME;
Variable names should start with an alphabet. Here the table name starts with
an '&' symbol.
Q. What is the advantage of specifying WITH
GRANT OPTION in the GRANT comm& in sql?
The privilege receiver can further grant the privileges he/she has obtained
from the owner to any other user.
Q. What is the use of DESC in SQL?
Answer :
DESC has two purposes. It is used to describe a schema as well as to retrieve
rows from table in descending order.
Explanation :
The query SELECT * FROM EMP ORDER BY ENAME DESC will display the output
sorted on ENAME in descending order.
Q. What is the use of CASCADE CONSTRAINTS?
When this clause is used with the DROP comm&, a parent table can be
dropped even when a child table exists.
Subscribe to:
Posts (Atom)