Welcome Guest | Sign in | Register
Functions - C Programming Interview Questions and Answers | LucentBlackBoard | LucentBlackBoard.com

Home > Technical Interviews > Computer Science & Engineering > C Programming > Functions Questions and Answers

1. When should I declare a function?

Functions that are used only in the current source file should be declared as static, and the function's declaration should appear in the current source file along with the definition of the function. Functions used outside of the current source file should have their declarations put in a header file, which can be included in whatever source file is going to use that function. For instance, if a function named stat_func() is used only in the source file stat.c, it should be declared as shown here:
/* stat.c */
#include
static int stat_func(int, int); /* static declaration of stat_func() */
void main(void);
void main(void)
{
...
rc = stat_func(1, 2);
...
}
/* definition (body) of stat_func() */
static int stat_func(int arg1, int arg2)
{
...
return rc;
}
In this example, the function named stat_func() is never used outside of the source file stat.c. There is therefore no reason for the prototype (or declaration) of the function to be visible outside of the stat.c source file. Thus, to avoid any confusion with other functions that might have the same name, the declaration ofstat_func() should be put in the same source file as the declaration of stat_func().
In the following example, the function glob_func() is declared and used in the source file global.c and is used in the source file extern.c. Because glob_func() is used outside of the source file in which it's declared, the declaration of glob_func() should be put in a header file (in this example, named proto.h) to be included in both the global.c and the extern.c source files. This is how it's done:
/* proto.h */
int glob_func(int, int); /* declaration of the glob_func() function */
/* global.c */
#include
#include "proto.h"
/* include this proto.h file for the declaration of glob_func() */
void main(void);
void main(void)
{
...
rc = glob_func(1, 2);
...
}
/* definition (body) of the glob_func() function */
int glob_func(int arg1, int arg2)
{
...
return rc;
}
/* extern.c */
#include
#include "proto.h"
/* include this proto.h file for the declaration of glob_func() */
void ext_func(void);
void ext_func(void)
{
...
/* call glob_func(), which is defined in the global.c source file */
rc = glob_func(10, 20);
...
}
In the preceding example, the declaration of glob_func() is put in the header file named proto.h becauseglob_func() is used in both the global.c and the extern.c source files. Now, whenever glob_func() is going to be used, you simply need to include the proto.h header file, and you will automatically have the function's declaration. This will help your compiler when it is checking parameters and return values from global functions you are using in your programs. Notice that your function declarations should always appear before the first function declaration in your source file.
In general, if you think your function might be of some use outside of the current source file, you should put its declaration in a header file so that other modules can access it. Otherwise, if you are sure your function will never be used outside of the current source file, you should declare the function as static and include the declaration only in the current source file.

2. Why should I prototype a function?

A function prototype tells the compiler what kind of arguments a function is looking to receive and what kind of return value a function is going to give back. This approach helps the compiler ensure that calls to a function are made correctly and that no erroneous type conversions are taking place. For instance, consider the following prototype:
int some_func(int, char*, long);
Looking at this prototype, the compiler can check all references (including the definition of some_func()) to ensure that three parameters are used (an integer, a character pointer, and then a long integer) and that a return value of type integer is received. If the compiler finds differences between the prototype and calls to the function or the definition of the function, an error or a warning can be generated to avoid errors in your source code. For instance, the following examples would be flagged as incorrect, given the preceding
prototype of some_func():
x = some_func(1); /* not enough arguments passed */
x = some_func("HELLO!", 1, "DUDE!"); /* wrong type of arguments used */
x = some_func(1, str, 2879, "T"); /* too many arguments passed */

/* In the following example, the return value expected
from some_func() is not an integer: */

long* lValue;
lValue = some_func(1, str, 2879); /* some_func() returns an int,
not a long* */
Using prototypes, the compiler can also ensure that the function definition, or body, is correct and correlates with the prototype. For instance, the following definition of some_func() is not the same as its prototype, and it therefore would be flagged by the compiler:
int some_func(char* string, long lValue, int iValue) /* wrong order of
parameters */
{
...
}
The bottom line on prototypes is that you should always include them in your source code because they provide a good error-checking mechanism to ensure that your functions are being used correctly. Besides, many of today's popular compilers give you warnings when compiling if they can't find a prototype for a function that is being referenced.

3. How many parameters should a function have?

