class: center, middle ### COMP26020 Programming Languages and Paradigms Part 1: C Programming *** # The C Standard Library Part 1 ## String & Memory Manipulation, Console Input, Math and Time ??? - Hello everyone - This is the first of a series of 3 videos in which we will talk about the C standard library - It's a set of functions you can use in your programs to realise various low-level tasks - In this video we'll see functions regarding string and memory manipulation, console input, math and time --- # Standard Library - Already saw: `printf`, `malloc`, `atoi`, etc. - `man
` in a Linux terminal: - Function description, prototype, required headers, return value ??? - We already came across a few functions of the standard library, such as `printf` or `malloc` - For every function of the standard library, if you type `man
` in a Linux terminal, you'll get access to the manual page for the function in question - It will give you everything you need to know to use that function: - Function description, prototype, required headers, return value - For each function that I present in this video, I'll put a link to an online man page - I encourage you to download these slides to check them out, or to use the man locally in a terminal --- class: center, middle, inverse # String Manipulation ??? - Let's start with string manipulation --- # String Copy ```c char *strcpy(char *dest, const char *src); char *strncpy(char *dest, const char *src, size_t n); ``` .codelink[[man](https://linux.die.net/man/3/strcpy)] ```c #include
/* ... */ char *string1 = "hello"; char *string2 = string1; // this is not a string copy! char string3[10]; // allocated space of 10 bytes, it's called a buffer /* not super safe, what happens if string1 > string3? */ strcpy(string3, string1); /* better */ strncpy(string3, string1, 10); printf("string1 @%p: %s\n", string1, string1); // string1 @1234: hello printf("string2 @%p: %s\n", string2, string2); // string2 @1234: hello printf("string3 @%p: %s\n", string3, string3); // string3 @5678: hello ``` .codelink[
`12-standard-library-1/strcpy.c`
]
??? - If you want to copy a string, you should use the `strcpy` function - Note that you cannot use the equal operator to copy a string - Remember that strings are arrays, and arrays are pointer - So effectively with equal you just create another copy of the pointer that points to the same array - As presented on the picture - So you should rather use `strcpy` - It takes the destination string as first parameter, and the source string as second parameter - The `const` marker is simply there to indicate that `strcpy` will not modify the source parameter - Notice how we allocate 10 bytes for the destination, on the stack pointed by `string3` - We could have also used `malloc` - We generally refer to this kind of space allocated in memory as a buffer - Keep that term in mind it will come back often in the course - With `strcpy`, be careful about the sizes of the strings, if the destination buffer is smaller than the source string, you'll get a nasty memory error, a buffer overflow - `strncpy` is safer as it accepts a 3rd argument, `n`, and copies only up to `n` bytes - So there you can put the size of the destination buffer - Note that both functions will also copy the termination character --- # String Concatenation ```c char *strcat(char *dest, const char *src); char *strncat(char *dest, const char *src, size_t n); ``` .codelink[[man](https://linux.die.net/man/3/strcat)] ```c #include
/* ... */ char world[6] = "world"; char s1[32]; char s2[32]; strcpy(s1, "hello "); strcpy(s2, "hello "); strcat(s1, world); // not very safe strncat(s2, world, 32); // better printf("s1: %s\n", s1); // hello world printf("s2: %s\n", s2); // hello world ``` .codelink[
`12-standard-library-1/strcat.c`
] ??? - To concatenate two strings, use the `strcat` or `strncat` functions - `strcat` takes two parameters, a destination and source string - In effect it concatenates the source at the end of the destination - Once again be careful about the buffer sizes - You can also use `strncat` to concatenate up to a given number of characters --- # Format-based String Creation ```c int sprintf(char *str, const char *format, ...); ``` .codelink[[man](https://linux.die.net/man/3/sprintf)] - Fill a string with `printf`-like specifiers ```c #include
int main(int argc, char **argv) { int a = 12; float b = 4.5; char *s = "hello"; char string[64]; sprintf(string, "a is %d, b is %f, s is %s\n", a, b, s); printf("%s", string); // a is 12, b is 4.500000, s is hello return 0; } ``` .codelink[
`12-standard-library-1/sprintf.c`
] ??? - `sprintf` is a useful function to create a string that is filled with values from variables of various type - This is done with `printf`-like specifiers - You call it like that - First, the destination string - Then, a constant string filled with text as well as specifiers, same as in `printf` - Then, a list of variables or expression corresponding to the specifiers, like in `printf` - Make sure the destination string is large enough to avoid memory errors --- # String Length and Comparison - Get string length with `strlen` - Compare two strings with `strcmp` -- *warning: returns 0 if they match!* .leftcol[ ```c size_t strlen(const char *s); ``` .codelink[[man](https://linux.die.net/man/3/strlen)] ] .rightcol[ ```c int strcmp(const char *s1, const char *s2); ``` .codelink[[man](https://linux.die.net/man/3/strcmp)] ] ```c #include
/* ... */ char *s1 = "hello"; char *s2 = "hello"; char *s3 = "not hello"; printf("strcmp(s1, s2) returns: %d\n", strcmp(s1, s2)); // 0 printf("strcmp(s1, s3) returns: %d\n", strcmp(s1, s3)); // -6 printf("length of s1: %d\n", strlen(s1)); // 5 printf("length of s2: %d\n", strlen(s2)); // 5 printf("length of s3: %d\n", strlen(s3)); // 9 ``` .codelink[
`12-standard-library-1/strlen-strcmp.c`
] More functions: `man string` and https://bit.ly/3Dek4GB ??? - To get the size of a string, the number of characters it contains, use `strlen` - Note that this function does not count the termination character - To compare two strings, use `strcmp` - It returns 0 if the string matches, a negative number if `s1` is located before `s2` in the lexicographical order, and a positive one if `s1` is after `s2` - You have an example of usage of both functions here - If you want to know more about string manipulation functions you can use this man page and also check out this link --- class: center, middle, inverse # Console Input ??? - Now let's briefly talk about receiving input from the user --- # Console Input .rightcol[ ```c int scanf(const char *format, ...); ``` .codelink[[man](https://linux.die.net/man/3/scanf)] ] .leftcol[ ```c char *fgets(char *s, int size, FILE *stream); ``` .codelink[[m](https://linux.die.net/man/3/fgets)] ] ```c int main(int argc, char **argv) { int int1, int2; double double1; float float1; char s[128]; printf("Please input a string:\n"); fgets(s, 128, stdin); printf("Please input an integer:\n"); scanf("%d", &int1); printf("Please input a float:\n"); scanf("%lf", &double1); /* make sure to us %lf for double and %f for float */ printf("Please enter an integer and a float separated by a space\n"); scanf("%d %f", &int2, &float1); printf("You have entered: %d, %d, %lf, %f, and %s\n", int1, int2, double1, float1, s); return 0; } ``` .codelink[
`12-standard-library-1/console-input.c`
] ??? - We have `fgets` to get a string from the user - You use it like that, putting the destination buffer as first parameter, the size of that buffer, and the special keyword `stdin` that indicate the standard input - The program will then read what is typed on the keyboard until the user presses enter - To input a number you should rather use `scanf` - It takes a `printf`-like format string, with a specifier for the variable we wish to update the value based on the user input - Then we have the addresses of the variable in question - For example here the user will enter an integer number and this value will be stored in the `int1` variable --- class: center, middle, inverse # Memory Manipulation ??? - Now let's see a couple of memory manipulation functions --- # Writing bytes to memory, Copying memory .leftcol[ ```c void *memset(void *s, int c, size_t n); ``` .codelink[[man](https://linux.die.net/man/3/memset)] ] .rightcol[ ```c void *memcpy(void *dest, void *src, size_t n); ``` .codelink[[m](https://linux.die.net/man/3/memcpy)] ] ```c #include
#include
// needed for memcpy and memset #include
int main(int argc, char **argv) { int buffer_size = 10; char *ptr1 = malloc(buffer_size); char *ptr2 = malloc(buffer_size); if(ptr1 && ptr2) { memset(ptr1, 0x40, buffer_size); // 0x40 is ascii code for @ memcpy(ptr2, ptr1, buffer_size); for(int i=0; i
`12-standard-library-1/memset-memcpy.c`
] ??? - `memset` repeatedly writes the byte `c`, `n` times, starting from address `s` - It can be useful for example when you want to zero out a buffer - In this example we use it to fill a character buffer with the ascii code for the `@` sign - `memcpy` copies a buffer into another one - Here we use it to copy `buffer_size` bytes, from the address pointed by `ptr1`, to the address pointed by `ptr2` - Of course, be aware of the sizes of your buffers to avoid overflows with these functions --- class: center, middle, inverse # Math ??? - Let's briefly talk about math functions --- # Math functions .leftcol[ ```c double ceil(double x); float ceilf(float x); ``` .codelink[[man](https://linux.die.net/man/3/ceil)] ```c double sqrt(double x); ``` .codelink[[man](https://linux.die.net/man/3/sqrt)] ```c double pow(double x); ``` .codelink[[man](https://linux.die.net/man/3/pow)] ```c double cos(double x); // ``` .codelink[[man](https://linux.die.net/man/3/cos)] ] .rightcol[ ```c // When compiling a program using math.h, // use -lm on the command line: // gcc program.c -o program -lm #include
#include
// needed for math functions int main(int argc, char **argv) { printf("ceil 2.5: %f\n", ceil(2.5)); printf("floor 2.5: %f\n", floor(2.5)); printf("2^5: %f\n", pow(2, 5)); printf("sqrt(4): %f\n", sqrt(4)); return 0; } ``` .codelink[
`12-standard-library-1/math.c`
] ] - And many more, see here: http://www.cplusplus.com/reference/cmath/ ??? - Here are a few math functions - Most have a `float` and `double` version, for example `ceil` and `ceilf` - You have the square root, power, cosinus, amongst many others - You can check out this link for more - Note that you need to use this special flag, `-lm` when building with the math part of the standard library --- class: middle, center, inverse # Time ??? - Let's see a few time related functions --- # Sleeping .leftcol[ ```c unsigned int sleep(unsigned int seconds); ``` .codelink[[man](https://linux.die.net/man/3/sleep)] ] .rightcol[ ```c int usleep(useconds_t usec); ``` .codelink[[man](https://linux.die.net/man/3/usleep)] ] ```c #include
#include
// needed for sleep and usleep int main(int argc, char **argv) { printf("hello!\n"); printf("Sleeping for 2 seconds ...\n"); sleep(2); printf("Now sleeping for .5 seconds ...\n"); usleep(500000); return 0; } ``` .codelink[
`12-standard-library-1/sleep.c`
] ??? - If you want your program to wait for a given amount of time you can use `sleep` for sleeping in seconds, and `usleep` for sleeping in microseconds - It is useful in certain applications that generally have an infinite main loop, but don't want to hang the CPU, such as servers --- # Current Time ```c time_t time(time_t *tloc); // time_t is generally a long long unsigned int ``` .codelink[[man](https://linux.die.net/man/2/time)] ```c #include
#include
// needed for time() int main(int argc, char **argv) { unsigned long long t = time(NULL); printf("Number of seconds elapsed since the epoch (01/01/1970):\n"); printf("%llu\n", t); return 0; } ``` .codelink[
`12-standard-library-1/time.c`
] ??? - To get the current time you can use the `time` function - A simple way to call it is with `NULL` as a parameter - It returns the number of seconds elapsed since the 1st of January 1970, which is kind of a standard timestamp for UNIX computers --- # Measuring Execution Time ```c int gettimeofday(struct timeval *tv, struct timezone *tz); // struct timeval { // time_t tv_sec; /* seconds (type: generally long unsigned) */ // suseconds_t tv_usec; /* microseconds (type: generally long unsigned) */ // }; ``` .codelink[[man](https://linux.die.net/man/2/gettimeofday)] ```c #include
#include
// needed for gettimeofday int main(int argc, char **argv) { struct timeval tv, start, stop, elapsed; gettimeofday(&tv, NULL); printf("Seconds since the epoch: %lu.%06lu\n", tv.tv_sec, tv.tv_usec); gettimeofday(&start, NULL); for(int i=0; i<1000000000; i++); gettimeofday(&stop, NULL); timersub(&stop, &start, &elapsed); printf("Busy loop took %lu.%06lu seconds\n", elapsed.tv_sec, elapsed.tv_usec); return 0; } ``` .codelink[
`12-standard-library-1/measuring-exec-time.c`
] ??? - To get something more precise we can use `gettimeofday` - It takes a pointer to a `struct timeval` as parameter - This struct has two fields, one for seconds and the other for microseconds - The second parameter should always be `NULL` - Like time it also returns the time elapsed since the 1st of January 1970 - Notice how we print the decimal part, `%06` indicates to include up to six leading zeroes if the microsecond value is inferior to one million - Without this you'll print incorrect values - `gettimeofay` is very useful to measure execution time - You can do it like that - You declare 3 `struct timeval` variables - We do a first call to `gettimeofay` right before the code for which we want to measure the execution time - Here it's just a busy loop - We do a second call to `gettimeofday` right after - Then we call `timersub` that computes the difference between the two timestamps --- # Summary - C standard library offers various low level functions for - String and memory operations - Console I/O - Math - Time - etc. ---- .center[Feedback form: https://bit.ly/2VFzbb2]
??? - So let's recap - We saw many functions in this video, regarding string and memory manipulation - Console input - Math - and time - In the next video we will continue to talk about the standard library, and we will look a file I/Os