Coupon Accepted Successfully!


Question 11

What is an opaque pointer?

A pointer is said to be opaque if the definition of the type to which it points to is not included in the current translation unit. A translation unit is the result of merging an implementation file with all its headers and header files.


Question 12

What is a null pointer assignment error?
This error means that the program has written, through a null (probably because its an uninitialized) pointer, to a location thats invalid.

Question 13

Does an array always get converted to a pointer? What is the difference between arr and &arr? How does one declare a pointer to an entire array?
Well, not always.
In C, the array and pointer arithmetic is such that a pointer can be used to access an array or to simulate an array. What this means is whenever an array appears in an expression, the compiler automatically generates a pointer to the array's first element (i.e, &a[0]).

There are three exceptions to this rule
1. When the array is the operand of the sizeof() operator.
2. When using the & operator.
3. When the array is a string literal initializer for a character array.

Also, on a side note, the rule by which arrays decay into pointers is not applied recursively!. An array of arrays (i.e. a two-dimensional array in C) decays into a pointer to an array, not a pointer to a pointer.

If you are passing a two-dimensional array to a function:

int myarray[NO_OF_ROWS][NO_OF_COLUMNS];

then, the function's declaration must match:
void myfunc(int myarray[][NO_OF_COLUMNS])
void myfunc(int (*myarray)[NO_OF_COLUMNS])

Since the called function does not allocate space for the array, it does not need to know the overall size, so the number of rows, NO_OF_ROWS, can be omitted. The width of the array is still important, so the column dimension
NO_OF_COLUMNS must be present.

An array is never passed to a function, but a pointer to the first element of the array is passed to the function. Arrays are automatically allocated memory. They can't be relocated or resized later. Pointers must be assigned to allocated memory (by using (say) malloc), but pointers can be reassigned and made to point to other memory chunks.

So, whats the difference between func(arr) and func(&arr)?

In C, &arr yields a pointer to the entire array. On the other hand, a simple reference to arr returns a pointer to the first element of the array arr. Pointers to arrays (as in &arr) when subscripted or incremented, step over entire arrays, and are useful only when operating on arrays of arrays. Declaring a pointer to an entire array can be done like int (*arr)[N];, where N is the size of the array.

Also, note that sizeof() will not report the size of an array when the array is a parameter to a function, simply because the compiler pretends that the array parameter was declared as a
pointer and sizeof reports the size of the pointer.

Question 14

Is the cast to malloc() required at all?
Before ANSI C introduced the void * generic pointer, these casts were required because older compilers used to return a char pointer.
int *myarray;
myarray = (int *)malloc(no_of_elements * sizeof(int));

But, under ANSI Standard C, these casts are no longer necessary as a void pointer can be assigned to any pointer. These casts are still required with C++, however.

Question 15

What does malloc() , calloc(), realloc(), free() do? What are the common problems with malloc()? Is there a way to find out how much memory a pointer was allocated?
malloc() is used to allocate memory. Its a memory manager.

calloc(m, n) is also used to allocate memory, just like malloc(). But in addition, it also zero fills the allocated memory area. The zero fill is all-bits-zero. calloc(m.n) is essentially equivalent to

p = malloc(m * n);
memset(p, 0, m * n);

The malloc() function allocates raw memory given a size in bytes. On the other hand, calloc() clears the requested memory to zeros before return a pointer to it. (It can also compute the request size given the size of the base data structure and the number of them desired.)

The most common source of problems with malloc() are
1. Writing more data to a malloc'ed region than it was allocated to hold.
2. malloc(strlen(string)) instead of (strlen(string) + 1).
3. Using pointers to memory that has been freed.
4. Freeing pointers twice.
5. Freeing pointers not obtained from malloc.
6. Trying to realloc a null pointer.

How does free() work?

Any memory allocated using malloc() realloc() must be freed using free(). In general, for every call to malloc(), there should be a corresponding call to free(). When you call free(), the memory pointed to by the passed pointer is freed. However, the value of the pointer in the caller remains unchanged. Its a good practice to set the pointer to NULL after freeing it to prevent accidental usage. The malloc()/free() implementation keeps track of the size of each block as it is allocated, so it is not required to remind it of the size when freeing it using free(). You can't use dynamically-allocated memory after you free it.

Is there a way to know how big an allocated block is?

Unfortunately there is no standard or portable way to know how big an allocated block is using the pointer to the block!. God knows why this was left out in C.

Is this a valid expression?
pointer = realloc(0, sizeof(int));

Yes, it is!

Question 16

What's the difference between const char *p, char * const p and const char * const p?
const char *p    -   This is a pointer to a constant char. One cannot change the value pointed at by p, but can change the pointer p itself.
*p = 'A' is illegal.
p  = "Hello" is legal.
Note that even char const *p is the same!

