Why is the library function needed in c

Day 17





Week 3

As you can see in this book, much of the power of C relies on the C standard library. Today I want to discuss some features that don't fit into the topics of the other lessons. This includes:

  • mathematical functions
  • Functions that deal with time and date information
  • Error handling functions
  • Functions for searching and sorting data

Math functions

The C standard library contains a number of functions that can be used to perform math operations. The prototypes for these functions are in the header file. The mathematical functions all return a value of the type. In the trigonometric functions, the angles are measured in radians instead of degrees - as is also common in mathematics. Remember that one radian (unit of radians) is equal to 57.296 degrees, and a full circle (360 degrees) is made up of 2 radians.1

Trigonometric functions

The trigonometric functions perform calculations as they are required in graphics and engineering programs.

function

prototype

description

Returns the arccosine of the argument. The argument must be in the range. The return value is in the range.

Returns the arcsine of the argument. The argument must be in the range. The return value is in the range.

Returns the arctangent of the argument. The return value is in the range
.

Returns the arctangent of. The return value is in the range.

Returns the cosine of the argument.

Returns the sine of the argument.

Returns the tangent of the argument.

Exponential and logarithmic functions

Exponential and logarithmic functions are needed for certain types of mathematical calculations.

function

prototype

description

Returns the natural exponent of the argument - that is, ex, where e is 2.7182818284590452354.

Returns the natural logarithm of the argument. The argument must be greater than zero.

Returns the logarithm to base 10 of the argument. The argument must be greater than zero.

The function calculates the normalized mantissa for the value x. The return value r of the function is a fraction in the range. The function assigns an integer exponent so that is. When the value is passed to the function, are and.

Returns.

Hyperbolic functions

The hyperbolic functions perform hyperbolic trigonometric calculations.

function

prototype

description

Returns the hyperbolic cosine of the argument.

Returns the hyperbolic sine of the argument.

Returns the hyperbolic tangent of the argument.

Other math functions

The standard library in C also contains various other mathematical functions;

function

prototype

description

Returns the square root of the argument. The argument must be equal to or greater than zero.

Returns the smallest integer that is not smaller than the argument. For example, it delivers and returns. Although it returns an integer value, this is of the type.

Returns the absolute value of the argument.

Returns the largest integer that is not larger than the argument. For example, it delivers and returns.

Separates into an integer and a fraction, both of which have the same sign as. The fraction is returned by the function, the integer part is assigned.

Returns. An error occurs if and is or if and is not an integer.

Returns the floating point of with the same sign as returned. The function returns if is.

An example of the math functions

One could fill an entire book with the programs for the mathematical functions. Listing 17.1 is a simple program that uses several of these functions. Please note that in order to compile this program you have to tell your gcc compiler that you are using mathematical functions which are housed in a separate library. To compile this program, enter the following command:

gcc -Wall -ggdb list1701.c -lm -o list1701

The parameter asks gcc to include a library. In the case of the mathematical library, this is simply called. On Day 20, "Advanced Compilers," we'll take a closer look at the topic of libraries.

Listing 17.1: Mathematical Functions of the C Library.

1: / * Use of the mathematical C functions * /
2:
3: #include
4: #include
5:
6: int main (void)
7: {
8:
9: double x;
10:
11: printf ("Please enter a number:");
12: scanf ("% lf", & x);
13:
14: printf ("\ n \ nOriginal value:% lf", x);
15:
16: printf ("\ nrounded up:% lf", ceil (x));
17: printf ("\ nrounded down:% lf", floor (x));
18: if (x> = 0)
19: printf ("\ nSquare root:% lf", sqrt (x));
20: else
21: printf ("\ nNegative number");
22:
23: printf ("\ ncosine:% lf \ n", cos (x));
24: return (0);
25: }

Enter a number: 100.95

Original value: 100.950000
Rounded up: 101.000000
Rounded off: 100.000000
Square root: 10.047388
Cosine: 0.913482

This listing contains only some of the mathematical functions that are available to you in the C standard library. Line 12 reads in a number from the user, which is output unchanged in line 14. Next, the entered value is passed to four C math functions -,, and. Note that it is only called if the number is not negative, since by definition negative numbers cannot have square roots. You can add any other math functions to this program to check their functionality.

time and date

The C library contains several functions that allow you to query the time in your programs. In C, the term time refers to both the time and the date. The function prototypes and the definition of the structure, which are used by many time functions, are in the header file.

Representation of the time

The time functions of C represent times in two different ways. The first form of representation is simply to represent time as the number of seconds that have elapsed since midnight on January 1, 1970. Negative values ​​represent the time before this date. The time values ​​themselves are stored as type integer values. In the prototypes of the time functions, however, the type identifiers and are used instead, which are defined as in using statements.

In the second form of representation, the time information is broken down into its components (year, month, day, etc.). For this type of representation, the time functions use the structure that is defined in as follows:

