Friday, July 20, 2018

C Questions And Answers – 2018A20

There are many commonly asked questions regarding C programming language. Below are some collected such question-answer examples. The questions are usually related with Turbo C IDE in windows or GCC under Linux environment [not always].

For more such examples, click C_Q&A label.

 

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

 

Why is it not possible to scan strings from keyboard in case of array of pointers to string?

 

Ans:

When an array is declared, dimension of array should be specified so that compiler can allocate memory for the array. When array of pointers to strings is declared its elements would contain garbage addresses. These addresses would be passed to scanf( ). So strings can be received but they would get stored at unkown locations. This is unsafe.

 

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

 

Bit Arrays

If in a program a variable is to take only two values 1 and 0, we really need only a single bit to store it.

 

Similarly, if a variable is to take values from 0 to 3, then two bits are sufficient to store these values. And if a variable is to take values from 0 through 7, then three bits will be enough, and so on. Why waste an entire integer when one or two or three bits will do? Because there aren't any one bit or two bit or three bit data types available in C. However, when there are several variables whose maximum values are small enough to pack into a single memory location, we can use `bit fields' to store several values in a single integer.

 

Bit fields are discussed in most standard C texts. They are usually used when we want to store assorted information which can be accommodated in 1, 2, 3 bits etc.

 

For example, the following data about an employee can be easily stored using bit fields.

male or female

single, married, divorced or widowed

 

have one of the eight different hobbies can choose from any of the fifteen different schemes proposed by the company to pursue his/her hobby.

 

This means we need one bit to store gender, two to store marital status, three for hobby, and four for scheme (with one value used for those who are not desirous of availing any of the schemes). We need ten bits altogether, which means we can pack all this information into a single integer, since an integer is 16 bits long.

 

At times we may need to store several True or False statuses. In such cases instead of using bit fields using an array of bits would be more sensible. On this array we may be required to perform the following operations:

 

Set a bit (make it 1).

Clear a bit (make it 0).

Test the status of a bit in the array.

Reach the appropriate bit slot in the array.

Generate a bit mask for setting and clearing a bit.

 

We can implement these operations using macros given below:

 

#define CHARSIZE 8

#define MASK ( y ) ( 1 << y % CHARSIZE )

#define BITSLOT ( y ) ( y / CHARSIZE )

#define SET ( x, y ) ( x[BITSLOT( y )] |= MASK( y ) )

#define CLEAR ( x, y ) ( x[BITSLOT( y )] &= ~MASK( y ) )

#define TEST ( x, y ) ( x[BITSLOT( y )] & MASK( y ) )

#define NUMSLOTS ( n ) ( ( n + CHARSIZE - 1) / CHARSIZE )

 

Using these macros we can declare an array of 50 bits be saying,

char arr[NUMSLOTS(50)] ;

 

To set the 20th bit we can say,

SET(arr, 20 ) ;

 

And if we are to test the status of 40th bit we may say,

if ( TEST ( arr, 40 ) )

 

Using bit arrays often results into saving a lot of precious memory. For example, the following program which implements the Sieve of Eratosthenes for generating prime numbers smaller than 100 requires only 13 bytes. Had we implemented the same logic using an array of integers we would have required an array of 100 integers, that is 200 bytes.

 

#include <stdio.h>

#include <string.h>

#define MAX 100

 

main( )

{

char arr[NUMSLOTS( MAX )] ;

int i, j ;

memset ( arr, 0, NUMSLOTS( MAX ) ) ;

for ( i = 2 ; i < MAX ; i++ )

{

if (!TEST (arr,i))

{

printf ( "\n%d", i ) ;

for ( j = i + i ; j < MAX ; j += i )

SET ( arr, j ) ;

}

}

}

 

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

 

Information Hiding in C

 

Though C language doesn't fully support encapsulation as C++ does, there is a simple technique through which we can implement encapsulation in C. The technique that achieves this is modular programming in C. Modular programming requires a little extra work from the programmer, but pays for itself during maintenance. To understand this technique let us take the example of the popular stack data structure. There are many methods of implementing a stack (array, linked list, etc.). Information hiding teaches that users should be able to push and pop the stack's elements without knowing about the stack's implementation. A benefit of this sort of information hiding is that users don't have to change their code even if the implementation details change.

 

Consider the following scenario:

To be able to appreciate the benefits of modular programming and thereby information hiding, would first show a traditional implementation of the stack data structure using pointers and a linked list of structures. The main( )function calls the push( ) and pop( ) functions.

 

#include <alloc.h>

 

typedef int element ;

void initialize_stack ( struct node ** ) ;

void push ( struct node **, element ) ;

element pop ( struct node * ) ;

int isempty ( struct node * ) ;

 

struct node

{

element data ;

struct node *next ;

} ;

 

void main( )

{

struct node *top ;

element num ;

initialize_stack ( &top ) ;

push ( &top, 10 ) ;

push ( &top, 20 ) ;

push ( &top, 30 ) ;

if ( isempty ( top ) )

printf ( "\nStack is empty" ) ;

else

{

num = pop ( top ) ;

printf ( "\n Popped %d", num ) ;

}

}

void initialize_stack ( struct node **p )

{

*p = NULL ;

}

void push ( struct node **p, element n )

{

struct node *r ;

r = ( struct node *) malloc ( sizeof ( struct node ) ) ;

r -> data = n ;

if ( *p == NULL )

r -> next = NULL ;

else

r -> next = *p ;

*p = r ;

}

element pop ( struct node *p )

{

element n;

struct node *r ;

n = p -> data ;

r = p ;

p = p -> next ;

free ( r ) ;

return ( n ) ;

}

int isempty (struct node *p)

{

if (p== NULL )

return ( -1 ) ;

else

return ( 0 ) ;

}

 

Notice how the specific implementation of the data structure is strewn throughout main( ). main( ) must see the definition of the structure node to use the push( ), pop( ), and other stack functions. Thus the implementation is not hidden, but is mixed with the abstract operations.

 

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

 

…till next post, bye-bye & take care.

No comments:

Post a Comment