const * char p   -   This is a constant pointer to (non-const) char. One cannot change the pointer p, but can change the value pointed atby p.
*p = 'A' is legal.
p  = "Hello" is illegal.

const char * const p  -   This is a constant pointer to constant char! One cannot change the value pointed to by p nor the pointer.
*p = 'A' is illegal.
p  = "Hello" is also illegal.

To interpret these declarations, let us first consider the general form of declaration
[qualifier] [storage-class] type [*[*]..] [qualifier] ident ; 
[storage-class] [qualifier] type [*[*]..] [qualifier] ident ; 

qualifier: volatile, const
storage-class:  auto, extern, static, register
type: void, char, short, int, long, float, double, signed, unsigned, enum-specifier, typedef-name, struct-or-union-specifier.

Both the forms are equivalent. Keywords in the brackets are optional. The simplest tip here is to notice the relative position of the `const' keyword with respect to the asterisk (*).

Note the following points:
  • If the `const' keyword is to the left of the asterisk, and is the only such keyword in the declaration, then object pointed by the pointer is constant, however, the pointer itself is variable. For example:
    const char * pcc; 
    char const * pcc; 
  • If the `const' keyword is to the right of the asterisk, and is the only such keyword in the declaration, then the object pointed by the pointer is variable, but the pointer is constant; i.e., the pointer, once initialized, will always point to the same object through out it's scope. For example:
    char * const cpc; 
  • If the `const' keyword is on both sides of the asterisk, the both the pointer and the pointed object are constant. For example:
    const char * const cpcc; 
    char const * const cpcc2; 
One can also follow the "nearness" principle; i.e.,
  • If the `const' keyword is nearest to the `type', then the object is constant. For example:
    char const * pcc; 
  • If the `const' keyword is nearest to the identifier, then the pointer is constant. For example:
    char * const cpc; 
  • If the `const' keyword is nearest, both to the identifier and the type, then both the pointer and the object are constant. For example:
    const char * const cpcc; 
    char const * const cpcc2; 
However, the first method seems more reliable...

Question 17

What is a void pointer? Why can't we perform arithmetic on a void * pointer?
The void data type is used when no other data type is appropriate. A void pointer is a pointer that may point to any kind of object at all. It is used when a pointer must be specified but its type is unknown.

The compiler doesn't know the size of the pointed-to objects incase of a void * pointer. Before performing arithmetic, convert the pointer either to char * or to the pointer type you're trying to manipulate.

Question 18

What do Segmentation fault, access violation, core dump and Bus error mean?

The segmentation fault, core dump, bus error kind of errors usually mean that the program tried to access memory it shouldn't have.

Probable causes are overflow of local arrays; improper use of null pointers; corruption of the malloc() data structures; mismatched function arguments (specially variable argument functions like sprintf(), fprintf(), scanf(), printf()).

For example, the following code is a sure shot way of inviting a segmentation fault in your program:

        "%s %d",

So whats the difference between a bus error and a segmentation fault?

A bus error is a fatal failure in the execution of a machine language instruction resulting from the processor
detecting an anomalous condition on its bus.

Such conditions include:

- Invalid address alignment (accessing a multi-byte number at an odd address).
- Accessing a memory location outside its address space.
- Accessing a physical address that does not correspond to any device.
- Out-of-bounds array references.
- References through uninitialized or mangled pointers.

A bus error triggers a processor-level exception, which Unix translates into a "SIGBUS" signal,which if not caught, will terminate the current process. It looks like a SIGSEGV, but the difference between the two is that SIGSEGV indicates an invalid access to valid memory, while SIGBUS indicates an access to an invalid address.

Bus errors mean different thing on different machines. On systems such as Sparcs a bus error occurs when you access memory that is not positioned correctly.

Maybe an example will help to understand how a bus error occurs


int main(void) 

  char *c; 
  long int *i; 
  c = (char *) malloc(sizeof(char)); 
  i = (long int *)c; 
  printf("%ld", *i); 
  return 0; 

On Sparc machines long ints have to be at addresses that are multiples of four (because they are four bytes long), while chars do not (they are only one byte long so they can be put anywhere). The example code uses the char to create an invalid address, and assigns the long int to the invalid address. This causes a bus error when the long int is dereferenced.

A segfault occurs when a process tries to access memory that it is not allowed to, such as the memory at address 0 (where NULL usually points). It is easy to get a segfault, such as the following example, which dereferences NULL.


int main(void) 

  char *p; 
  p = NULL; 
  return 0; 

Question 19

What is the difference between an array of pointers and a pointer to an array?

This is an array of pointers

int *p[10];

This is a pointer to a 10 element array

int (*p)[10];

Test Your Skills Now!
Take a Quiz now
Reviewer Name