struct tm {
int tm_sec; / * Seconds past the full minute - [0.59] * /
int tm_min; / * Minutes past the hour - [0.59] * /
int tm_hour; / * Hours since midnight - [0.23] * /
int tm_mday; / * Day of the month - [1.31] * /
int tm_mon; / * Months since January - [0.11] * /
int tm_year; / * Years since 1900 * /
int tm_wday; / * Days since Sunday - [0.6] * /
int tm_yday; / * Days since January 1st - [0.365] * /
int tm_isdst; / * Flag for daylight saving time * /
};

The time functions

This section describes the various library functions in C that have to do with time. However, always remember that the term time includes both the date and the hours, minutes and seconds. An example program follows the descriptions.

Determine the current time

To get the current time from the internal clock of your system, use the function that is declared as follows:

time_t time (time_t * ptr);

Remember that in is defined as a synonym for. The function returns the number of seconds that have elapsed since midnight on January 1, 1970. If a non - pointer is passed to the function, it stores this value in the variable of the type to which the pointer points. So to store the current time in the variable, you would set up the following code:

time_t now;

now = time (0);

Or you can use the return via the argument:

time_t now;
time_t * zgr_jetzt = & now;
time (zgr_jetzt);

Convert the time representations from one another

Knowing how many seconds have passed since January 1, 1970 is usually not very helpful. For this reason, C provides you with the function with which you can convert a value into a structure. A structure contains the day, month, year, and other time information in a format that is more convenient for output and display. The prototype of this function is:

struct tm * localtime (time_t * ptr);

This function returns a pointer to a static structure variable of the type, so that you do not have to declare a structure variable of the type, but only a pointer to the type. The static structure tag is used and overwritten each time you call. If you want to save the returned value, your program must declare a separate structure variable of the type and copy the values ​​of the static structure variables into this.

The reverse conversion - from a structure variable of the type to a value of the type - is carried out with the help of the function. The prototype is:

time_t mktime (struct tm * ntime);

This function returns the number of seconds that have elapsed between midnight of January 1st, 1970 and the time represented by the structure variable of the type pointed to.

Output times

The functions and are used to convert time information into formatted strings that can be output. Both functions return the time as a string in a special format. The difference between the two functions is that the time is transferred as a value of the type, while the time is received as a structure variable of the type. The prototypes of these functions are:

char * asctime (struct tm * ptr);
char * ctime (time_t * ptr);

Both functions return a pointer to a static, zero-terminated 26-character string that specifies the time of the function argument in the following 24-hour format:

Thu Jun 13 10:22:23 1991

Both functions use a static string that is overwritten each time the function is called.

If you want to change the format of the time, this function is available to you. The time to be formatted is transferred to this function as a structure variable of the type. The formatting takes place using a format string. The prototype of the function is:

size_t strftime (char * s, size_t max, char * fmt, struct tm * ptr);

The function receives the time to be formatted via the structure variable pointed to by the pointer, formats it according to the specification of the format string and writes the result as a zero-terminated string to the memory position pointed to. The argument should specify the size of the space reserved for. If the resulting string (including the terminating null character) contains more than characters, the function returns and the string is invalid. In the other case, the function returns the number of characters written -.

The format string consists of one or more of the conversion specifiers listed in Table 17.1.

The now infamous Year 2000 problem was caused by the fact that programmers chose a two-digit specifier for the year, where - as we now know - a four-digit specifier would have been better. Some of the following format specifiers only output the year with two digits, that is, 1999 becomes 99. Dates after December 31, 1999 can be output as 00 or 100, depending on the implementation. Always be careful when choosing date specifiers

Specifier

What he will be replaced by

Abbreviated weekday name

Full weekday name

Abbreviated month name

Full month name

Date and time display (for example, Tue Apr 18 10:41:50 2000)

Day of the month as a decimal number from 01 to 31

The hour as a decimal number from 00 to 23

The hour as a decimal number from 00 to 11

The day of the year as a decimal number from 001 to 366

The month as a decimal number from 01 to 12

The minute as a decimal number from 00 to 59

AM or PM

The second as a decimal number from 00 to 59

The week of the year as a decimal number from 00 to 53. Sunday is considered the first day of the week

The day of the week as a decimal number from 0 to 6 (Sunday = 0)

The week of the year as a decimal number from 00 to 53. Monday is considered the first day of the week

Date representation (for example, 30-Jun-91)

Time display (for example, 10:41:50)

The year, excluding the century, as a decimal number from 00 to 99

The year, with the century, as a decimal number

The name of the time zone if the information is available or blank if it is not known

A single percent sign%

Table 17.1: Conversion specifiers that can be used with strftime ().

Calculate time differences

You can use the macro to calculate the time difference between two times in seconds. This macro subtracts two values ​​and returns the difference. The prototype is:

double difftime (time_t time1, time_t time0);

This function subtracts from and returns the difference, i.e. the number of seconds between the two times. It is often used to calculate the elapsed time. An example of this is shown in Listing 17.2.

You can use the function to find out a different type of duration. The function indicates how many millionths of a second have passed since the program was started. The prototype of the function is:

clock_t clock (void);

