1. Why should I use standard library functions instead of writing my own?
The standard library functions have three advantages: they work, they're efficient, and they're portable. They work: Your compiler vendor probably got them right. More important, the vendor is likely to have done a thorough test to prove they're right, more thorough than you probably have time for. (There are expensive test suites to make that job easier.)
They're efficient: Good C programmers use the standard library functions a lot, and good compiler vendors know that. There's a competitive advantage for the vendor to provide a good implementation. When competing compilers are compared for efficiency, a good compiler implementation can make all the difference. The vendor has more motivation than you do, and probably more time, to produce a fast implementation.
They're portable: In a world where software requirements change hourly, the standard library functions do the same thing, and mean the same thing, for every compiler, on every computer. They're one of the few things you, as a C programmer, can count on.
The funny thing is, one of the most standard pieces of information about the standard library is hard to find. For every function, there's one header file (or, rarely, two) that guarantees to give you that function's prototype. (You should always include the prototype for every function you call;) What's funny? That header file might not be the file that actually contains the prototype. In some (sad!) cases, it's not even the header file recommended by the compiler manual. The same is true for macros, typedefs, and global variables.
2. What header files do I need in order to define the standard library functions I use?
The funny thing is, these are not necessarily the files that define what you're looking for. Your compiler guarantees that (for example) if you want the EDOM macro, you can get it by including <errno.h>. EDOM might be defined in <errno.h>, or <errno.h> might just include something that defines it. Worse, the next version of your compiler might define EDOM somewhere else.
Don't look in the files for the definition and use that file. Use the file that's supposed to define the symbol you want. It'll work.
A few names are defined in multiple files: NULL, size_t, and wchar_t. If you need a definition for one of these names, use a file you need to include anyway, or pick one arbitrarily. (<stddef.h> is a reasonable choice; it's small, and it defines common macros and types.)
Standard library functions header files.
Function/Macro | Header File | |
---|---|---|
abort | - | stdlib.h |
abs | - | stdlib.h |
acos | - | math.h |
asctime | - | time.h |
asin | - | math.h |
assert | - | assert.h |
atan | - | math.h |
atan2 | - | math.h |
atexit | - | stdlib.h |
atof | - | stdlib.h |
atoi | - | stdlib.h |
atol | - | stdlib.h |
bsearch | - | stdlib.h |
BUFSIZ | - | stdlib.h |
calloc | - | stdlib.h |
ceil | - | math.h |
clearerr | - | stdio.h |
clock | - | time.h |
CLOCKS_PER_SEC | - | time.h |
clock_t | - | time.h |
cos | - | math.h |
cosh | - | math.h |
ctime | - | time.h |
difftime | - | time.h |
div | - | stdlib.h |
div_t | - | stdlib.h |
EDOM | - | errno.h |
EOF | - | stdio.h |
ERANGE | - | errno.h |
errno | - | errno.h |
exit | - | stdlib.h |
EXIT_FAILURE | - | stdlib.h |
EXIT_SUCCESS | - | stdlib.h |
exp | - | math.h |
fabs | - | math.h |
fclose | - | stdio.h |
feof | - | stdio.h |
ferror | - | stdio.h |
fflush | - | stdio.h |
fgetc | - | stdio.h |
fgetpos | - | stdio.h |
fgets | - | stdio.h |
FILE | - | stdio.h |
FILENAME_MAX | - | stdio.h |
floor | - | math.h |
fmod | - | math.h |
fopen | - | stdio.h |
FOPEN_MAX | - | stdio.h |
fpos_t | - | stdio.h |
fprintf | - | stdio.h |
fputc | - | stdio.h |
fputs | - | stdio.h |
fread | - | stdio.h |
freopen | - | stdio.h |
frexp | - | math.h |
fscanf | - | stdio.h |
fseek | - | stdio.h |
fsetpos | - | stdio.h |
ftell | - | stdio.h |
fwrite | - | stdio.h |
getc | - | stdio.h |
getchar | - | stdio.h |
getenv | - | stdlib.h |
gets | - | stdio.h |
gmtime | - | time.h |
HUGE_VAL | - | math.h |
_IOFBF | - | stdio.h |
_IOLBF | - | stdio.h |
_IONBF | - | stdio.h |
isalnum | - | ctype.h |
isalpha | - | ctype.h |
iscntrl | - | ctype.h |
isdigit | - | ctype.h |
isgraph | - | ctype.h |
islower | - | ctype.h |
isprint | - | ctype.h |
ispunct | - | ctype.h |
isspace | - | ctype.h |
isupper | - | ctype.h |
isxdigit | - | ctype.h |
jmp_buf | - | setjmp.h |
labs | - | stdlib.h |
LC_ALL | - | locale.h |
LC_COLLATE | - | locale.h |
LC_CTYPE | - | locale.h |
LC_MONETARY | - | locale.h |
LC_NUMERIC | - | locale.h |
LC_TIME | - | locale.h |
struct lconv | - | locale.h |
ldexp | - | math.h |
ldiv | - | stdlib.h |
ldiv_t | - | stdlib.h |
localeconv | - | locale.h |
localtime | - | time.h |
log | - | math.h |
log10 | - | math.h |
longjmp | - | setjmp.h |
L_tmpnam | - | stdio.h |
malloc | - | stdlib.h |
mblen | - | stdlib.h |
mbstowcs | - | stdlib.h |
mbtowc | - | stdlib.h |
MB_CUR_MAX | - | stdlib.h |
memchr | - | string.h |
memcmp | - | string.h |
memcpy | - | string.h |
memmove | - | string.h |
memset | - | string.h |
mktime | - | time.h |
modf | - | math.h |
NDEBUG | - | assert.h |
NULL | - | locale.h, stddef.h, stdio.h, stdlib.h, string.h, time.h |
offsetof | - | stddef.h |
perror | - | stdio.h |
pow | - | math.h |
printf | - | stdio.h |
ptrdiff_t | - | stddef.h |
putc | - | stdio.h |
putchar | - | stdio.h |
puts | - | stdio.h |
qsort | - | stdlib.h |
raise | - | signal.h |
rand | - | stdlib.h |
RAND_MAX | - | stdlib.h |
realloc | - | stdlib.h |
remove | - | stdio.h |
rename | - | stdio.h |
rewind | - | stdio.h |
scanf | - | stdio.h |
SEEK_CUR | - | stdio.h |
SEEK_END | - | stdio.h |
SEEK_SET | - | stdio.h |
setbuf | - | stdio.h |
setlocale | - | locale.h |
setvbuf | - | stdio.h |
SIGABRT | - | signal.h |
SIGFPE | - | signal.h |
SIGILL | - | signal.h |
SIGINT | - | signal.h |
signal | - | signal.h |
SIGSEGV | - | signal.h |
SIGTERM | - | signal.h |
sig_atomic_t | - | signal.h |
SIG_DFL | - | signal.h |
SIG_ERR | - | signal.h |
SIG_IGN | - | signal.h |
sin | - | math.h |
sinh | - | math.h |
size_t | - | stddef.h, stdlib.h, string.h, sprintf, stdio.h |
sqrt | - | math.h |
srand | - | stdlib.h |
sscanf | - | stdio.h |
stderr | - | stdio.h |
stdin | - | stdio.h |
stdout | - | stdio.h |
strcat | - | string.h |
strchr | - | string.h |
strcmp | - | string.h |
strcoll | - | string.h |
strcpy | - | string.h |
strcspn | - | string.h |
strerror | - | string.h |
strftime | - | time.h |
strlen | - | string.h |
strncat | - | string.h |
strncmp | - | string.h |
strncpy | - | string.h |
strpbrk | - | string.h |
strrchr | - | string.h |
strspn | - | string.h |
strstr | - | string.h |
strtod | - | stdlib.h |
strtok | - | string.h |
strtol | - | stdlib.h |
strtoul | - | stdlib.h |
strxfrm | - | string.h |
system | - | stdlib.h |
tan | - | math.h |
tanh | - | math.h |
time | - | time.h |
time_t | - | time.h |
struct tm | - | time.h |
tmpfile | - | stdio.h |
tmpnam | - | stdio.h |
TMP_MAX | - | stdio.h |
tolower | - | ctype.h |
toupper | - | ctype.h |
ungetc | - | stdio.h |
va_arg | - | stdarg.h |
va_end | - | stdarg.h |
va_list | - | stdarg.h |
va_start | - | stdarg.h |
vfprintf | - | stdio.h |
vprintf | - | stdio.h |
vsprintf | - | stdio.h |
wchar_t | - | stddef.h, stdlib.h |
wcstombs | - | stdlib.h |
wctomb | - | stdlib.h |
3. How can I write functions that take a variable number of arguments?
Use <stdarg.h>. This defines some macros that let your program deal with variable numbers of arguments.
There's no portable way for a C function, with no constraints on what it might be passed, to know how many arguments it might have gotten or what their types are. If a C function doesn't take a fixed number of arguments (of fixed types), it needs some convention for what the arguments are. For example, the first argument to printf is a string, which indicates what the remaining arguments are:
printf("Hello, world!\n"); /* no more arguments */
printf("%s\n", "Hello, world!"); /* one more string argument */
printf("%s, %s\n", "Hello", "world!"); /* two more string arguments */
printf("%s, %d\n", "Hello", 42); /* one string, one int */
The below program shows a simple printf-like function. The first argument is the format; from the format string, the number and types of the remaining arguments can be determined. As with the real printf, if the format doesn't match the rest of the arguments, the result is undefined. There's no telling what your program will do then (but probably something bad).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
static char * int2str(int n)
{
int minus = (n < 0);
static char buf[32];
char *p = &buf[31];
if (minus)
n = -n;
*p = '\0';
do {
*--p = '0' + n % 10;
n /= 10;
} while (n > 0);
if (minus)
*--p = '-';
return p;
}
/* This is a simple printf-like function that handles only
the format specifiers %%, %s, and %d. */
void simplePrintf(const char *format, ...)
{
va_list ap; /* ap is our argument pointer. */
int i;
char *s;
/* Initialize ap to start with the argument after "format" */
va_start(ap, format);
for ( ; *format; format++)
{
if (*format != '%')
{
putchar(*format);
continue;
}
switch (*++format)
{
case 's':
/* Get next argument (a char*) */
s = va_arg(ap, char *);
fputs(s, stdout);
break;
case 'd':
/* Get next argument (an int) */
i = va_arg(ap, int);
s = int2str(i);
fputs(s, stdout);
break;
case '\0':
format--;
break;
default:
putchar(*format);
break;
}
}
/* Clean up varying arguments before returning */
va_end(ap);
}
void main()
{
simplePrintf("The %s tax rate is %d%%.\n", "sales", 6);
}
4. What is the difference between a free-standing and a hosted environment?
Not all C programmers write database management systems and word processors. Some write code for embedded systems, such as anti-lock braking systems and intelligent toasters. Embedded systems don't necessarily have any sort of file system, or much of an operating system at all. The ANSI/ISO standard calls these "free-standing" systems, and it doesn't require them to provide anything except the language itself. The alternative is a program running on a PC or a mainframe or something in-between; that's a "hosted" environment.
Even people developing for free-standing environments should pay attention to the standard library. For one thing, if a free-standing environment provides some functionality (such as a square root function), it's likely to provide it in a way that's compatible with the standard. (Reinventing the square root is like reinventing the square wheel; what's the point?) Beyond that, embedded programs are often tested on a PC before they're downloaded to a toaster (or whatever). Using the standard functions will increase the amount of code that can be identical in both the test and the real environments.
5. What standard functions are available to manipulate strings?
Short answer: the functions in <string.h>.
C doesn't have a built-in string type. Instead, C programs use char arrays, terminated by the NUL ('\0') character.
C programs (and C programmers) are responsible for ensuring that the arrays are big enough to hold all that will be put in them. There are three approaches:
1. Set aside a lot of room, assume that it will be big enough, and don't worry what happens if it's not big enough (efficient, but this method can cause big problems if there's not enough room).
2. Always allocate and reallocate the necessary amount of room (not too inefficient if done with realloc; this method can take lots of code and lots of runtime).
3. Set aside what should be enough room, and stop before going beyond it (efficient and safe, but you might lose data).
There are two sets of functions for C string programming. One set (strcpy, strcat, and so on) works with the first and second approaches. This set copies or uses as much as it's asked to—and there had better be room for it all, or the program might be buggy. Those are the functions most C programmers use. The other set (strncpy, strncat, and so on) takes the third approach. This set needs to know how much room there is, and it never goes beyond that, ignoring everything that doesn't fit.
The "n" (third) argument means different things to these two functions:
To strncpy, it means there is room for only "n" characters, including any NUL character at the end. strncpy copies exactly "n" characters. If the second argument doesn't have that many, strncpy copies extra NUL characters. If the second argument has more characters than that, strncpy stops before it copies any NUL character. That means, when using strncpy, you should always put a NUL character at the end of the string yourself; don't count on strncpy to do it for you.
To strncat, it means to copy up to "n" characters, plus a NUL character if necessary. Because what you really know is how many characters the destination can store, you usually need to use strlen to calculate how many characters you can copy.
The difference between strncpy and strncat is "historical." (That's a technical term meaning "It made sense to somebody, once, and it might be the right way to do things, but it's not obvious why right now.")
An example of the "string-n" functions.
#include <stdio.h>
#include <string.h>
/*
Normally, a constant like MAXBUF would be very large, to
help ensure that the buffer doesn't overflow. Here, it's very
small, to show how the "string-n" functions prevent it from
ever overflowing.
*/
#define MAXBUF 16
int
main(int argc, char** argv)
{
char buf[MAXBUF];
int i;
buf[MAXBUF - 1] = '\0';
strncpy(buf, argv[0], MAXBUF-1);
for (i = 1; i < argc; ++i) {
strncat(buf, " ",
MAXBUF - 1 - strlen(buf));
strncat(buf, argv[i],
MAXBUF - 1 - strlen(buf));
}
puts(buf);
return 0;
}
strcpy and strncpy copy a string from one array to another. The value on the right is copied to the value on the left; think of the order as being the same as that for assignment.
strcat and strncat "concatenate" one string onto the end of another. For example, if a1 is an array that holds "dog" and a2 is an array that holds "wood", after calling strcat(a1, a2), a1 would hold "dogwood". strcmp and strncmp compare two strings. The return value is negative if the left argument is less than the right, zero if they're the same, and positive if the left argument is greater than the right. There are two common idioms for equality and inequality:
if (strcmp(s1, s2)) {
/* s1 != s2 */
}
and
if (! strcmp(s1, s2)) {
/* s1 == s2 */
}
This code is not incredibly readable, perhaps, but it's perfectly valid C code and quite common; learn to recognize it. If you need to take into account the current locale when comparing strings, use strcoll.
A number of functions search in a string. (In all cases, it's the "left" or first argument being searched in.)strchr and strrchr look for (respectively) the first and last occurrence of a character in a string. (memchr andmemrchr are the closest functions to the "n" equivalents strchr and strrchr.) strspn, strcspn (the "c" stands for "complement"), and strpbrk look for substrings consisting of certain characters or separated by certain characters:
n = strspn("Iowa", "AEIOUaeiou");
/* n = 2; "Iowa" starts with 2 vowels */
n = strcspn("Hello world", " \t");
/* n = 5; white space after 5 characters */
p = strbrk("Hello world", " \t");
/* p points to blank */
strstr looks for one string in another:
p = strstr("Hello world", "or");
/* p points to the second "o" */
strtok breaks a string into tokens, which are separated by characters given in the second argument. strtokis "destructive"; it sticks NUL characters in the original string. (If the original string should be changed, it should be copied, and the copy should be passed to strtok.) Also, strtok is not "reentrant"; it can't be called from a signal-handling function, because it "remembers" some of its arguments between calls. strtok is an odd function, but very useful for pulling apart data separated by commas or white space.
The below program shows a simple program that uses strtok to break up the words in a sentence.
/* An example of using strtok. */
#include <stdio.h>
#include <string.h>
static char buf[] = "Now is the time for all good men ...";
int main()
{
char* p;
p = strtok(buf, " ");
while (p) {
printf("%s\n", p);
p = strtok(NULL, " ");
}
return 0;
}
85 docs|57 tests
|
1. What are standard library functions in C programming? |
2. How can standard library functions be used in C programs? |
3. What are some commonly used standard library functions in C programming? |
4. Can we create our own standard library functions in C? |
5. How can we find the documentation for standard library functions in C? |
|
Explore Courses for Interview Preparation exam
|