There is no set number or "guideline" limit to the number of parameters your functions can have. However, it is considered bad programming style for your functions to contain an inordinately high (eight or more) number of parameters. The number of parameters a function has also directly affects the speed at which it is called—the more parameters, the slower the function call. Therefore, if possible, you should minimize the number of parameters you use in a function. If you are using more than four parameters, you might want to rethink your function design and calling conventions.
One technique that can be helpful if you find yourself with a large number of function parameters is to put your function parameters in a structure. Consider the following program, which contains a function namedprint_report() that uses 10 parameters. Instead of making an enormous function declaration and proto- type, the print_report() function uses a structure to get its parameters:
#include
typedef struct
{
int orientation;
char rpt_name[25];
char rpt_path[40];
int destination;
char output_file[25];
int starting_page;
int ending_page;
char db_name[25];
char db_path[40];
int draft_quality;
} RPT_PARMS;
void main(void);
int print_report(RPT_PARMS*);
void main(void)
{
RPT_PARMS rpt_parm; /* define the report parameter
structure variable */
...
/* set up the report parameter structure variable to pass to the
print_report() function */
rpt_parm.orientation = ORIENT_LANDSCAPE;
rpt_parm.rpt_name = "QSALES.RPT";
rpt_parm.rpt_path = "C:\REPORTS";
rpt_parm.destination = DEST_FILE;
rpt_parm.output_file = "QSALES.TXT";
rpt_parm.starting_page = 1;
rpt_parm.ending_page = RPT_END;
rpt_parm.db_name = "SALES.DB";
rpt_parm.db_path = "C:\DATA";
rpt_parm.draft_quality = TRUE;
/* Call the print_report() function, passing it a pointer to the
parameters instead of passing it a long list of 10 separate
parameters. */
ret_code = print_report(&rpt_parm);
...
}
int print_report(RPT_PARMS* p)
{
int rc;
...
/* access the report parameters passed to the print_report()
function */
orient_printer(p->orientation);
set_printer_quality((p->draft_quality == TRUE) ? DRAFT : NORMAL);
...
return rc;
}
The preceding example avoided a large, messy function prototype and definition by setting up a predefined structure of type RPT_PARMS to hold the 10 parameters that were needed by the print_report() function. The only possible disadvantage to this approach is that by removing the parameters from the function definition, you are bypassing the compiler's capability to type-check each of the parameters for validity during the compile stage.
Generally, you should keep your functions small and focused, with as few parameters as possible to help with execution speed. If you find yourself writing lengthy functions with many parameters, maybe you should rethink your function design or consider using the structure-passing technique presented here. Additionally, keeping your functions small and focused will help when you are trying to isolate and fix bugs in your programs.

4. What is a static function?

A static function is a function whose scope is limited to the current source file. Scope refers to the visibility of a function or variable. If the function or variable is visible outside of the current source file, it is said to haveglobal, or external, scope. If the function or variable is not visible outside of the current source file, it is said to have local, or static, scope.
A static function therefore can be seen and used only by other functions within the current source file. When you have a function that you know will not be used outside of the current source file or if you have a function that you do not want being used outside of the current source file, you should declare it as static. Declaring local functions as static is considered good programming practice. You should use static functions often to avoid possible conflicts with external functions that might have the same name.
For instance, consider the following example program, which contains two functions. The first function,open_customer_table(), is a global function that can be called by any module. The second function,open_customer_indexes(), is a local function that will never be called by another module. This is because you can't have the customer's index files open without first having the customer table open. Here is the code:
#include
int open_customer_table(void); /* global function, callable from
any module */
static int open_customer_indexes(void); /* local function, used only in
this module */
int open_customer_table(void)
{
int ret_code;
/* open the customer table */
...
if (ret_code == OK)
{
ret_code = open_customer_indexes();
}
return ret_code;
}
static int open_customer_indexes(void)
{
int ret_code;
/* open the index files used for this table */
...
return ret_code;
}
Generally, if the function you are writing will not be used outside of the current source file, you should declare it as static.

5. Should a function contain a return statement if it does not return a value?

In C, void functions (those that do not return a value to the calling function) are not required to include a return statement. Therefore, it is not necessary to include a return statement in your functions declared as being void.
In some cases, your function might trigger some critical error, and an immediate exit from the function might be necessary. In this case, it is perfectly acceptable to use a return statement to bypass the rest of the function's code. However, keep in mind that it is not considered good programming practice to litter your functions with return statements-generally, you should keep your function's exit point as focused and clean as possible.




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