To find out how much time it takes to execute a particular section of the program, you have to call twice - before and after the code block in question - and then subtract the two return values ​​from each other.

Use the time functions

Listing 17.2 shows you how to use the timing functions of the C library.

Listing 17.2: The time functions of the C library.

1: / * Examples for the use of the time functions. * /
2:
3: #include
4: #include
5:
6: int main (void)
7: {
8: time_t start, end, now;
9: struct tm * zgr;
10: char * c, buffer1 [80];
11: double duration;
12:
13: / * Record the time of the program start. * /
14:
15: start = time (0);
16:
17: / * Record the current time. Calls time () on the * /
18: / * second way up. * /
19:
20: time (& now);
21:
22: / * Converts the time_t value into a structure of the type tm. * /
23:
24: zgr = localtime (& now);
25:
26: / * Generates a formatted string with the current * /
27: / * time and spend it. * /
28:
29: c = asctime (zgr);
30: puts (c);
31: getc (stdin);
32:
33: / * Uses the strftime () function to do various * /
34: / * to generate formatted versions of the time. * /
35:
36: strftime (puffer1,80, "This is% U. Week of the year% Y", zgr);
37: puts (buffer1);
38: getc (stdin);
39:
40: strftime (buffer1, 80, "Today is% A,% m /% d /% Y", zgr);
41: puts (buffer1);
42: getc (stdin);
43:
44: strftime (buffer1, 80, "It is% M minutes after% I.", Zgr);
45: puts (buffer1);
46: getc (stdin);
47:
48: / * Reads the current time and calculates the program duration. * /
49:
50: end = time (0);
51: duration = difftime (end, start);
52: printf ("Execution time with time () =% f seconds. \ N", duration);
53:
54: / * Returns the program duration with clock () in hundredths * /
55: / * seconds on. * /
56:
57: printf ("execution time with clock () =% ld hundredths of a second. \ N",
58: clock ());
59: return (0);
60: }

Wed Sep 15 12:21:27 1999

This is week 37 of 1999

Today is Wednesday, 09/15/1999

It's 21 minutes past 12.

Execution time with time () = 11.000000 seconds.
Execution time with clock () = 10000 hundredths of a second.

This program contains a lot of comment lines, which should help you to better understand what was happening. Since we want to use time functions, the header file is included in line 4. Line 8 declares three variables of type -, and. These variables can record time as the number of seconds that have elapsed since January 1, 1970. Line 9 declares a pointer to a structure. The structure has already been described.The types of the remaining variables should be known to you.

The program records its start time in line 15, for which purpose it calls the function. The whole thing is repeated in line 20, but this time the program does not use the value returned by the) function, but transfers a pointer to the variable. Line 24 does exactly what the comment in line 22 says: it converts the value of into a structure variable of the type. The following sections of the program display the value of the current time in different formats on the screen. Line 29 uses the function to assign the information to a character pointer. Line 30 outputs the formatted information. The program then waits for the user to press Enter.

Lines 36 through 46 use the function to output the date in three formats. With the help of Table 17.1 you should be able to find out what is being printed with these lines. You can safely ignore the warnings issued for some of the format specifiers.

The current time is determined again in line 50. This is the time the program ends. Line 51 uses the function to calculate the execution time of the program from the times for program start and end. This value is output in line 52. The program ends with the fact that it calculates the execution time again using the function and outputs it.

Error handling functions

The C standard library contains a number of functions and macros that are useful for handling program errors.

The assert () function

The macro can detect program errors. It is defined in and its prototype is:

void assert (int expression);

The argument can be anything you want to test - a single variable or any C expression. If it is evaluated as, it doesn't matter. If, on the other hand, is evaluated as, outputs an error message and aborts program execution.

How is it used? Most of the time, the macro is used to detect program errors (other than compilation errors). A program error has no influence on the compilation of the program, but leads to incorrect results or undesired behavior of the program (crash, etc.). For example, suppose a financial analysis program you have written occasionally gives incorrect answers, and you suspect that the problem is that the variable is taking negative values ​​- which shouldn't be happening. To check this, place the statement

assert (interest_rate> = 0);

at positions in the program where is used. If the variable ever turns negative, the macro will alert you. You can then take a closer look at the code in question and get to the bottom of the problem.

To see how it works, run Listing 17.3. If you enter a value greater than zero, the program displays the value and ends normally. If you enter a value that is less than or equal to zero, the macro forces the program to terminate. The exact error message you get depends on your compiler, but the following is a typical example:

Assertion failed: x, file list1703.c, line 13

Note that your program must have been compiled in debug mode in order to run properly. Check your compiler manual if you don't know how to enable debug mode (will be explained shortly). If you later compile the last version in release mode, the macros will be deactivated.

Listing 17.3. The assert () macro.

1: / * The macro assert (). * /
2:
3: #include
4: #include
5:
6: int main (void)
7: {
8: int x;
9:
10: printf ("\ nEnter an integer value:");
11: scanf ("% d", & x);
12:
13: assert (x> = 0);
14:
15: printf ("Your entry was% d. \ N \ n", x);
16: return (0);
17: }

