Flipkart.com

II.4: What is a const pointer?

Answer:
The access modifier keyword const is a promise the programmer makes to the compiler that the value of avariable will not be changed after it is initialized. The compiler will enforce that promise as best it can by notenabling the programmer to write code which modifies a variable that has been declared const.
A “const pointer,” or more correctly, a “pointer to const,” is a pointer which points to data that is const(constant, or unchanging).
A pointer to const is declared by putting the word const at the beginning of thepointer declaration. This declares a pointer which points to data that can’t be modified. The pointer itselfcan be modified.
The following example illustrates some legal and illegal uses of a const pointer:

const char *str = “hello”;
char c = *str /* legal */str++;/* legal */
*str = ‘a’; /* illegal */
str[1] = ‘b’;/* illegal */

The first two statements here are legal because they do not modify the data that str points to. The next twostatements are illegal because they modify the data pointed to by str.Pointers to const are most often used in declaring function parameters. For instance, a function that countedthe number of characters in a string would not need to change the contents of the string, and it might bewritten this way:

my_strlen(const char *str){int count = 0;
while (*str++)
{
++;
}
return count;
}
Note that non-const pointers are implicitly converted to const pointers when needed, but const pointersare not converted to non-const pointers. This means that my_strlen() could be called with either a constor a non-const character pointer.
Reference:
II.7: Can a variable be both const and volatile?
II.8: When should the const modifier be used?
II.14: When should a type cast not be used?
II.18: What is the benefit of using const for declaring constants?

II.3: What is page thrashing?

Answer:
Some operating systems (such as UNIX or Windows in enhanced mode) use virtual memory. Virtual memory is a technique for making a machine behave as if it had more memory than it really has, by using disk space to simulate RAM (random-access memory). In the 80386 and higher Intel CPU chips, and in most other modern microprocessors (such as the Motorola 68030, Sparc, and Power PC), exists a piece of hardware called the Memory Management Unit, or MMU.
The MMU treats memory as if it were composed of a series of “pages.” A page of memory is a block of contiguous bytes of a certain size, usually 4096 or 8192 bytes. The operating system sets up and maintains a table for each running program called the Process Memory Map, or PMM. This is a table of all the pages of memory that program can access and where each is really located.
Every time your program accesses any portion of memory, the address (called a “virtual address”) is processed by the MMU. The MMU looks in the PMM to find out where the memory is really located (called the “physical address”). The physical address can be any location in memory or on disk that the operating system has assigned for it. If the location the program wants to access is on disk, the page containing it must be read from disk into memory, and the PMM must be updated to reflect this action (this is called a “page fault”).

Hope you’re still with me, because here’s the tricky part. Because accessing the disk is so much slower than accessing RAM, the operating system tries to keep as much of the virtual memory as possible in RAM. If you’re running a large enough program (or several small programs at once), there might not be enough RAM to hold all the memory used by the programs, so some of it must be moved out of RAM and onto disk (this action is called “paging out”).

The operating system tries to guess which areas of memory aren’t likely to be used for a while (usually based on how the memory has been used in the past). If it guesses wrong, or if your programs are accessing lots of memory in lots of places, many page faults will occur in order to read in the pages that were paged out. Because all of RAM is being used, for each page read in to be accessed, another page must be paged out. This can lead to more page faults, because now a different page of memory has been moved to disk. The problem of many
page faults occurring in a short time, called “page thrashing,” can drastically cut the performance of a system.

Programs that frequently access many widely separated locations in memory are more likely to cause page thrashing on a system. So is running many small programs that all continue to run even when you are not actively using them. To reduce page thrashing, you can run fewer programs simultaneously. Or you can try changing the way a large program works to maximize the capability of the operating system to guess which pages won’t be needed. You can achieve this effect by caching values or changing lookup algorithms in large data structures, or sometimes by changing to a memory allocation library which provides an implementation
of malloc() that allocates memory more efficiently. Finally, you might consider adding more RAM to the system to reduce the need to page out.
Reference:
VII.17: How do you declare an array that will hold more than 64KB of data?
VII.21: What is the heap?
XVIII.14: How can I get more than 640KB of memory available to my DOS program?
XXI.31: How is memory organized in Windows?

