# C Language interview questions

• 1.

Can you subtract pointers from each other? Why would you?

If you have two pointers into the same array, you can subtract them. The answer is the number of elements between the two elements.

Consider the street address analogy presented in the introduction of this chapter. Say that I live at 118 Fifth Avenue and that my neighbor lives at 124 Fifth Avenue. The "size of a house" is two (on my side of the street, sequential even numbers are used), so my neighbor is (124-118)/2 (or 3) houses up from me. (There are two houses between us, 120 and 122; my neighbor is the third.) You might do this subtraction if you're going back and forth between indices and pointers.

You might also do it if you're doing a binary search. If p points to an element that's before what you're looking for, and q points to an element that's after it, then (q-p)/2+p points to an element between p and q. If that element is before what you want, look between it and q. If it's after what you want, look between p and it.

(If it's what you're looking for, stop looking.)

You can't subtract arbitrary pointers and get meaningful answers. Someone might live at 110 Main Street, but I can't subtract 110 Main from 118 Fifth (and divide by 2) and say that he or she is four houses away!

If each block starts a new hundred, I can't even subtract 120 Fifth Avenue from 204 Fifth Avenue. They're on the same street, but in different blocks of houses (different arrays).

C won't stop you from subtracting pointers inappropriately. It won't cut you any slack, though, if you use the meaningless answer in a way that might get you into trouble.

