Welcome Guest | Sign in | Register
Pointers - C Programming Interview Questions and Answers | LucentBlackBoard | LucentBlackBoard.com
11. Can you add pointers together? Why would you?

No, you can't add pointers together. If you live at 1332 Lakeview Drive, and your neighbor lives at 1364 Lakeview, what's 1332+1364? It's a number, but it doesn't mean anything. If you try to perform this type of calculation with pointers in a C program, your compiler will complain.
The only time the addition of pointers might come up is if you try to add a pointer and the difference of two pointers:
p = p + p2 - p1;
which is the same thing as this:
p = (p + p2) - p1.
Here's a correct way of saying this:
p = p + ( p2 - p1 );
Or even better in this case would be this example:
p += p2 - p1;

12. How do you use a pointer to a function?

The hardest part about using a pointer-to-function is declaring it. Consider an example. You want to create a pointer, pf, that points to the strcmp() function. The strcmp() function is declared in this way:
int strcmp( const char *, const char * )
To set up pf to point to the strcmp() function, you want a declaration that looks just like the strcmp()function's declaration, but that has *pf rather than strcmp:
int (*pf)( const char *, const char * );
Notice that you need to put parentheses around *pf. If you don't include parentheses, as in
int *pf( const char *, const char * ); /* wrong */
you'll get the same thing as this:
(int *) pf( const char *, const char * ); /* wrong */
That is, you'll have a declaration of a function that returns int*.
After you've gotten the declaration of pf, you can #include and assign the address of strcmp()to pf:
pf = strcmp;
or
pf = & strcmp; /* redundant & */
You don't need to go indirect on pf to call it:
if ( pf( str1, str2 ) > 0 ) /* ... */

13. When would you use a pointer to a function?

Pointers to functions are interesting when you pass them to other functions. A function that takes function pointers says, in effect, "Part of what I do can be customized. Give me a pointer to a function, and I'll call it when that part of the job needs to be done. That function can do its part for me." This is known as a "callback." It's used a lot in graphical user interface libraries, in which the style of a display is built into the library but the contents of the display are part of the application.
As a simpler example, say you have an array of character pointers (char*s), and you want to sort it by the value of the strings the character pointers point to. The standard qsort() function uses function pointers to perform that task. qsort() takes four arguments
1. a pointer to the beginning of the array,
2. the number of elements in the array,
3. the size of each array element, and
4. a comparison function.
and returns an int.
The comparison function takes two arguments, each a pointer to an element. The function returns 0 if the pointed-to elements compare equal, some negative value if the first element is less than the second, and some positive value if the first element is greater than the second. A comparison function for integers might look like this:
int icmp( const int *p1, const int *p2 )
{
return *p1 - *p2;
}
The sorting algorithm is part of qsort(). So is the exchange algorithm; it just copies bytes, possibly by callingmemcpy() or memmove(). qsort() doesn't know what it's sorting, so it can't know how to compare them. That part is provided by the function pointer.
You can't use strcmp() as the comparison function for this example, for two reasons. The first reason is thatstrcmp()'s type is wrong; more on that a little later. The second reason is that it won't work. strcmp() takes two pointers to char and treats them as the first characters of two strings. The example deals with an array of character pointers (char*s), so the comparison function must take two pointers to character pointers(char*s). In this case, the following code might be an example of a good comparison function:
int strpcmp( const void *p1, const void *p2 )
{
char * const *sp1 = (char * const *) p1;
char * const *sp2 = (char * const *) p2;
return strcmp( *sp1, *sp2 );
}
The call to qsort() might look something like this:
qsort( array, numElements, sizeof( char * ), pf2 );
qsort() will call strpcmp() every time it needs to compare two character pointers (char*s).
Why can't strcmp() be passed to qsort(), and why were the arguments of strpcmp() what they were?
A function pointer's type depends on the return type of the pointed-to function, as well as the number and types of all its arguments. qsort() expects a function that takes two constant void pointers:
void qsort( void *base,
size_t numElements,
size_t sizeOfElement,
int (*compFunct)( const void *, const void *) );
Because qsort() doesn't really know what it's sorting, it uses a void pointer in its argument (base) and in the arguments to the comparison function. qsort()'s void* argument is easy; any pointer can be converted to avoid* without even needing a cast. The function pointer is harder.
For an array of character arrays, strcmp() would have the right algorithm but the wrong argument types. The simplest, safest way to handle this situation is to pass a function that takes the right argument types forqsort() and then casts them to the right argument types. That's what strpcmp() does.
If you have a function that takes a char*, and you know that a char* and a void* are the same in every environment your program might ever work in, you might cast the function pointer, rather than the pointed- to function's arguments, in this way:
char table[ NUM_ELEMENTS ][ ELEMENT_SIZE ];
/* ... */
/* passing strcmp() to qsort for array of array of char */
qsort( table, NUM_ELEMENTS, ELEMENT_SIZE,
( int (*)( const void *, const void * ) ) strcmp );
Casting the arguments and casting the function pointer both can be error prone. In practice, casting the function pointer is more dangerous.
The basic problem here is using void* when you have a pointer to an unknown type. C++ programs sometime solve this problem with templates.