II.1: Where in memory are my variables stored?

Answer:
Variables can be stored in several places in memory, depending on their lifetime. Variables that are defined outside any function (whether of global or file static scope), and variables that are defined inside a function as static variables, exist for the lifetime of the program’s execution.

These variables are stored in the “data segment.” The data segment is a fixed-size area in memory set aside for these variables. The data segment is subdivided into two parts, one for initialized variables and another for uninitialized variables.
Variables that are defined inside a function as auto variables (that are not defined with the keyword static) come into existence when the program begins executing the block of code (delimited by curly braces {}) containing them, and they cease to exist when the program leaves that block of code. Variables that are the arguments to functions exist only during the call to that function.

These variables are stored on the “stack.”
The stack is an area of memory that starts out small and grows automatically up to some predefined limit.
In DOS and other systems without virtual memory, the limit is set either when the program is compiled or when it begins executing.

In UNIX and other systems with virtual memory, the limit is set by the system,
and it is usually so large that it can be ignored by the programmer. For a discussion on what virtual memory is, see II.3.

The third and final area doesn’t actually store variables but can be used to store data pointed to by variables. Pointer variables that are assigned to the result of a call to the malloc() function contain the address of a dynamically allocated area of memory. This memory is in an area called the “heap.” The heap is another area that starts out small and grows, but it grows only when the programmer explicitly calls malloc() or other memory allocation functions, such as calloc(). The heap can share a memory segment with either the data segment or the stack, or it can have its own segment. It all depends on the compiler options and operating system.

The heap, like the stack, has a limit on how much it can grow, and the same rules apply as to how
that limit is determined.
Reference:
I.1: What is a local block?
II.2: Do variables need to be initialized?
II.3: What is page thrashing?
VII.20: What is the stack?
VII.21: What is the heap?


II.2: Do variables need to be initialized?
Answer:
No. All variables should be given a value before they are used, and a good compiler will help you find variables that are used before they are set to a value. Variables need not be initialized, however.Variables defined outside a function or defined inside a function with the static keyword (those defined in the data segment discussed in the preceding FAQ) are already initialized to 0 for you if you do not explicitly initialize them.

Automatic variables are variables defined inside a function or block of code without the static keyword.
These variables have undefined values if you don’t explicitly initialize them. If you don’t initialize an automatic variable, you must make sure you assign to it before using the value.
Space on the heap allocated by calling malloc() contains undefined data as well and must be set to a known value before being used. Space allocated by calling calloc() is set to 0 for you when it is allocated.

Reference:
I.1: What is a local block?
VII.20: What is the stack?
VII.21: What is the heap?

I.13: What is the difference between ++var and var++?

Answer:
The ++ operator is called the increment operator. When the operator is placed before the variable (++var), the variable is incremented by 1 before it is used in the expression. When the operator is placed after the variable (var++), the expression is evaluated, and then the variable is incremented by 1. The same holds true for the decrement operator (--). When the operator is placed before the variable, you are said to have a prefix operation. When the operator is placed after the variable, you are said to have a postfix operation.

For instance, consider the following example of postfix incrementation:
int x, y;
x = 1;
y = (x++ * 5);

In this example, postfix incrementation is used, and x is not incremented until after the evaluation of the expression is done. Therefore, y evaluates to 1 times 5, or 5. After the evaluation, x is incremented to 2.

Now look at an example using prefix incrementation:
int x, y;
x = 1;
y = (++x * 5);

This example is the same as the first one, except that this example uses prefix incrementation rather than postfix. Therefore, x is incremented before the expression is evaluated, making it 2. Hence, y evaluates to 2 times 5, or 10.


