C language: library function simulation

Keywords: C C++

preface

We know that there are many library functions in C language, which play a very important role in our programming. Let's write several common library functions to further understand their internal working principle.

Common library functions

String function

strlen

The string length function is a function we often use. It will not be repeated here. The following three methods are provided for reference

size_t my_strlen_1(char* s) {
	size_t count = 0;
	while (*s++) {
		++count;
	}
	return count;
}
size_t my_strlen_2(char*s){
	if (*s == 0)
		return 0;
	else
		return 1 + my_strlen_2(++s);
}
size_t my_strlen_3(char* s) {
	char* p = s;
	while (*p++) {

	}
	return p - s-1;
}
  1. There is a common non '\ 0' plus one method, and finally returns a value
  2. Function iteration method without creating temporary variables
  3. Pointer subtraction

strcmp

strcmp function is the abbreviation of string compare. It is used to compare two strings and return an integer according to the comparison result.
The basic form is strcmp(str1,str2)
If str1=str2, zero is returned;
If STR1 < STR2, a negative number is returned;
If STR1 > STR2, a positive number is returned.

int my_strcmp(const char* s1, const char* s2) {
	assert(s1 && s2);
	while (*s1 == *s2) {
		if (*s1 == 0)
			return 0;
		++s1;
		++s2;
	}
	return *s1 - *s2;
}

strcat

String append function

  1. Copy the string pointed to by src (including "\ 0") after the string pointed to by DeST (delete "\ 0" at the original end of * dest). Ensure that * dest is long enough to accommodate the copied * src* The original characters in src remain unchanged. Returns a pointer to dest.
  2. It should be noted that the dest array should be long enough to store the additional contents.
char* my_strcat(char* dest, const char* src) {
	assert(dest && src);
	char* p = dest;
	while (*dest) {
		++dest;
	}
	while ((*dest++ = *src++)) {
		;
	}
	return p;
}

strcpy

strcpy copies the string containing '\ 0' terminator to another address space, and the return value type is char *.

char* my_strcpy(char* dest, const char* src) {
	assert(dest&&src);
	char* p = dest;
	while (*dest++ = *src++) {


	}
	return p;
}

strstr

The strstr(str1,str2) function is used to determine whether the string str2 is a substring of str1. If yes, the function returns the str1 string from the first occurrence of str2 to the end of str1; Otherwise, NULL is returned.
In our setting, if it is not a string, it returns - 1;

int strStr(char* haystack, char* needle) {
    int n = strlen(haystack);
    int m = strlen(needle);
    for (int i = 0; i + m <= n; i++) {
        int flag = 1;
        for (int j = 0; j < m; j++) {
            if (haystack[i + j] != needle[j]) {
                flag = 0;
                break;
            }
        }
        if (flag) {
            return i;
        }
    }
    return -1;
}

Force buckle - simulated str

Memory operation function

memcpy function

memcpy refers to the memory copy function used in C and C + +. The function prototype is

void *memcpy(void *dest, void *src, size_t count);

The function copies several bytes from the starting position of the source memory address to the target memory address, that is, n bytes from the source src to the target dest.
We need to pay attention to:

  1. The memory areas indicated by src and dest may overlap, but if the memory areas indicated by source and destin ation overlap, this function does not ensure that the overlapping area of source is not overwritten before copying. memmove can be used to handle overlapping areas. In other words, the memory space to be copied and pasted cannot coincide
  2. The memcpy function overwrites the original memory contents
  3. src and dest are not necessarily arrays, and any read-write space can be used.

With the above information, we can implement the memcpy function

void* my_memcpy(void* dest, const void* src, size_t n) {
	while (n--) {
		*((char*)dest + n) = *((char*)src + n);
	}
	return dest;//                                         (1)
}

Code interpretation:

(1) Copy from back to front is adopted, and dest pointer is not changed, so dest pointer can be returned directly; If you copy from front to back, you may need to change the dest pointer. At this time, we need to create a variable in advance to store dest and then use it to return

The string copy function strcpy described above seems to be very similar to memcpy. The differences between them are as follows
There are three main differences between strcpy and memcpy.

  1. The copied content is different. strcpy can only copy strings, while memcpy can copy any content, such as character arrays, integers, structs, classes, etc.
  2. Replication methods are different. strcpy does not need to specify the length. It ends only when it encounters the string terminator "\ 0" of the copied character, so it is easy to overflow. memcpy determines the copy length according to its third parameter.
  3. Different uses. strcpy is usually used when copying strings, while memcpy is usually used when copying other types of data.

memmove

In the above function, we know that the copy of memcpy cannot be used for overlapping space. The reason is that the content disappears after coverage. memmove is to solve this problem. How to solve it?
It's very simple. Judge the overlap, and discuss whether the copy mode is from front to back or from back to front, so as to avoid the impact caused by overlapping memory
In short, overlapping spaces are used first and then covered
Now we will discuss the situation

Case 1
We can see that there is no overlapping space between the two, so you can copy from the front or from the back

Case 2
We can see that the front part of src is overwritten. If it is copied from the past, it will not be affected even if it is overwritten, so it can only be copied from the past

Case 3
According to situation 2 analysis, we can only copy from the back

Situation 4
It can be copied from the front or from the back

We can classify case 2 or case 3 into one category and other categories
I chose to classify case 3 into one category, and its corresponding condition is

      dest>=src&&(char*)dest<(char*)src+count;

Function internal operation

void* my_memmove(void* dest, const void* src, size_t count) {
	assert(dest && src);
	char* p = dest;
	if (dest >= src && (char*)dest <= (char*)src + count) {
		while (count--) {
			*((char*)dest + count) = *((char*)src + count); //(1)
		}
	}
	else {
		while (count--) {
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}//(2)
	return p;
}

Code interpretation

(1) Copy back to front
(2) Copy from front to back

Posted by bibby on Sun, 19 Sep 2021 19:53:09 -0700