14. Can the size of an array be declared at runtime?

No. In an array declaration, the size must be known at compile time. You can't specify a size that's known only at runtime. For example, if i is a variable, you can't write code like this:
char array[i]; /* not valid C */
Some languages provide this latitude. C doesn't. If it did, the stack would be more complicated, function calls would be more expensive, and programs would run a lot slower.
If you know that you have an array but you won't know until runtime how big it will be, declare a pointer to it and use malloc() or calloc() to allocate the array from the heap.
If you know at compile time how big an array is, you can declare its size at compile time. Even if the size is some complicated expression, as long as it can be evaluated at compile time, it can be used.
/* A program that copies the argv array and all the pointed-to
strings. It also deallocates all the copies. */
#include
#include
int main(int argc, char** argv)
{
char** new_argv;
int i;
/* Since argv[0] through argv[argc] are all valid, the
program needs to allocate room for argc+1 pointers. */
new_argv = (char**) calloc(argc+1, sizeof (char*));
/* or malloc((argc+1) * sizeof (char*)) */
printf("allocated room for %d pointers starting at %P\n", argc+1, new_argv);
/* now copy all the strings themselves
(argv[0] through argv[argc-1]) */
for (i = 0; i < argc; ++i) {
/* make room for '\0' at end, too */
new_argv[i] = (char*) malloc(strlen(argv[i]) + 1);
strcpy(new_argv[i], argv[i]);
printf("allocated %d bytes for new_argv[%d] at %P, ""copied \"%s\"\n",
strlen(argv[i]) + 1, i, new_argv[i], new_argv[i]);
}
new_argv[argc] = NULL;
/* To deallocate everything, get rid of the strings (in any
order), then the array of pointers. If you free the array
of pointers first, you lose all reference to the copied
strings. */
for (i = 0; i < argc; ++i)
{
free(new_argv[i]);
printf("freed new_argv[%d] at %P\n", i, new_argv[i]);
argv[i] = NULL;
}
free(new_argv);
printf("freed new_argv itself at %P\n", new_argv);
return 0; 

15. Is it better to use malloc() or calloc()?

Both the malloc() and the calloc() functions are used to allocate dynamic memory. Each operates slightly different from the other. malloc() takes a size and returns a pointer to a chunk of memory at least that big:
void *malloc( size_t size );
calloc() takes a number of elements, and the size of each, and returns a pointer to a chunk of memory at least big enough to hold them all:
void *calloc( size_t numElements, size_t sizeOfElement );
There's one major difference and one minor difference between the two functions. The major difference is thatmalloc() doesn't initialize the allocated memory. The first time malloc() gives you a particular chunk of memory, the memory might be full of zeros. If memory has been allocated, freed, and reallocated, it probably has whatever junk was left in it. That means, unfortunately, that a program might run in simple cases (when memory is never reallocated) but break when used harder (and when memory is reused).
calloc() fills the allocated memory with all zero bits. That means that anything there you're going to use as achar or an int of any length, signed or unsigned, is guaranteed to be zero. Anything you're going to use as a pointer is set to all zero bits. That's usually a null pointer, but it's not guaranteed.
Anything you're going to use as a float or double is set to all zero bits; that's a floating-point zero on some types of machines, but not on all.
The minor difference between the two is that calloc() returns an array of objects; malloc() returns one object. Some people use calloc() to make clear that they want an array. Other than initialization, most C programmers don't distinguish between
calloc( numElements, sizeOfElement)
and
malloc( numElements * sizeOfElement)
There's a nit, though. malloc() doesn't give you a pointer to an array. In theory (according to the ANSI C standard), pointer arithmetic works only within a single array. In practice, if any C compiler or interpreter were to enforce that theory, lots of existing C code would break. (There wouldn't be much use for realloc(), either, which also doesn't guarantee a pointer to an array.)
Don't worry about the array-ness of calloc(). If you want initialization to zeros, use calloc(); if not, usemalloc().




Partner Sites
LucentBlackBoard.com                  SoftLucent.com                  LucentJobs.com
All rights reserved © 2012-2015 SoftLucent.