Enter an integer value: 10
Your input was 10.
Enter an integer value: -1

list1703: list1703.c: 13: main: Assurance "x> = 0" not fulfilled.
Aborted (core dumped)

Your error message may look slightly different depending on your system and compiler, but in general they are all the same. This example shows you the file name of the C source text file,, and the line number. Note the term "core dumped" in the error message. This means that all of the memory used by your program has been written to a file called, which can then be loaded into a debugger for further investigation.

Run this program and make sure for yourself that the error message printed by on line 13 consists of the failed expression, the name of the file, and the line number of the call.

The work of depends on another macro named (which stands for "do not debug"). If the macro is not defined (the default), is active. Is defined, is deactivated. This is much easier than going through the whole program for the instructions and deleting them (only to find out later that you need them again). To define the macro, use the directive. If you want to convince yourself of the effects, add the instruction

#define NDEBUG

in the second line of Listing 17.3. Now the program outputs the entered values ​​and ends normally even if you enter.

Note that nothing special needs to be defined as long as it is in a directive. You can find out more about the directive on day 20.

The header file errno.h

The header file defines several macros that are used to define and document runtime errors. These macros are used in conjunction with the feature that was first used on Day 15, "Working with Files." At this point we want to deal with it in more detail.

The definitions in contain a global integer variable called. Many library functions in C assign a value to this variable if an error occurs during function execution. The file also defines a set of symbolic constants for these errors, which are listed in Table 17.2.

Surname

value

Message and meaning

Argument list too long (list length exceeds 128 bytes)

Access denied (for example, when trying to write to a file that was opened for read only)

Bad file descriptor

An argument passed to a mathematical function is outside the valid definition range

File exists

Too many open files

File or directory does not exist

Exec format error

Not enough memory (for example, not enough memory to run the function)

Path not found

Result out of range (for example, the result returned by a math function is too large or too small for the data type of the return value)

Table 17.2: The symbolic error constants defined in errno.h.

You can use it in two ways. Some functions use their return value to signal that an error has occurred. In such a case, you can check the value of to determine the nature of the error and act accordingly. Otherwise, that is, if you haven't been told directly that an error has occurred, you can check. If the value is nonzero, there is an error somewhere and the specific value of reflects the nature of the error. You need to remember to go back to zero after fixing the error. The next section is dedicated. Listing 17.4 illustrates the use of and.

The function perror ()

The function is another C tool for error handling. When called, a message is output that describes the last error that occurred during a library function or system call. The prototype that can be found in is:

void perror (char * msg);

The argument points to an optional, user-defined message. This message is output first, followed by a colon and the implementation-related message that describes the last error. If you invoke and there was no error, the message says “Success2

A call to is not yet a measure for error handling. It is up to the program to take action - for example to request the user to end the program or to query the value of and to react specifically depending on the type of error. Note that a program does not have to include the header file in order to use the global variable. The header file is only required if your program uses the symbolic error constants from Table 17.2. Listing 17.4 illustrates the use of and to handle run-time errors.

Listing 17.4. Handling runtime errors with perror () and errno.

1: / * Example of error handling with perror () and errno. * /
2:
3: #include
4: #include
5: #include
6:
7: int main (void)
8: {
9: FILE * fp;
10: char filename [80];
11:
12: printf ("Enter a filename:");
13: fgets (filename, 80, stdin);
14: filename [strlen (filename) -1] = 0;
15:
16: if ((fp = fopen (filename, "r")) == NULL)
17: {
18: perror ("You messed up");
19: printf ("errno =% d. \ N", errno);
20: exit (1);
21: }
22: else
23: {
24: puts ("File opened for reading.");
25: fclose (fp);
26: }
27: return (0);
28: }

Enter a file name: list1704.c
File opened for reading.

Enter a file name: nonefile.xxx
You messed up !: File or directory not found
errno = 2.

This program outputs one of two messages, depending on whether a file could be opened for reading or not. Line 16 tries to open a file. If the file opens without any problems, the -part of the -loop is executed and the following message is output:

File opened for reading.

If an error occurs while opening the file, for example because the file does not exist, lines 18 to 20 of the loop are executed. Line 18 calls the function with the string "". Then the error number is output. The result looks like this:

You messed up !: File or directory not found
errno = 2

What you should do

What not

Include the header file if you want to use the symbolic error codes from Table 17.2.

Check your programs for possible errors. Never assume that everything is flawless.

Do not include the header file if you do not want to use the symbolic error codes from Table 17.2.

Functions with a variable number of arguments

You have already seen several library functions, such as and, that take any number of arguments. You can also write your own functions that take any length of argument list. Programs that contain functions with arbitrarily long argument lists must include the header file.

When you declare a function that takes a list of arguments of any length, you specify the fixed parameters first - those are the ones that must always be present. There must be at least one fixed parameter. Then put an ellipse at the end of the parameter list to indicate that zero or more arguments are being passed to the function. In this context, please keep in mind that, as mentioned on Day 4, "Functions," there is a difference between a parameter and an argument.

