Set - 3

Question 1 :

What is the benefit of using #define to declare a constant ?

Answer :

Using the #define method of declaring a constant enables you to declare a constant in one place and use it throughout your program. This helps make your programs more maintainable, because you need to maintain only the #define statement and not several instances of individual constants throughout your program.

For instance, if your program used the value of pi (approximately 3.14159) several times, you might want to declare a constant for pi as follows:

#define PI 3.14159

Using the #define method of declaring a constant is probably the most familiar way of declaring constants to traditional C programmers. Besides being the most common method of declaring constants, it also takes up the least memory.

Constants defined in this manner are simply placed directly into your source code, with no variable space allocated in memory. Unfortunately, this is one reason why most debuggers cannot inspect constants created using the #define method.


Question 2 :

How can I search for data in a linked list ?

Answer :

Unfortunately, the only way to search a linked list is with a linear search, because the only way a linked list's members can be accessed is sequentially.
Sometimes it is quicker to take the data from a linked list and store it in a different data structure so that searches can be more efficient.


Question 3 :

Why should we assign NULL to the elements (pointer) after freeing them ?

Answer :

This is paranoia based on long experience. After a pointer has been freed, you can no longer use the pointed-to data. The pointer is said to dangle; it doesn't point at anything useful.

If you NULL out or zero out a pointer immediately after freeing it, your program can no longer get in trouble by using that pointer. True, you might go indirect on the null pointer instead, but that's something your debugger might be able to help you with immediately.

Also, there still might be copies of the pointer that refer to the memory that has been deallocated; that's the nature of C. Zeroing out pointers after freeing them won't solve all problems;


Question 4 :

What is a null pointer assignment error ? What are bus errors, memory faults, and core dumps ?

Answer :

These are all serious errors, symptoms of a wild pointer or subscript. 
Null pointer assignment is a message you might get when an MS-DOS program finishes executing. Some such programs can arrange for a small amount of memory to be available "where the NULL pointer points to (so to speak).

If the program tries to write to that area, it will overwrite the data put there by the compiler.

When the program is done, code generated by the compiler examines that area. If that data has been changed, the compiler-generated code complains with null pointer assignment.

This message carries only enough information to get you worried. There's no way to tell, just from a null pointer assignment message, what part of your program is responsible for the error. Some debuggers, and some compilers, can give you more help in finding the problem.

Bus error: core dumped and Memory fault: core dumped are messages you might see from a program running under UNIX. They're more programmer friendly. Both mean that a pointer or an array subscript was wildly out of bounds. You can get these messages on a read or on a write. They aren't restricted to null pointer problems.

The core dumped part of the message is telling you about a file, called core, that has just been written in your current directory. This is a dump of everything on the stack and in the heap at the time the program was running. With the help of a debugger, you can use the core dump to find where the bad pointer was used.

That might not tell you why the pointer was bad, but it's a step in the right direction. If you don't have write permission in the current directory, you won't get a core file, or the core dumped message


Question 5 :

When should a type cast be used ?

Answer :

There are two situations in which to use a type cast. The first use is to change the type of an operand to an arithmetic operation so that the operation will be performed properly.
The second case is to cast pointer types to and from void * in order to interface with functions that expect or return void pointers.
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));

 


Question 6 :

What is the difference between a string copy (strcpy) and a memory copy (memcpy)? When should each be used?

Answer :

The strcpy() function is designed to work exclusively with strings. It copies each byte of the source string to the destination string and stops when the terminating null character () has been moved.

On the other hand, the memcpy() function is designed to work with any type of data. Because not all data ends with a null character, you must provide the memcpy() function with the number of bytes you want to copy from the source to the destination.


Question 7 :

How can I convert a string to a number ?

Answer :

The standard C library provides several functions for converting strings to numbers of all formats (integers, longs, floats, and so on) and vice versa.

The following functions can be used to convert strings to numbers: 
Function Name Purpose

atof() Converts a string to a double-precision floating-point value. 
atoi() Converts a string to an integer. 
atol() Converts a string to a long integer. 
strtod() Converts a string to a double-precision floating-point value and reports any leftover numbers that could not be converted. 
strtol() Converts a string to a long integer and reports any leftover numbers that could not be converted. 
strtoul() Converts a string to an unsigned long integer and reports any leftover numbers that could not be converted.


Question 8 :

How can I convert a number to a string ?