When you subtract pointers, you get a value of some integer type. The ANSI C standard defines a typedef,ptrdiff_t, for this type. (It's in <stddef.h>.) Different compilers might use different types (int or long or whatever), but they all define ptrdiff_t appropriately.

Below is a simple program that demonstrates this point. The program has an array of structures, each 16 bytes long. The difference between array[0] and array[8] is 8 when you subtract struct stuff pointers, but 128 (hex 0x80) when you cast the pointers to raw addresses and then subtract.

If you subtract 8 from a pointer to array[8], you don't get something 8 bytes earlier; you get something 8 elements earlier.

``````#include <stdio.h>
#include <stddef.h>
struct stuff {
char    name[16];
/* other stuff could go here, too */
};
struct stuff array[] = {
{ "The" },
{ "quick" },
{ "brown" },
{ "fox" },
{ "jumped" },
{ "over" },
{ "the" },
{ "lazy" },
{ "dog." },
{ "" }
};
int main()
{
struct stuff    *p0 = & array[0];
struct stuff    *p8 = & array[8];
ptrdiff_t       diff = p8 - p0;
ptrdiff_t       addr_diff = (char*) p8 - (char*) p0;
/* cast the struct stuff pointers to void* */
printf("& array[0] = p0 = %P\n", (void*) p0);
printf("& array[8] = p8 = %P\n", (void*) p8);
/* cast the ptrdiff_t's to long's
(which we know printf() can handle) */
printf("The difference of pointers is %ld\n",
(long) diff);
printf("The difference of addresses is %ld\n",
printf("p8 - 8 = %P\n", (void*) (p8 - 8));

printf("p0 + 8 = %P (same as p8)\n", (void*) (p0 + 8));
return 0;
}``````
• 2.

When is a void pointer used?

void pointer is used for working with raw memory or for passing a pointer to an unspecified type.

Some C code operates on raw memory. When C was first invented, character pointers (char *) were used for that. Then people started getting confused about when a character pointer was a string, when it was a character array, and when it was raw memory.

For example, strcpy() is used to copy data from one string to another, and strncpy() is used to copy at most a certain length string to another:

char *strcpy( char *str1, const char *str2 );

char *strncpy( char *str1, const char *str2, size_t n );

memcpy() is used to move data from one location to another:

void pointers are used to mean that this is raw memory being copied. NUL characters (zero bytes) aren't significant, and just about anything can be copied. Consider the following code:

``````#include "thingie.h"    /* defines struct thingie */
struct thingie  *p_src, *p_dest;
/* ... */
memcpy( p_dest, p_src, sizeof( struct thingie) * numThingies );
``````

This program is manipulating some sort of object stored in a struct thingie. p1 and p2 point to arrays, or parts of arrays, of struct thingies. The program wants to copy numThingies of these, starting at the one pointed to by p_src, to the part of the array beginning at the element pointed to by p_destmemcpy() treatsp_src and p_dest as pointers to raw memory; sizeof( struct thingie) * numThingies is the number of bytes to be copied.

• 3.

What is a void pointer?

void pointer is a C convention for "a raw address." The compiler has no idea what type of object a void pointer "really points to." If you write

int *ip;

ip points to an int. If you write

void *p;

p doesn't point to a void!

In C and C++, any time you need a void pointer, you can use another pointer type. For example, if you have a char*, you can pass it to a function that expects a void*. You don't even need to cast it. In C (but not in C++), you can use a void* any time you need any kind of pointer, without casting. (In C++, you need to cast it.)

• 4.

When is a null pointer used?

The null pointer is used in three ways:

1. To stop indirection in a recursive data structure.

2. As an error value.

3. As a sentinel value.

1. Using a Null Pointer to Stop Indirection or Recursion

Recursion is when one thing is defined in terms of itself. A recursive function calls itself. The following factorial function calls itself and therefore is considered recursive:

``````/* Dumb implementation; should use a loop */
unsigned factorial( unsigned i )
{
if ( i == 0 || i == 1 )
{
return 1;
}
else
{
return i * factorial( i - 1 );
}
}
``````

A recursive data structure is defined in terms of itself. The simplest and most common case is a (singularly) linked list. Each element of the list has some value, and a pointer to the next element in the list:

``````struct string_list
{
char    *str;   /* string (in this case) */
struct string_list      *next;
};
``````

There are also doubly linked lists (which also have a pointer to the preceding element) and trees and hash tables and lots of other neat stuff. You'll find them described in any good book on data structures. You refer to a linked list with a pointer to its first element. That's where the list starts; where does it stop? This is where the null pointer comes in. In the last element in the list, the next field is set to NULL when there is no following element. To visit all the elements in a list, start at the beginning and go indirect on the next pointer as long as it's not null:

``````while ( p != NULL )
{
/* do something with p->str */
p = p->next;
}
``````

Notice that this technique works even if p starts as the null pointer.

2. Using a Null Pointer As an Error Value

The second way the null pointer can be used is as an error value. Many C functions return a pointer to some object. If so, the common convention is to return a null pointer as an error code:

``````if ( setlocale( cat, loc_p ) == NULL )
{
/* setlocale() failed; do something */
/* ... */
}
``````

This can be a little confusing. Functions that return pointers almost always return a valid pointer (one that doesn't compare equal to zero) on success, and a null pointer (one that compares equal to zero) pointer on failure. Other functions return an int to show success or failure; typically, zero is success and nonzero is failure. That way, a "true" return value means "do some error handling":

``````if ( raise( sig ) != 0 ) {
/* raise() failed; do something */
/* ... */
}
``````

The success and failure return values make sense one way for functions that return ints, and another for functions that return pointers. Other functions might return a count on success, and either zero or some negative value on failure. As with taking medicine, you should read the instructions first.

Using a Null Pointer As a Sentinel Value

The third way a null pointer can be used is as a "sentinel" value. A sentinel value is a special value that marks the end of something. For example, in main(), argv is an array of pointers. The last element in the array (argv[argc]) is always a null pointer. That's a good way to run quickly through all the elements:

``````/* A simple program that prints all its arguments.
It doesn't use argc ("argument count"); instead,
it takes advantage of the fact that the last value
in argv ("argument vector") is a null pointer. */
#include <stdio.h>
#include <assert.h>
int
main( int argc, char **argv)
{
int i;
printf("program name = \"%s\"\n", argv[0]);
for (i=1; argv[i] != NULL; ++i)
printf("argv[%d] = \"%s\"\n", i, argv[i]);
assert(i == argc);
return 0;
}``````
• 5.

What is a null pointer?

There are times when it's necessary to have a pointer that doesn't point to anything. The macro NULL, defined in <stddef.h>, has a value that's guaranteed to be different from any valid pointer. NULL is a literal zero, possibly cast to void* or char*. Some people, notably C++ programmers, prefer to use 0 rather than NULL.

You can't use an integer when a pointer is required. The exception is that a literal zero value can be used as the null pointer. (It doesn't have to be a literal zero, but that's the only useful case. Any expression that can be evaluated at compile time, and that is zero, will do. It's not good enough to have an integer variable that might be zero at runtime.)

• 6.

How many levels of pointers can you have?

The answer depends on what you mean by "levels of pointers." If you mean "How many levels of indirection can you have in a single declaration?" the answer is "At least 12."

int i = 0;

int *ip01 = & i;

int **ip02 = & ip01;

int ***ip03 = & ip02;

int ****ip04 = & ip03;

int *****ip05 = & ip04;

int ******ip06 = & ip05;

int *******ip07 = & ip06;

int ********ip08 = & ip07;

int *********ip09 = & ip08;

int **********ip10 = & ip09;

int ***********ip11 = & ip10;

int ************ip12 = & ip11;

************ip12 = 1; /* i = 1 */

If you mean "How many levels of pointer can you use before the program gets hard to read," that's a matter of taste, but there is a limit. Having two levels of indirection (a pointer to a pointer to something) is common. Any more than that gets a bit harder to think about easily; don't do it unless the alternative would be worse.

If you mean "How many levels of pointer indirection can you have at runtime," there's no limit. This point is particularly important for circular lists, in which each node points to the next. Your program can follow the pointers forever.

Consider the following program "A circular list that uses infinite indirection".

``````/* Would run forever if you didn't limit it to MAX */
#include <stdio.h>
struct circ_list
{
char    value[ 3 ];     /* e.g., "st" (incl '\0') */
struct circ_list        *next;
};
struct circ_list    suffixes[] = {
"th", & suffixes[ 1 ], /* 0th */
"st", & suffixes[ 2 ], /* 1st */
"nd", & suffixes[ 3 ], /* 2nd */
"rd", & suffixes[ 4 ], /* 3rd */
"th", & suffixes[ 5 ], /* 4th */
"th", & suffixes[ 6 ], /* 5th */
"th", & suffixes[ 7 ], /* 6th */
"th", & suffixes[ 8 ], /* 7th */
"th", & suffixes[ 9 ], /* 8th */
"th", & suffixes[ 0 ], /* 9th */
};
#define MAX 20
int main()
{
int i = 0;
struct circ_list    *p = suffixes;
while (i <= MAX)
{
printf( "%d%s\n", i, p->value );
++i;
p = p->next;
}
return 0;
}
``````

Each element in suffixes has one suffix (two characters plus the terminating NUL character) and a pointer to the next element. next is a pointer to something that has a pointer, to something that has a pointer, ad infinitum.

The example is dumb because the number of elements in suffixes is fixed. It would be simpler to have an array of suffixes and to use the i%10'th element. In general, circular lists can grow and shrink.

• 7.

What is indirection?

If you declare a variable, its name is a direct reference to its value. If you have a pointer to a variable, or any other object in memory, you have an indirect reference to its value. If p is a pointer, the value of p is the address of the object. *p means "apply the indirection operator to p"; its value is the value of the object that p points to. (Some people would read it as "Go indirect on p.")

*p is an lvalue; like a variable, it can go on the left side of an assignment operator, to change the value. If pis a pointer to a constant, *p is not a modifiable lvalue; it can't go on the left side of an assignment.

Consider the following program. It shows that when p points to i*p can appear wherever i can.

``````#include <stdio.h>
int main()
{
int i;
int *p;
i = 5;
p = & i;    /* now *p == i */
printf("i=%d, p=%P, *p=%d\n", i, p, *p);
*p = 6;     /* same as i = 6 */
printf("i=%d, p=%P, *p=%d\n", i, p, *p);
return 0;
}
``````

After p points to i (p = &i), you can print i or *p and get the same thing. You can even assign to *p, and the result is the same as if you had assigned to i.

• 8.

How do you print only part of a string?

The following program shows how to print only part of a string using the printf() function:

``````#include <stdio.h>
#include <string.h>
void main(void);
void main(void)
{
char* source_str = "THIS IS THE SOURCE STRING";
/* Use printf() to print the first 11 characters of source_str. */
printf("First 11 characters: '%11.11s'\n", source_str);
/* Use printf() to print only the
last 13 characters of source_str. */
printf("Last 13 characters: '%13.13s'\n",
source_str + (strlen(source_str) - 13));
}
``````

This example program produces the following output:

First 11 characters: 'THIS IS THE'

Last 13 characters: 'SOURCE STRING'

The first call to printf() uses the argument "%11.11s" to force the printf() function to make the output exactly 11 characters long. Because the source string is longer than 11 characters, it is truncated, and only the first 11 characters are printed. The second call to printf() is a bit more tricky. The total length of thesource_str string is calculated (using the strlen() function). Then, 13 (the number of characters you want to print) is subtracted from the total length of source_str.

This gives the number of remaining characters in source_str. This number is then added to the address of source_str to give a pointer to an address in the source string that is 13 characters from the end of source_str. By using the argument "%13.13s", the program forces the output to be exactly 13 characters long, and thus the last 13 characters of the string are printed.

• 9.

How can you tell whether two strings are the same?

The standard C library provides several functions to compare two strings to see whether they are the same. One of these functions, strcmp(), is used here to show how this task is accomplished:

``````#include <stdio.h>
#include <string.h>
void main(void);
void main(void)
{
char* str_1 = "abc";
char* str_2 = "abc";
char* str_3 = "ABC";
if (strcmp(str_1, str_2) == 0)
printf("str_1 is equal to str_2.\n");
else
printf("str_1 is not equal to str_2.\n");
if (strcmp(str_1, str_3) == 0)
printf("str_1 is equal to str_3.\n");
else
printf("str_1 is not equal to str_3.\n");
}
``````

This program produces the following output:

str_1 is equal to str_2.

str_1 is not equal to str_3.

Notice that the strcmp() function is passed two arguments that correspond to the two strings you want to compare. It performs a case-sensitive lexicographic comparison of the two strings and returns one of the following values:

Return Value   Meaning
<0 - The first string is less than the second string.
0 - The two strings are equal.
>0 - The first string is greater than the second string.

In the preceding example code, strcmp() returns 0 when comparing str_1 (which is "abc") and str_2 (which is "abc"). However, when comparing str_1 (which is "abc") with str_3 (which is "ABC"), strcmp() returns a value greater than 0, because the string "ABC" is greater than (in ASCII order) the string "abc".

Many variations of the strcmp() function perform the same basic function (comparing two strings), but with slight differences. The following table lists some of the functions available that are similar to strcmp():

Function Name   Description
strcmp() - Case-sensitive comparison of two strings
strcmpi() - Case-insensitive comparison of two strings
stricmp() - Same as strcmpi()
strncmp() - Case-sensitive comparison of a portion of two strings
strnicmp() - Case-insensitive comparison of a portion of two strings

Looking at the example provided previously, if you were to replace the call to strcmp() with a call tostrcmpi() (a case-insensitive version of strcmp()), the two strings "abc" and "ABC" would be reported as being equal.

• 10.

How can I convert a string to a number?

The standard C library provides several functions for converting strings to numbers of all formats (integers, longs, floats, and so on) and vice versa. One of these functions, atoi(), is used here to illustrate how a string is converted to an integer:

``````#include <stdio.h>
#include <stdlib.h>
void main(void);
{
int num;
char* str = "100";
num = atoi(str);
printf("The string 'str' is %s and the number 'num' is %d.\n",
str, num);
}
``````

To use the atoi() function, you simply pass it the string containing the number you want to convert. The return value from the atoi() function is the converted integer value.

The following functions can be used to convert strings to numbers:

Function Name   Purpose
atof() - Converts a string to a double-precision floating-point value.
atoi() - Converts a string to an integer.
atol() - Converts a string to a long integer.
strtod() - Converts a string to a double-precision floating-point value and reports any "leftover" numbers that could not be converted.
strtol() - Converts a string to a long integer and reports any "leftover" numbers that could not be converted.
strtoul() - Converts a string to an unsigned long integer and reports any "leftover" numbers that could not be converted.

Sometimes, you might want to trap overflow errors that can occur when converting a string to a number that results in an overflow condition. The following program shows an example of the strtoul() function, which traps this overflow condition:

``````#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
void main(void);
void main(void)
{
char* str  = "1234567891011121314151617181920";
unsigned long num;
char* leftover;
num = strtoul(str, &leftover, 10);
printf("Original string:      %s\n", str);
printf("Converted number:     %lu\n", num);
printf("Leftover characters:  %s\n", leftover);
}
``````

In this example, the string to be converted is much too large to fit into an unsigned long integer variable. The strtoul() function therefore returns ULONG_MAX (4294967295) and sets the char* leftover to point to the character in the string that caused it to overflow. It also sets the global variable errno to ERANGE to notify the caller of the function that an overflow condition has occurred. The strtod() and strtol() functions work exactly the same way as the strtoul() function shown above. Refer to your C compiler documentation for more information regarding the syntax of these functions.

• 11.

How can I convert a number to a string?

The standard C library provides several functions for converting numbers of all formats (integers, longs, floats, and so on) to strings and vice versa. One of these functions, itoa(), is used here to illustrate how an integer is converted to a string:

``````#include <stdio.h>
#include <stdlib.h>
void main(void);
void main(void)
{
int num = 100;
char str[25];
itoa(num, str, 10);
printf("The number 'num' is %d and the string 'str' is %s.\n",
num, str);
}
``````

Notice that the itoa() function takes three arguments: the first argument is the number you want to convert to the string, the second is the destination string to put the converted number into, and the third is the base, or radix, to be used when converting the number. The preceding example uses the common base 10 to convert the number to the string.

The following functions can be used to convert integers to strings:

Function Name   Purpose
itoa() - Converts an integer value to a string.
ltoa() - Converts a long integer value to a string.
ultoa() - Converts an unsigned long integer value to a string.

Note that the itoa()ltoa(), and ultoa() functions are not ANSI compatible. An alternative way to convert an integer to a string (that is ANSI compatible) is to use the sprintf() function, as in the following example:

``````#include <stdio.h>
#include <stdlib.h>
void main(void);
void main(void)
{
int num = 100;
char str[25];
sprintf(str, "%d", num);
printf("The number 'num' is %d and the string 'str' is %s.\n",
num, str);
}
``````

When floating-point numbers are being converted, a different set of functions must be used. Here is an example of a program that uses the standard C library function fcvt() to convert a floating-point value to a string:

``````#include <stdio.h>
#include <stdlib.h>
void main(void);
void main(void)
{
double num = 12345.678;
char* str;
int dec_pl, sign, ndigits = 3;    /* Keep 3 digits of precision. */
str = fcvt(num, ndigits, &dec_pl, &sign);  /* Convert the float
to a string. */
printf("Original number:  %f\n", num);     /* Print the original
floating-point
value. */
printf("Converted string: %s\n", str);     /* Print the converted
string's value */
printf("Decimal place:    %d\n", dec_pl);  /* Print the location of
the decimal point. */
printf("Sign:             %d\n", sign);    /* Print the sign.
0 = positive,
1 = negative. */
}
``````

Notice that the fcvt() function is quite different from the itoa() function used previously. The fcvt()function takes four arguments. The first argument is the floating-point value you want to convert. The second argument is the number of digits to be stored to the right of the decimal point. The third argument is a pointer to an integer that is used to return the position of the decimal point in the converted string. The fourth argument is a pointer to an integer that is used to return the sign of the converted number (0 is positive, 1 is negative).

Note that the converted string does not contain the actual decimal point. Instead, the fcvt() returns the position of the decimal point as it would have been if it were in the string. In the preceding example, the dec_pl integer variable contains the number 5 because the decimal point is located after the fifth digit in the resulting string. If you wanted the resulting string to include the decimal point, you could use the gcvt()function  (described in the following table).

The following functions can be used to convert floating-point values to strings:

Function   Purpose
ecvt() - Converts a double-precision floating-point value to a string without an embedded decimal point.
fcvt() - Same as ecvt(), but forces the precision to a specified number of digits.
gcvt() - Converts a double-precision floating-point value to a string with an embedded decimal point.
• 12.

How can I copy just a portion of a string?

You can use the standard C library function strncpy() to copy one portion of a string into another string. The strncpy() function takes three arguments: the first argument is the destination string, the second argument is the source string, and the third argument is an integer representing the number of characters you want to copy from the source string to the destination string. For example, consider the following program, which uses the strncpy() function to copy portions of one string to another:

``````#include <stdio.h>
#include <string.h>
void main(void);
void main(void)
{
char* source_str = "THIS IS THE SOURCE STRING";
char dest_str1[40] = {0}, dest_str2[40] = {0};
/* Use strncpy() to copy only the first 11 characters. */
strncpy(dest_str1, source_str, 11);
printf("How about that! dest_str1 is now: '%s'!!!\n", dest_str1);
/* Now, use strncpy() to copy only the last 13 characters. */
strncpy(dest_str2, source_str + (strlen(source_str) - 13), 13);
printf("Whoa! dest_str2 is now: '%s'!!!\n", dest_str2);
}
``````

The first call to strncpy() in this example program copies the first 11 characters of the source string intodest_str1. This example is fairly straightforward, one you might use often. The second call is a bit more complicated and deserves some explanation. In the second argument to the strncpy() function call, the total length of the source_str string is calculated (using the strlen() function). Then, 13 (the number of characters you want to print) is subtracted from the total length of source_str. This gives the number of remaining characters in source_str. This number is then added to the address of source_str to give a pointer to an address in the source string that is 13 characters from the end of source_str.

Then, for the last argument, the number 13 is specified to denote that 13 characters are to be copied out of the string. The combination of these three arguments in the second call to strncpy() sets dest_str2 equal to the last 13 characters of source_str.

The example program prints the following output:

``````How about that! dest_str1 is now: 'THIS IS THE'!!!
Whoa! dest_str2 is now: 'SOURCE STRING'!!!
``````

Notice that before source_str was copied to dest_str1 and dest_st2dest_str1 and dest_str2 had to be initialized to null characters (\0). This is because the strncpy() function does not automatically append a null character to the string you are copying to. Therefore, you must ensure that you have put the null character after the string you have copied, or else you might wind up with garbage being printed.

• 13.

How can I pad a string to a known length?

Padding strings to a fixed length can be handy when you are printing fixed-length data such as tables or spreadsheets. You can easily perform this task using the printf() function. The following example program shows how to accomplish this task:

``````#include <stdio.h>
char *data[25] = {
"REGION", "--Q1--",    "--Q2--",   "--Q3--", "  --Q4--",
"North", "10090.50", "12200.10", "26653.12", "62634.32",
"South", "21662.37", "95843.23", "23788.23", "48279.28",
"East", "23889.38", "23789.05", "89432.84", "29874.48",
"West", "85933.82", "74373.23", "78457.23", "28799.84" };
void main(void);
void main(void)
{
int x;
for (x=0; x<25; x++)
{
if ((x % 5) == 0 && (x != 0))
printf("\n");
printf("%-10.10s", data[x]);
}
}
``````

In this example, a character array (char* data[]) is filled with this year's sales data for four regions. Of course, you would want to print this data in an orderly fashion, not just print one figure after the other with no formatting. This being the case, the following statement is used to print the data:

printf("%-10.10s", data[x]);

The "%-10.10s" argument tells the printf() function that you are printing a string and you want to force it to be 10 characters long. By default, the string is right-justified, but by including the minus sign (-) before the first 10, you tell the printf() function to left-justify your string. This action forces the printf() function to pad the string with spaces to make it 10 characters long. The result is a clean, formatted spreadsheet-like

output:

``````REGION      --Q1--   --Q2--     --Q3--    --Q4--
North      10090.50  12200.10  26653.12  62634.32
South      21662.37  95843.23  23788.23  48279.28
East       23889.38  23789.05  89432.84  29874.48
West       85933.82  74373.23  78457.23  28799.84``````
• 14.

How can I right-justify a string?

Even though the C language does not provide a standard function that right-justifies a string, you can easily build your own function to perform this action. Using the rtrim() function, you can create your own function to take a string and right-justify it. Here is how this task is accomplished:

``````#include <stdio.h>
#include <string.h>
#include <malloc.h>
void main(void);
char* rjust(char*);
char* rtrim(char*);
void main(void)
{
char* rjust_str = "This string is not right-justified.                  ";
/* Show the status of the string before calling the rjust()
function. */
printf("Before calling rjust(), rjust_str is '%s'\n.", rjust_str);
/* Call the rjust() function to right-justify this string. */
rjust(rjust_str);
/* Show the status of the string
after calling the rjust() function. */
printf("After calling rjust(), rjust_str is '%s'\n.", rjust_str);
}
/* The rjust() function right-justifies a string. */
char* rjust(char* str)
{
int n = strlen(str);   /* Save the original length of the string. */
char* dup_str;
dup_str = strdup(str);  /* Make an exact duplicate of the string. */
rtrim(dup_str);         /* Trim off the trailing spaces. */
/* Call sprintf() to do a virtual "printf" back into the original
string. By passing sprintf() the length of the original string,
we force the output to be the same size as the original, and by
default the sprintf() right-justifies the output. The sprintf()
function fills the beginning of the string with spaces to make
it the same size as the original string. */
sprintf(str, "%*.*s", n, n, dup_str);
free(dup_str);    /* Free the memory taken by
the duplicated string. */
return str;       /* Return a pointer to the string. */
}
/* The rtrim() function removes trailing spaces from a string. */
char* rtrim(char* str)
{
int n = strlen(str) - 1;  /* Start at the character BEFORE the null
character (\0). */
while (n>0)            /* Make sure we don't go out of bounds... */
{
if (*(str+n) != ' ')    /* If we find a nonspace character: */
{
*(str+n+1) = '\0'; /* Put the null character at one
character past our current
position. */
break;             /* Break out of the loop. */
}
else      /* Otherwise, keep moving backward in the string. */
n--;
}
return str;                   /* Return a pointer to the string. */
}
``````

The rjust() function first saves the length of the original string in a variable named n. This step is needed because the output string must be the same length as the input string. Next, the rjust() function calls the standard C library function named strdup() to create a duplicate of the original string. A duplicate of the string is required because the original version of the string is going to be overwritten with a right-justified version. After the duplicate string is created, a call to the rtrim() function is invoked (using the duplicate string, not the original), which eliminates all trailing spaces from the duplicate string.

Next, the standard C library function sprintf() is called to rewrite the new string to its original place in memory. The sprintf() function is passed the original length of the string (stored in n), thereby forcing the output string to be the same length as the original. Because sprintf() by default right-justifies string output, the output string is filled with leading spaces to make it the same size as the original string. This has the effect of right-justifying the input string. Finally, because the strdup() function dynamically allocates memory, the free() function is called to free up the memory taken by the duplicate string.

• 15.

How can I remove the leading spaces from a string?

The C language does not provide a standard function that removes leading spaces from a string. It is easy, however, to build your own function to do just this. you can easily construct a custom function that uses the rtrim() function in conjunction with the standard C library function strrev() to remove the leading spaces from a string. Look at how this task is performed:

``````#include <stdio.h>
#include <string.h>
void main(void);
char* ltrim(char*);
char* rtrim(char*);
void main(void)
{
/* Show the status of the string before calling the ltrim()
function. */
printf("and has a length of %d.\n", strlen(lead_str));
/* Call the ltrim() function to remove the leading blanks. */
/* Show the status of the string
after calling the ltrim() function. */
printf("and has a length of %d.\n", strlen(lead_str));
}
/* The ltrim() function removes leading spaces from a string. */
char* ltrim(char* str)
{
strrev(str);    /* Call strrev() to reverse the string. */
rtrim(str);     /* Call rtrim() to remove the "trailing" spaces. */
strrev(str);    /* Restore the string's original order. */
return str;     /* Return a pointer to the string. */
}
/* The rtrim() function removes trailing spaces from a string. */
char* rtrim(char* str)
{
int n = strlen(str) - 1;     /* Start at the character BEFORE
the null character (\0). */
while (n>0)            /* Make sure we don't go out of bounds... */
{
if (*(str+n) != ' ')    /* If we find a nonspace character: */
{
*(str+n+1) = '\0'; /* Put the null character at one
character past our current
position. */
break;             /* Break out of the loop. */
}
else      /* Otherwise, keep moving backward in the string. */
n--;
}
return str;                  /* Return a pointer to the string. */
}
``````

Notice that the ltrim() function performs the following tasks: First, it calls the standard C library functionstrrev(), which reverses the string that is passed to it. This action puts the original string in reverse order, thereby creating "trailing spaces" rather than leading spaces. Now, the rtrim() function is used to remove the "trailing spaces" from the string. After this task is done, the strrev() function is called again to "reverse" the string, thereby putting it back in its original order.

• 16.

How can I remove the trailing spaces from a string?

The C language does not provide a standard function that removes trailing spaces from a string. It is easy, however, to build your own function to do just this. The following program uses a custom function namedrtrim() to remove the trailing spaces from a string. It carries out this action by iterating through the string backward, starting at the character before the terminating null character (\0) and ending when it finds the first nonspace character. When the program finds a nonspace character, it sets the next character in the string to the terminating null character (\0), thereby effectively eliminating all the trailing blanks. Here is how this task is performed:

``````#include <stdio.h>
#include <string.h>
void main(void);
char* rtrim(char*);
void main(void)
{
char* trail_str = "This string has trailing spaces in it.               ";
/* Show the status of the string before calling the rtrim()
function. */
printf("Before calling rtrim(), trail_str is '%s'\n", trail_str);
printf("and has a length of %d.\n", strlen(trail_str));
/* Call the rtrim() function to remove the trailing blanks. */
rtrim(trail_str);
/* Show the status of the string
after calling the rtrim() function. */
printf("After calling rtrim(), trail_str is '%s'\n", trail_str);
printf("and has a length of %d.\n", strlen(trail_str));
}
/* The rtrim() function removes trailing spaces from a string. */
char* rtrim(char* str)
{
int n = strlen(str) - 1;     /* Start at the character BEFORE
the null character (\0). */
while (n>0)            /* Make sure we don't go out of bounds... */
{
if (*(str+n) != ' ')    /*  If we find a nonspace character: */
{
*(str+n+1) = '\0'; /* Put the null character at one
character past our current
position. */
break;             /* Break out of the loop. */
}
else      /* Otherwise, keep moving backward in the string. */
n--;
}
return str;                  /* Return a pointer to the string. */
}
``````

Notice that the rtrim() function works because in C, strings are terminated by the null character. With the insertion of a null character after the last nonspace character, the string is considered terminated at that point, and all characters beyond the null character are ignored.

• 17.

What is the difference between a string copy (strcpy) and a memory copy (memcpy)? When should each be used?

The strcpy() function is designed to work exclusively with strings. It copies each byte of the source string to the destination string and stops when the terminating null character (\0) has been moved. On the other hand, the memcpy() function is designed to work with any type of data.

Because not all data ends with a null character, you must provide the memcpy() function with the number of bytes you want to copy from the source to the destination. The following program shows examples of both the strcpy() and the memcpy() functions:

``````#include <stdio.h>
#include <string.h>
typedef struct cust_str {
int  id;
char last_name[20];
char first_name[15];
} CUSTREC;
void main(void);
void main(void)
{
char*   src_string = "This is the source string";
char    dest_string[50];
CUSTREC src_cust;
CUSTREC dest_cust;
printf("Hello!  I'm going to copy src_string into dest_string!\n");
/* Copy src_string into dest_string. Notice that the destination
string is the first argument. Notice also that the strcpy()
function returns a pointer to the destination string. */
printf("Done! dest_string is: %s\n",
strcpy(dest_string, src_string));
printf("Encore! Let's copy one CUSTREC to another.\n");
printf("I'll copy src_cust into dest_cust.\n");
/* First, initialize the src_cust data members. */
src_cust.id = 1;
strcpy(src_cust.last_name, "Strahan");
strcpy(src_cust.first_name, "Troy");
/* Now, use the memcpy() function to copy the src_cust structure to
the dest_cust structure. Notice that, just as with strcpy(), the
destination comes first. */
memcpy(&dest_cust, &src_cust, sizeof(CUSTREC));
printf("Done! I just copied customer number #%d (%s %s).",
dest_cust.id, dest_cust.first_name, dest_cust.last_name);
}
``````

When dealing with strings, you generally should use the strcpy() function, because it is easier to use with strings. When dealing with abstract data other than strings (such as structures), you should use the memcpy() function.

• 18.

Is using exit() the same as using return?

No. The exit() function is used to exit your program and return control to the operating system. The return statement is used to return from a function and return control to the calling function. If you issue a return from the main() function, you are essentially returning control to the calling function, which is the operating system. In this case, the return statement and exit() function are similar. Here is an example of a program that uses the exit() function and return statement:

``````#include <stdio.h>
#include <stdlib.h>
int main(int, char**);
int do_processing(void);
int do_something_daring();
int main(int argc, char** argv)
{
int ret_code;
if (argc < 3)
{
printf("Wrong number of arguments used!\n");
/* return 1 to the operating system */
exit(1);
}
ret_code = do_processing();
...
/* return 0 to the operating system */
exit(0);
}
int do_processing(void)
{
int rc;
rc = do_something_daring();
if (rc == ERROR)
{
printf("Something fishy is going on around here..."\n);
/* return rc to the operating system */
exit(rc);
}
/* return 0 to the calling function */
return 0;
}
``````

In the main() function, the program is exited if the argument count (argc) is less than 3. The statementexit(1); tells the program to exit and return the number 1 to the operating system. The operating system can then decide what to do based on the return value of the program. For instance, many DOS batch files check the environment variable named ERRORLEVEL for the return value of executable programs.

• 19.

What does a function declared as PASCAL do differently?

A C function declared as PASCAL uses a different calling convention than a "regular" C function. Normally, C function parameters are passed right to left; with the PASCAL calling convention, the parameters are passed left to right.

Consider the following function, which is declared normally in a C program:

int regular_func(int, char*, long);

Using the standard C calling convention, the parameters are pushed on the stack from right to left. This means that when the regular_func() function is called in C, the stack will contain the following parameters:

long

char*

int

The function calling regular_func() is responsible for restoring the stack when regular_func() returns.

When the PASCAL calling convention is being used, the parameters are pushed on the stack from left to right.

Consider the following function, which is declared as using the PASCAL calling convention:

int PASCAL pascal_func(int, char*, long);

When the function pascal_func() is called in C, the stack will contain the following parameters:

int

char*

long

The function being called is responsible for restoring the stack pointer. Why does this matter? Is there any benefit to using PASCAL functions?

Functions that use the PASCAL calling convention are more efficient than regular C functions—the function calls tend to be slightly faster. Microsoft Windows is an example of an operating environment that uses the PASCAL calling convention. The Windows SDK (Software Development Kit) contains hundreds of functions declared as PASCAL.

When Windows was first designed and written in the late 1980s, using the PASCAL modifier tended to make a noticeable difference in program execution speed. In today's world of fast machinery, the PASCAL modifier is much less of a catalyst when it comes to the speed of your programs. In fact, Microsoft has abandoned the PASCAL calling convention style for the Windows NT operating system.

In your world of programming, if milliseconds make a big difference in your programs, you might want to use the PASCAL modifier when declaring your functions. Most of the time, however, the difference in speed is hardly noticeable, and you would do just fine to use C's regular calling convention.

• 20.

Is it possible to execute code even after the program exits the main() function?

The standard C library provides a function named atexit() that can be used to perform "cleanup" operations when your program terminates. You can set up a set of functions you want to perform automatically when your program exits by passing function pointers to the atexit() function. Here's an example of a program that uses the atexit() function:

``````#include <stdio.h>
#include <stdlib.h>
void close_files(void);
void print_registration_message(void);
int main(int, char**);
int main(int argc, char** argv)
{
...
atexit(print_registration_message);
atexit(close_files);
while (rec_count < max_records)
{
process_one_record();
}
exit(0);
}
``````

This example program uses the atexit() function to signify that the close_files() function and theprint_registration_message() function need to be called automatically when the program exits. When the main() function ends, these two functions will be called to close the files and print the registration message. There are two things that should be noted regarding the atexit() function. First, the functions you specify to execute at program termination must be declared as void functions that take no parameters. Second, the functions you designate with the atexit() function are stacked in the order in which they are called with atexit(), and therefore they are executed in a last-in, first-out (LIFO) method. Keep this information in mind when using the atexit() function. In the preceding example, the atexit() function is stacked as shown here:

atexit(print_registration_message);

atexit(close_files);

Because the LIFO method is used, the close_files() function will be called first, and then theprint_registration_message() function will be called.

The atexit() function can come in handy when you want to ensure that certain functions (such as closing your program's data files) are performed before your program terminates.