How does a function know how many arguments were passed to it in a particular call? You tell her. One of the fixed parameters informs the function of the total number of arguments. For example, if you use the function, the function can tell from the number of conversion specifiers in the format string how many more arguments to expect. It is even more direct if one of the fixed function arguments specifies the number of further arguments. The example I'm about to present takes this approach, but before that you should become familiar with some of the tools that C provides for implementing functions with arbitrarily long lists of arguments.

The function must know the type of each argument in the list. In the case of, the conversion specifiers indicate the respective type of the argument. In other cases, as in the following example, all arguments of the arbitrarily long list are of the same type, so there are no problems. To create a function that accepts different types in the argument list, you need to find a way to pass the information about the argument types. One possibility would be to specify a character code, as we did with the function in Listing 8.7.

The tools for implementing lists of arguments of any length are defined in. These tools are used within the function to access the arguments from the argument list. They are:

A pointer data type

A macro used to initialize the list of arguments

A macro that can be used to access the arguments in the argument list one after the other

A macro for cleaning up

In the following I will briefly describe how these macros are used in a function and then show you an example. Inside the function, you need to do the following to access the arguments:

  1. Declare a pointer variable of type. This pointer is required to access the individual arguments. It is common, if not absolutely necessary, to mention this variable.
  2. Call the macro, passing it the pointer and name of the last fixed argument. The macro has no return value. It initializes the pointer to point to the first argument in the argument list.
  3. To address the individual arguments, call the macro and pass it the pointer and the data type of the next argument. When the function has taken arguments, invoke -mal to access the arguments in the order in which they are listed in the function call.
  4. When all arguments from the argument list have been addressed, call the macro and pass it the pointer. In some implementations this macro is not needed, but in others it does all the necessary cleanup. You should make it a rule to call in case your C implementation requires it.

Let us now come to the example: The function from Listing 17.5 calculates the arithmetic mean for a series of integer values. The program passes a single fixed argument to the function that specifies the number of further arguments, followed by the list of numbers.

Listing 17.5. A function with an arbitrarily long list of arguments.