Answer :

The standard C library provides several functions for converting numbers of all formats (integers, longs, floats, and so on) to strings and vice versa

The following functions can be used to convert integers to strings: 
Function Name Purpose

itoa() Converts an integer value to a string. 
ltoa() Converts a long integer value to a string. 
ultoa() Converts an unsigned long integer value to a string. 
The following functions can be used to convert floating-point values to strings:

Function Name Purpose 
ecvt() Converts a double-precision floating-point value to a string without an embedded decimal point. 
fcvt() Same as ecvt(), but forces the precision to a specified number of digits. 
gcvt() Converts a double-precision floating-point value to a string with an embedded decimal point.


Question 9 :

Is it possible to execute code even after the program exits the main() function?

Answer :

The standard C library provides a function named atexit() that can be used to perform cleanup operations when your program terminates.
You can set up a set of functions you want to perform automatically when your program exits by passing function pointers to the at exit() function.


Question 10 :

What is the stack ?

Answer :

The stack is where all the functions' local (auto) variables are created. The stack also contains some information used to call and return from functions.

A stack trace is a list of which functions have been called, based on this information. When you start using a debugger, one of the first things you should learn is how to get a stack trace.

The stack is very inflexible about allocating memory; everything must be deallocated in exactly the reverse order it was allocated in. For implementing function calls, that is all that's needed. Allocating memory off the stack is extremely efficient. One of the reasons C compilers generate such good code is their heavy use of a simple stack.

There used to be a C function that any programmer could use for allocating memory off the stack. The memory was automatically deallocated when the calling function returned. This was a dangerous function to call; it's not available anymore.


Question 11 :

How do you print an address ?

Answer :

The safest way is to use printf() (or fprintf() or sprintf()) with the %P specification. That prints a void pointer (void*). Different compilers might print a pointer with different formats.

Your compiler will pick a format that's right for your environment. 
If you have some other kind of pointer (not a void*) and you want to be very safe, cast the pointer to a void*:

printf( %Pn, (void*) buffer );

 


Question 12 :

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

Answer :

The preprocessor will include whatever file you specify in your #include statement. Therefore, if you have the line

#include

in your program, the file macros.inc will be included in your precompiled program. It is, however, unusual programming practice to put any file that does not have a .h or .hpp extension in an #include statement.

You should always put a .h extension on any of your C files you are going to include. This method makes it easier for you and others to identify which files are being used for preprocessing purposes.

For instance, someone modifying or debugging your program might not know to look at the macros.inc file for macro definitions. That person might try in vain by searching all files with .h extensions and come up empty.

If your file had been named macros.h, the search would have included the macros.h file, and the searcher would have been able to see what macros you defined in it.


Question 13 :

What is Preprocessor ?

Answer :

The preprocessor is used to modify your program according to the preprocessor directives in your source code.

Preprocessor directives (such as #define) give the preprocessor specific instructions on how to modify your source code. The preprocessor reads in all of your include files and the source code you are compiling and creates a preprocessed version of your source code.

This preprocessed version has all of its macros and constant symbols replaced by their corresponding code and value assignments. If your source code contains any conditional preprocessor directives (such as #if), the preprocessor evaluates the condition and modifies your source code accordingly.

The preprocessor contains many features that are powerful to use, such as creating macros, performing conditional compilation, inserting predefined environment variables into your code, and turning compiler features on and off.

For the professional programmer, in-depth knowledge of the features of the preprocessor can be one of the keys to creating fast, efficient programs.


Question 14 :

How can you restore a redirected standard stream ?

Answer :

The preceding example showed how you can redirect a standard stream from within your program. But what if later in your program you wanted to restore the standard stream to its original state?

By using the standard C library functions named dup() and fdopen(), you can restore a standard stream such as stdout to its original state.

The dup() function duplicates a file handle. You can use the dup() function to save the file handle corresponding to the stdout standard stream.

The fdopen() function opens a stream that has been duplicated with the dup() function.


Question 15 :

What is the purpose of realloc( ) ?

Answer :

The function realloc(ptr,n) uses two arguments. the first argument ptr is a pointer to a block of memory for which the size is to be altered. The second argument n specifies the new size.

The size may be increased or decreased. If n is greater than the old size and if sufficient space is not available subsequent to the old region, the function realloc( ) may create a new region and all the old data are moved to the new region.