I.14: What does the modulus operator do?
Answer:
The modulus operator (%) gives the remainder of two divided numbers. For instance, consider the following portion of code:
x = 15/7

If x were an integer, the resulting value of x would be 2. However, consider what would happen if you were to apply the modulus operator to the same equation:
x = 15%7

The result of this expression would be the remainder of 15 divided by 7, or 1. This is to say that 15 divided by 7 is 2 with a remainder of 1.
The modulus operator is commonly used to determine whether one number is evenly divisible into another.

For instance, if you wanted to print every third letter of the alphabet, you would use the following code:
int x;
for (x=1; x<=26; x++)
if ((x%3) == 0)
printf(“%c”, x+64);

The preceding example would output the string “cfilorux”, which represents every third letter in the alphabet.

I.11: What is an rvalue?

Answer:
In I.9, an lvalue was defined as an expression to which a value can be assigned. It was also explained that an lvalue appears on the left side of an assignment statement. Therefore, an rvalue can be defined as an expression that can be assigned to an lvalue. The rvalue appears on the right side of an assignment statement.
Unlike an lvalue, an rvalue can be a constant or an expression, as shown here:

int x, y;
x = 1; /* 1 is an rvalue; x is an lvalue */
y = (x + 1); /* (x + 1) is an rvalue; y is an lvalue */

As stated in I.9, an assignment statement must have both an lvalue and an rvalue. Therefore, the following statement would not compile because it is missing an rvalue:

int x;
x = void_function_call() /* the function void_function_call() returns nothing */
If the function had returned an integer, it would be considered an rvalue because it evaluates into something
that the lvalue, x, can store.
Reference:
I.9: What is an lvalue?
I.10: Can an array be an lvalue?


I.12: Is left-to-right or right-to-left order guaranteed for operator precedence?
Answer:
The simple answer to this question is neither. The C language does not always evaluate left-to-right or right to- left. Generally, function calls are evaluated first, followed by complex expressions and then simple expressions. Additionally, most of today’s popular C compilers often rearrange the order in which the expression is evaluated in order to get better optimized code. You therefore should always implicitly define
your operator precedence by using parentheses.
For example, consider the following expression:

a = b + c/d / function_call() * 5

The way this expression is to be evaluated is totally ambiguous, and you probably will not get the results you want. Instead, try writing it by using implicit operator precedence:
a = b + (((c/d) / function_call()) * 5)

Using this method, you can be assured that your expression will be evaluated properly and that the compiler will not rearrange operators for optimization purposes.

I.10: Can an array be an lvalue?

Answer:
In I.9, an lvalue was defined as an expression to which a value can be assigned. Is an array an expression to which we can assign a value? The answer to this question is no, because an array is composed of several separate array elements that cannot be treated as a whole for assignment purposes. The following statement is therefore illegal:

int x[5], y[5];
x = y;
You could, however, use a for loop to iterate through each element of the array and assign values individually, such as in this example:

int i;
int x[5];
int y[5];
...
for (i=0; i<5; your_name =" my_name;">Reference:
I.9: What is an lvalue?
I.11: What is an rvalue?

I.9: What is an lvalue?

Answer:
An lvalue is an expression to which a value can be assigned. The lvalue expression is located on the left side of an assignment statement, whereas an rvalue (see FAQ I.11) is located on the right side of an assignment statement. Each assignment statement must have an lvalue and an rvalue. The lvalue expression must reference a storable variable in memory. It cannot be a constant. For instance, the following lines show a few examples of lvalues:

int x;
int* p_int;
x = 1;
*p_int = 5;

The variable x is an integer, which is a storable location in memory.

Therefore, the statement x = 1 qualifies x to be an lvalue. Notice the second assignment statement, *p_int = 5. By using the * modifier to reference the area of memory that p_int points to, *p_int is qualified as an lvalue. In contrast, here are a few examples of what would not be considered lvalues:

#define CONST_VAL 10
int x;
/* example 1 */
1 = x;
/* example 2 */
CONST_VAL = 5;

In both statements, the left side of the statement evaluates to a constant value that cannot be changed because constants do not represent storable locations in memory. Therefore, these two assignment statements do notcontain lvalues and will be flagged by your compiler as errors

I.10: Can an array be an lvalue?
I.11: What is an rvalue?

I.8: What is the difference between goto and longjmp()

Answer:
A goto statement implements a local jump of program execution, and the longjmp() and setjmp() functions implement a nonlocal, or far, jump of program execution. Generally, a jump in execution of any kind should be avoided because it is not considered good programming practice to use such statements as goto and longjmp in your program.
A goto statement simply bypasses code in your program and jumps to a predefined position. To use the goto statement, you give it a labeled position to jump to. This predefined position must be within the same function. You cannot implement gotos between functions.
Here is an example of a goto statement:

void bad_programmers_function(void)
{
int x;
printf(“Excuse me while I count to 5000...\n”);
x = 1;
while (1)
{
printf(“%d\n”, x);
if (x == 5000)
goto all_done;
else
x = x + 1;
}
all_done:
printf(“Whew! That wasn’t so bad, was it?\n”);
}

This example could have been written much better, avoiding the use of a goto statement. Here is an example of an improved implementation:
void better_function(void)
{
int x;
printf(“Excuse me while I count to 5000...\n”);
for (x=1; x<=5000; x++)
printf(“%d\n”, x);
printf(“Whew! That wasn’t so bad, was it?\n”);
}
As previously mentioned, the longjmp() and setjmp() functions implement a nonlocal goto.
When your program calls setjmp(), the current state of your program is saved in a structure of type jmp_buf. Later, your program can call the longjmp() function to restore the program’s state as it was when you called setjmp().
Unlike the goto statement, the longjmp() and setjmp() functions do not need to be implemented in the same function. However, there is a major drawback to using these functions: your program, when restored to its previously saved state, will lose its references to any dynamically allocated memory between the longjmp() and the setjmp(). This means you will waste memory for every malloc() or calloc() you have implemented between your longjmp() and setjmp(), and your program will be horribly inefficient. It is highly recommended that you avoid using functions such as longjmp() and setjmp() because they, like the goto statement, are quite often an indication of poor programming practice.
Here is an example of the longjmp() and setjmp() functions:

#include
#include
jmp_buf saved_state;
void main(void);
void call_longjmp(void);
void main(void)
{
int ret_code;
printf(“The current state of the program is being saved...\n”);
ret_code = setjmp(saved_state);
if (ret_code == 1)
{
printf(“The longjmp function has been called.\n”);
printf(“The program’s previous state has been restored.\n”);
exit(0);
}
printf(“I am about to call longjmp and\n”);
printf(“return to the previous program state...\n”);
call_longjmp();
}
void call_longjmp(void)
{
longjmp(saved_state, 1);
}

I.7: How can you tell whether a loop ended prematurely?

Answer:
Generally, loops are dependent on one or more variables. Your program can check those variables outside the loop to ensure that the loop executed properly. For instance, consider the following example:


#define REQUESTED_BLOCKS 512
int x;
char* cp[REQUESTED_BLOCKS];
/* Attempt (in vain, I must add...) to
allocate 512 10KB blocks in memory. */
for (x=0; x< REQUESTED_BLOCKS; x++)
{
cp[x] = (char*) malloc(10000, 1);
if (cp[x] == (char*) NULL)
break;
}
/* If x is less than REQUESTED_BLOCKS, the loop has ended prematurely. */
if (x < REQUESTED_BLOCKS)
printf(“Bummer! My loop ended prematurely!\n”);


Notice that for the loop to execute successfully, it would have had to iterate through 512 times. Immediately following the loop, this condition is tested to see whether the loop ended prematurely. If the variable x isanything less than 512, some error has occurred