1: / * functions with any number of arguments. * /
2:
3: #include
4: #include
5:
6: float average (int num, ...);
7:
8: int main (void)
9: {
10: float x;
11:
12: x = average (10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
13: printf ("The first average value is% f. \ N", x);
14: x = average (5, 121, 206, 76, 31, 5);
15: printf ("The second average is% f. \ N", x);
16: return (0);
17: }
18:
19: float average (int num, ...)
20: {
21: / * Declares a variable of the type va_list. * /
22:
23: va_list arg_ptr;
24: int count, total = 0;
25:
26: / * Initializes the argument pointer. * /
27:
28: va_start (arg_ptr, num);
29:
30: / * Addresses every argument in the variable list. * /
31:
32: for (count = 0; count 33: total + = va_arg (arg_ptr, int);
34:
35: / * Cleanup. * /
36:
37: va_end (arg_ptr);
38:
39: / * Divides the total by the number of values ​​to obtain the * /
40: / * average to get. Converts all to a float type * /
41: / * um, so that the return value is of type float. * /
42:
43: return ((float) total / num);
44: }

The first average is 5,500,000.
The second average is 87.800003.

The function is called for the first time in line 12. The first argument passed to it - the only fixed argument - specifies the number of values ​​in the argument list of any length. In the function, in lines 32 and 33, all arguments are read from the argument list and added up in the variable. After adding up all of the arguments from the list, line 43 converts the variable to type and then divides to get the average.

I would like to draw your attention to two points in this listing.Line 28 calls to initialize the argument list. This call must be made before the values ​​are read from the list. And line 37 calls for cleanup after the function no longer needs the values. You should always include these two functions in your programs whenever you implement a function with any number of arguments.

Strictly speaking, a function that takes any number of arguments does not need to have a fixed parameter that specifies the number of arguments passed. For example, you could mark the end of the argument list with a special value that is not used anywhere else. However, this method limits the arguments that can be passed, so it is best to avoid them.

Search and sort

One of the most common tasks that programs have to deal with is finding and sorting data. The C standard library contains general functions that can be used to solve these tasks.

Search with bsearch ()

The library function performs a binary search on an array of data, looking for an array element that matches a value (the key) it is looking for. To be able to apply, the array must be sorted in ascending order. The program must also provide the comparison function it needs to determine whether a data element is greater than, less than, or equal to another element. The prototype of is in and reads:

void * bsearch (const void * key, const void * base, size_t num, size_t size,
int (* cmp) (void * elem1, void * elem2));

This prototype is quite complex. Therefore, you should study it carefully. The argument is a pointer to the data element being searched for and a pointer to the first element in the array to be searched. Both are declared with the type so that they can point to any C data object.

The argument is the number of elements in the array and the size of the elements in bytes. The type specifier refers to the data type returned by the operator that is unsigned. Typically, the operator is used to specify the values ​​for and.

The last argument,, is a pointer to the comparison function. This can be a function set up by the programmer or - if string data are searched - the library function. The comparison function must meet the following two criteria:

  • It must take pointers to two data elements.
  • It must return one of the following values:

    Element 1 is smaller than element 2.

    Element 1 is equal to element 2.

    Element 1 is larger than element 2.

The return value of is a pointer of the type. The function returns a pointer to the first array element that corresponds to the key, or if no match is found. The type of pointer returned must be converted accordingly before the pointer can be used.

The operator can provide the and arguments as follows. If that is the array to be searched, then the instruction returns

sizeof (array [0]);

returns the value for, that is, the size of an array element in bytes. Since the expression returns the size of an entire array in bytes, you can use the following statement to determine the value of, the number of elements in the array:

sizeof (array) / sizeof (array [0])

The binary search algorithm is very efficient. You can use it to search a large array very quickly. However, it assumes that the array elements are sorted in ascending order. And this is how the algorithm works:

  1. The key is compared to the element in the middle of the array. If there is already a match at this point, another search is done. Otherwise the key must be either smaller or larger than the array element.
  2. If the key is smaller than the array element, the element searched for, if any, must be in the first half of the array. Correspondingly, if the element you are looking for is larger than the array element, it is in the second half of the array.
  3. The search is limited to the corresponding half of the array and the algorithm starts again with step 1.

As you can see, any binary search comparison cuts the searched array in half. For example, an array with 1000 elements can be searched with only 10 searches, and an array with 16,000 elements with only 14 searches. In general it can be said that a binary search takes searches to search through an array of 2n elements.

Sort with qsort ()

The library function is an implementation of the quicksort algorithm developed by C.A.R. Hoare was invented. This function sorts an array into a given order. Usually it is sorted in ascending order, but can also be sorted in descending order. The prototype of this function is defined in and reads:

void qsort (void * base, size_t num, size_t size,
int (* cmp) (void * elem1, void * elem2));

The argument points to the first element in the array, is the number of elements in the array and the size of an array element in bytes. The argument is a pointer to a comparison function. The same rules apply to this comparison function as to the comparison function used by and described in the previous section. Often the same comparison function is used for and. The function has no return value.

Search and sort: two examples

Listing 17.6 illustrates the use of and. The program sorts and searches through an array of values.

Listing 17.6: Using the qsort () and bsearch () functions to find and sort values.

1: / * Use qsort () and bsearch () with values. * /
2:
3: #include
4: #include
5:
6: #define MAX 20
7:
8: int intvgl (const void * v1, const void * v2);
9:
10: int main (void)
11: {
12: int arr [MAX], count, search, * zgr;
13:
14: / * Read in values. * /
15:
16: printf ("Enter% d integers. \ N", MAX);
17:
18: for (count = 0; count 19: scanf ("% d", & arr [count]);
20:
21: puts ("Press Enter to sort the values.");
22: getc (stdin);
23:
24: / * Sorts the array in ascending order. * /
25:
26: qsort (arr, MAX, sizeof (arr [0]), intvgl);
27:
28: / * Outputs the sorted array. * /
29:
30: for (count = 0; count 31: printf ("\ narr [% d] =% d.", Count, arr [count]);
32:
33: puts ("\ nContinue with Enter.");
34: getc (stdin);
35:
36: / * Enter search value. * /
37:
38: printf ("Please enter a value to search for:");
39: scanf ("% d", & search);
40:
41: / * Perform search. * /
42:
43: zgr = (int *) bsearch (& search, arr, MAX, sizeof (arr [0]), intvgl);
44:
45: if (zgr! = NULL)
46: printf ("% d found at arr [% d]. \ N", search, (zgr - arr));
47: else
48: printf ("% d not found. \ N", search);
49: return (0);
50: }
51:
52: int intvgl (const void * v1, const void * v2)
53: {
54: return (* (int *) v1 - * (int *) v2);
55: }

Enter 20 integer values.
45
12
999
1000
321
123
2300
954
1968
12
2
1999
1776
1812
1456
1
9999
3
76
200
Press Enter to sort the values.

arr [0] = 1.
arr [1] = 2.
arr [2] = 3.
arr [3] = 12.
arr [4] = 12.
arr [5] = 45.
arr [6] = 76.
arr [7] = 123.
arr [8] = 200.
arr [9] = 321.
arr [10] = 954.
arr [11] = 999.
arr [12] = 1000.
arr [13] = 1456.
arr [14] = 1776.
arr [15] = 1812.
arr [16] = 1968.
arr [17] = 1999.
arr [18] = 2300.
arr [19] = 9999.
Continue with Enter.

Enter a value to search:
1776
Found in 1776 at arr [14]

Listing 17.6 combines everything that has been said so far about sorting and searching. At the beginning of the program you can enter up to values ​​(in this case 20). The values ​​are sorted and then output in the new order. You can then enter a value to search for in the array. A final message informs you whether the value was found in the array or not.

You should already be familiar with the code on lines 18 and 19 that reads the values ​​for the array. Line 26 calls to sort the array. The first argument is a pointer to the first element in the array. This is followed by the argument, the number of elements in the array. Then the size of the first element is specified so that it knows the size of the elements. The call ends with the argument for the sort function.

The function is defined in lines 52 to 55. It returns the difference between the two values ​​passed to it. At first glance this seems almost too easy, but remember which values ​​the comparison function should return. If the elements are the same, it should be returned. If element one is greater than element two, a positive number should be returned, and if the first element is smaller than the second element, a negative number should be returned. And that's exactly what does.

The search is carried out with. Note that the arguments for are virtually the same as for. The only difference is that the first argument of is the key that is being searched for. returns a pointer to the point where the key was found or if the key was not found. In line 43 the return value of is assigned. is then used in the - instruction on lines 45 to 48 to inform the user that the search has been successful.

Listing 17.7 basically does the same thing as Listing 17.6, except that this time strings are sorted and searched.

Listing 17.7: Using qsort () and bsearch () for strings.

1: / * Use qsort () and bsearch () for strings. * /
2:
3: #include
4: #include
5: #include
6:
7: #define MAX 20
8:
9: int compare (const void * s1, const void * s2);
10:
11: int main (void)
12: {
13: char * data [MAX], buffer [80], * zgr, * search, ** search1;
14: int count;
15:
16: / * Read a list of words. * /
17:
18: printf ("Please enter% d words. \ N", MAX);
19:
20: for (count = 0; count 21: {
22: printf ("Word% d:", count + 1);
23: fgets (buffer, 80, stdin);
24: buffer [strlen (buffer) -1] = 0;
25: data [count] = malloc (strlen (buffer) +1);
26: strcpy (data [count], buffer);
27: }
28:
29: / * Sorts the words (or rather the pointers). * /
30:
31: qsort (data, MAX, sizeof (data [0]), compare);
32:
33: / * Print the sorted words. * /
34:
35: for (count = 0; count 36: printf ("\ n% d:% s", count + 1, data [count]);
37:
38: / * Read in a search term. * /
39:
40: printf ("\ n \ nEnter a search term:");
41: fgets (buffer, 80, stdin);
42: buffer [strlen (buffer) -1] = 0;
43:
44: / * Carries out the search. search1 becomes the pointer * /
45: / * on the pointer to the search term. * /
46:
47: search = buffer;
48: search1 = & search;
49: zgr = bsearch (search1, data, MAX, sizeof (data [0]), compare);
50:
51: if (zgr! = NULL)
52: printf ("% s found. \ N", buffer);
53: else
54: printf ("% s not found. \ N", buffer);
55: return (0);
56: }
57:
58: int compare (const void * s1, const void * s2)
59: {
60: return (strcmp (* (char **) s1, * (char **) s2));
61: }

Enter 20 words.
Word 1: apple
Word 2: orange
Word 3: grapefruit
Word 4: peach
Word 5: plum
Word 6: pear
Word 7: cherry
Word 8: banana
Word 9: raspberry
Word 10: Lime
Word 11: tangerine
Word 12: star fruit
Word 13: watermelon
Word 14: gooseberry
Word 15: plum
Word 16: strawberry
Word 17: currant
Word 18: blueberry
Word 19: grape
Word 20: Cowberry

1: apple
2: banana
3: pear
4: blueberry
5: strawberry
6: grapefruit
7: raspberry
8: currant
9: cherry
10: Lime
11: orange
12: peach
13: plum
14: lingonberry
15: gooseberry
16: star fruit
17: tangerine
18: grape
19: watermelon
20: plum

Enter a search term: orange
Orange found.

There are a couple of points in Listing 17.7 that we should briefly cover. The program uses an array of pointers to strings - a technique introduced on Day 14, "Advanced Pointers." As you learned back then, you can sort the strings by sorting the array of pointers. To do this, however, the comparison function must be adapted. Pointers to the two elements in the array that are being compared are passed to the comparison function. However, you don't want to sort the array of pointers by the values ​​of the pointers themselves, but by the values ​​of the strings that the pointers refer to.

So you need to use a comparison function that passes pointer to pointer. Each argument to is a pointer to an array element, and since each element is itself a pointer (to a string), the argument is a pointer to a pointer. Within the function itself, you dereference the pointers so that the return value depends on the values ​​of the referenced strings.

The fact that the arguments passed are pointers to pointers creates problems in other ways as well. You store the search term in and you also know that the name of an array (in this case) is a pointer to the array. However, you don't have to pass it yourself, but a pointer to it. The problem with this is that it is a pointer constant, not a pointer variable. itself has no address in memory; it's a symbol that evaluates to the address of the array. Therefore, you cannot create a pointer pointing to using the address operator in front of (as in).

How do you behave in such a case? First you create a pointer variable and assign it the value of. This pointer variable has the name in our program. Since is a pointer variable, it has an address, and you can create a pointer to take that address as a value - here. When you finally call, you pass as the first argument - a pointer to a pointer to the search string. The function passes the argument and everything goes like clockwork.

What you should do

Don't forget to sort your search array in ascending order before using.

Summary

Today we got to know some useful functions of the C function library: Functions for performing mathematical calculations, for processing time information and for error handling. You will particularly find the functions for searching and sorting data useful. Writing your own programs can save you a lot of time.

questions and answers

Question:
Why are the return values ​​of almost all math functions of the type?

Answer:
The answer to this question lies in the pursuit of accuracy (rather than consistency). The type is more precise than the other data types. Using return values ​​ensures that the return values ​​are as accurate as possible. For more on this, read the explanations about type conversion and automatic conversions from day 18, "Using memory".

Question:
Are and the only ways how to sort and search for data in C?

Answer:
The two functions and are part of the standard library. However, you don't have to use them. Many computer textbooks provide instructions on how to write your own search and sort programs. C contains all of the commands you need to write your own functions. You can also buy special search and sort routines. The biggest advantage of and is that they are already implemented and that they are supplied with every ANSI / ISO-compatible compiler.

Question:
Do the mathematical functions check whether the data transferred to them are within the permissible range of values?

Answer:
Never assume that the information you entered is correct. You should therefore check all data entered by the user. For example, if you pass a negative value to the function, the function generates an error. You will certainly not want to report this error as it is. Why not? Remove the statement from Listing 17.1 and enter a negative number to see what I mean.

Question:
Why don't all compilers support the same functions?

Answer:
In today's discussion you learned that certain C functions are not available on all compilers or on all computer systems

There are standards that all ANSI compilers adhere to.But these standards do not forbid compiler manufacturers to add further functionality to their products. This new functionality comes in the form of new features. Every compiler manufacturer adds a number of functions to their compilers that they consider useful for their customers.

Question:
Isn't C actually a standardized language?

Answer:
C is in fact highly standardized. The American National Standards Institute (ANSI) developed the ANSI-C standard, which specifies almost all of the details of C, including the functions that come with it. Some compiler manufacturers have added features that are not part of the ANSI standard to their compilers in order to stay ahead of the competition. In addition, you may come across a compiler which, according to your own statements, does not comply with the ANSI standard. If you limit yourself to ANSI standard compilers, you will find that 99% of the program syntax and functions are the same.

Workshop

The workshop contains quiz questions to help you consolidate your knowledge, as well as exercises to encourage you to apply what you have learned and gain your own experience. The solutions to the questions and the exercises can be found in Appendix C.

quiz

  1. What is the return type for the math functions of C?
  2. Which type of variable does C correspond to?
  3. What are the differences between the functions and?
  4. What does the function do to fix an existing error?
  5. Can you write a function that takes an arbitrarily long list of arguments without fixed arguments?
  6. Which macros should you use when writing functions with arbitrarily long lists of arguments?
  7. What do you have to do before searching an array with?
  8. How many comparisons would you have to make to find an element in an array of 16,000 elements?
  9. How many comparisons would one have to make to find an element in an array of 10 elements?
  10. How many comparisons would you have to make to find an element in an array of 2,000,000 elements?
  11. Which values ​​must a comparison function return for and?
  12. What returns if it doesn't find the element you're looking for?

Exercises

  1. Make a call. The array to be searched is named and the values ​​are strings. The comparison function is called. Assume that all names are the same size.
  2. TROUBLESHOOTING: What's wrong with the following program? #include
    #include
    int main (void)
    {
    int values ​​[10], count, search, ctr;

    printf ("Enter values");
    for (ctr = 0; ctr <10; ctr ++)
    scanf ("% d", & values ​​[ctr]);

    qsort (values, 10, comparison_function ());
    }
  3. TROUBLESHOOTING: Is there anything wrong with the comparison function? int intvgl (int element1, int element2)
    {
    if (element 1> element 2)
    return -1;
    else if (element 1 return 1;
    else
    return 0;
    }

There are no answers to the following exercises:

  1. Modify Listing 17.1 to work with negative numbers. To do this, sort according to the absolute value. You may need to refer to the man pages to find the function that calculates the absolute value.
  2. Write a program with a menu that contains options for various math functions. Use as many math functions as possible.
  3. Using the timing functions discussed today, write a function that will pause the program for about five seconds.
  4. 7. Add the function to the program from exercise 4. The program should display a message if a negative value has been entered.
  5. Write a program that reads 30 names and sorts them as well. The program should output the sorted names.
  6. Change the program in exercise 8 so that the program does not read any further entries after entering »« and sorts the values ​​entered up to then.
  7. Day 14 demonstrated a simple way to sort an array of pointers to strings. Write a program that measures the time it takes to sort a large array of pointers using this method, and then compares that time to the time it takes to do the same search using the library function.
  8. Implement a function that a) accepts any number of strings as arguments, b) attaches the strings in sorted order to form a single large string, and c) returns a pointer to the new string to the calling program.
1

2

    Most of the time "no error" is output on English systems.