Functions are important program design tools because they allow you to break a large program up into manageable pieces, and to deal with each piece separately.
Pure functions. A pure function does not change anything. It only computes a value. For example, strlen is a pure function. You pass it a string, and it gives you the length of the string. You think of a pure function the way you do a mathematical function such as sqrt.
Procedures. A procedure is a function that makes changes to things, and that returns a void value. You think of it as performing a command. Sometimes, a procedure only changes the values of reference parameters. Sometimes, it changes other things, such as things pointed to by parameters or pointers inside data structures.
Mixed functions. A mixed function returns a value, and also has side effects. For example, scanf is a mixed function. It puts values in its parameters, but it also returns a value. (The value returned by scanf is the number of items that it successfully read.) Mixed functions can be useful, but should be used with care. If you do more than one in a single expression, the different mixed functions might interfere with one another.
The functions of a particular application can usually be broken into two groups. First are functions that are particular to the application, and would make little sense if found in another application. Such functions might, for example, print messages that would almost certainly not be appropriate to other applications. I will call these functions application specific. The second kind of functions are those that might easily be picked up and put into another application, without change. I will call these functions application independent.
Prototype. The prototype tells the types of the parameters and the return type. It tells the compiler how the function can be used in a program.
Meaning. The meaning of a function tells what the function does. It is usually a comment, and is called a contract for the function. The contract should tell about all of the parameters, about the return value, and about any changes that the function makes. It should not tell details that are supposed to be encapsulated inside the function, such as how the function does its job.
You can tell whether a function is application specific or application independent by examining its contract. If the description of the function makes reference to where this function fits into the current application (for example, by saying that this function is called by function jam, which handles part three of the application) then the function is application specific. If the description only tells what the function does, without reference to who calls it or exactly how it is used in the application, then the function is often application independent.
Novice programmers tend to make all of their functions application specific. Expert programmers make as many functions as possible application independent.
This is an application independent function. Its description tells what it does, not for what purpose some other part of a program uses it.
/////////////////////////////////////////////////////// // prime(n) returns TRUE if n is prime, and FALSE if n // is not prime. /////////////////////////////////////////////////////// bool prime(long int n) { //-------------------------------------------------- // The algorithm is to divide n by 2,3,...,k until a // factor is found or n < k*k. //-------------------------------------------------- long int k = 2; while(n >= k*k) { if(0 == n % k) return FALSE; k++; } //-------------------------------------------------- // If we get out of the loop, then no factor was found, // and n must be prime. //-------------------------------------------------- return TRUE; }
////////////////////////////////////////////////// // replace_slash_by_colon(s) replaces each '/' in // null-terminated string s by ':'. The change // is made in-place. ////////////////////////////////////////////////// void replace_slash_by_colon(char* s) { char* p = s; while(*p != 0) { if('/' == *p) *p = ':'; p++; } }
///////////////////////////////////////////////// // Parameter s must be a null-terminated string. // // Return a pointer to a newly allocated string // (allocated using new), where that string is a // copy of s, but with each '/' replaced by ':'. ///////////////////////////////////////////////// char* slash_replaced_by_colon(const char* s) { const char* p = s; char* n = new char[strlen(s) + 1]; char* q = n; while(*p != 0) { if('/' == *p) *q = ':'; else *q = *p; p++; q++; } *q = 0; // copy the null. return n; }
/////////////////////////////////////////////////// // Parameter s must be a null-terminated string. // // Put, into buffer dest, a copy of string src, but // with each '/' replaced by a ':'. /////////////////////////////////////////////////// void replace_slash_by_colon(char* dest, const char* src) { const char* p = src; char* q = dest; while(*p != 0) { if('/' == *p) *q = ':'; else *q = *p; p++; q++; } *q = 0; // copy the null. }