[advanced learning notes of C language] III. detailed explanation of string function + memory function

Posted by christa on Sat, 29 Jan 2022 15:03:59 +0100


This article continues from the previous article [advanced learning notes of C language] III. detailed explanation of string function (1) (sorting out liver explosion and hematemesis, recommended collection!!!)
To introduce and learn the string operation function and memory operation function in detail.

9, strtok

char* strtok(char* str, const char* sep);
Header file: string h
Function name: strtok
Function parameters:
[parameter 1] str, the starting position of the string to be split
[parameter 2] sep, the starting position of the character set used for segmentation
Function return type: char *, mark position
Function function: string segmentation

Application examples:

#include<stdio.h>
#include<string.h>
int main()
{
	//192.168.31.121 network ip address -- dotted decimal
	//192 168 31 121  ---strtok  .
	//student_zhang@whu.edu e-mail address
	//student_zhang whu edu --- @ .
	char arr[] = "student_zhang@whu.edu";
	char* p = "@.";
	char buf[100] = { 0 };
	char* ret = 0;//The position used to receive the mark after segmentation
	//Make a temporary copy before splitting the string
	strcpy(buf, arr);
	//Split strings in buf

	//ret = strtok(buf, p);
	//printf("%s\n", ret);

	//ret = strtok(NULL, p);
	//printf("%s\n", ret);

	//ret = strtok(NULL, p);
	//printf("%s\n", ret);

	//One time printing
	for (ret = strtok(buf, p); ret != NULL; ret = strtok(NULL, p))
	{
		printf("%s\n", ret);
	}

	return 0;
}

Detailed explanation:
(1) The sep parameter is a string that defines the set of characters used as delimiters
(2) The first parameter specifies a string that contains 0 or more tags separated by one or more separators in the sep string.
(3) The strtok function finds the next tag in str, ends it with \ 0, and returns a pointer to this tag.
(Note: the strtok function will change the string to be manipulated, so the string segmented by the strtok function is generally a temporary copy of the content and can be modified.)
(4) The first parameter of the strtok function is not NULL), the function will find the first tag in str, and the strtok function will save its position in the string.
(5) The first parameter of strtok function is NULL), and the function will start at the position saved in the same string to find the next tag.
(6) A NULL pointer is returned if there are no more tags in the string.

10, strerror

char* strerror(int errnum);
Header file: string h
Function name: strerror
Function parameter: errnum, int type, indicating the error code number
Function return type: char *, which returns the error information corresponding to the error code
Function function: Get a system error message(strerror) or prints a user - supplied error
message(_strerror). Return the error information of the system (that is, use this function to return the reason information of the error when the program makes an error)

Error code --- the corresponding error information.

In actual use, the error code is not controlled by us, but receives the error information returned by the system

printf("%s\n", strerror(errno));
//errno is a global error code variable
//When an error occurs in the execution of the library function of C language, the corresponding error code will be assigned to errno
//Errno needs to reference the header file errno h

Examples of actual use:
Open file

#include<stdio.h>
#include<errno.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	//There is no test in the current path Txt file, so it should fail to open the file
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
	}
	else
	{
		printf("Open file success!\n");
	}
	return 0;
}

perror: printing error information directly is equivalent to two steps:
1. First convert the error code into error information
2. Print error information (including user-defined information)
Use: perror("fopen");
Header file: stdio H no active parameter transmission is required
strerror: convert the error code into error information. If you want to print, you need to use the printing function, such as printf, etc

Character classification function:

Character conversion function:


give an example:
Capital letter to lowercase

#include <stdio.h>
#include <ctype.h>
int main()
{
	int i = 0;
	char str[] = "Test string. \n";
	char c;
	while (str[i])
	{
		c = str[i];
		if (isupper(c))
			c = tolower(c);
		putchar(c);
		i++;
	}
	return 0;
}

Memory function

11, memcpy

In the previous study, we know that strcpy function can be used for string copying, but can we still use strcpy function when the data we copy is not string, such as int type and double type? Strcpy function takes \ 0 as the end flag of string copy when copying. When copying other types of data, there may not be \ 0 at the end of copying. So using strcpy function is definitely not feasible. Then what shall I do? In fact, we can use memcpy function - memory copy function to copy any type of data.
give an example:

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[] = { 0,1,2,3,4 };
	int arr2[5] = { 0 };
	memcpy(arr2, arr1, sizeof(arr1));
	return 0;
}

Before copying:

After copying:

Algorithm analysis + illustration:

The memcpy function can copy any type of data. Why? First, let's think about the memory state corresponding to the actual use of different types of function parameters? For example, if the data of char type is to be copied, should it be copied one byte by one according to the length (1) of char type. If you want to copy int type data, should you also copy it in 4 bytes and 4 bytes according to the length of int type (4) What if it's a double type, 8 bytes? What about the structure?

Obviously, if we think in this way, we will fall into the experience trap. In fact, if we jump out and consider that any type of data is an integer multiple of one byte (1 to N times, n is a positive integer greater than or equal to 1). If we do not consider the type of data, we copy it one byte by one byte, Finally, no matter what type of data can be copied successfully. (at this time, some students may consider that since you can copy one byte by one byte, why not copy one bit by one bit? Answer: 1. It's not necessary. Copying in bytes can meet our needs. If you want to copy in smaller bits, it will only lead to an unwarranted increase in the number of program execution. 2. It's inconvenient to operate. Use words Copying in sections can be operated by converting pointer coercion type to char *. What about in bits? How to operate, isn't it troublesome!)

Function introduction: memcpy void* memcpy(void* dest, const void* src, size_t count);
Header file: string h
Function name: memcpy
Function parameters:
Parameter 1: destination, type: char *, indicating the destination of memory copy
Parameter 2: source, type: char *, indicating the starting position of memory copy
Parameter 3: count, type: size_t. Indicates the number of bytes of copied memory
The return type of the function: void *, which is actually the starting position of the return destination
Function function: memory copy

Key contents:

(1) The function memcpy copies num bytes of data back to the memory location of destination from the location of source.
(2) This function will not stop when it encounters' \ 0 '.
(3) If there is any overlap between source and destination, the copied result is undefined.

Simulation Implementation of memcpy

#include<stdio.h>
#include<assert.h>
#include<string.h>

void* my_memcpy(void* dest, const char* src, size_t num)
{
	void* dest_start = dest;
	assert(dest && src);
	while (num--)
	{
		//*(char*)dest = *(char*)src;
		//dest = (char*)dest + 1;//++(char*)dest
		//src = (char*)src + 1;//++(char*)src
		*((char*)dest)++ = *((char*)src)++;
	}
	return dest_start;
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };

	my_memcpy(arr2, arr1, 20);
	return 0;
}

Note: the mencpy function should copy non overlapping memory, and the memmove function can copy overlapping memory
C language stipulates that menmcy can copy as long as it does not overlap, while memmcy in VS can copy both non overlap and overlap.
C language stipulates that the overlapping copy can be handled by memmove.

12, memmove

Suppose we have an integer array 1 2 3 4 5 6 7 8 9 10. If we want to copy the first five numbers to positions 3 - 8, that is:

Can we do it through memcpy? The following test shows:
Before execution:

After execution:

The result is: 1 2 1 2 1 2 1 8 9 10 is not what we want 1 2 1 2 3 4 5 8 9 10
Why?

From the method we just simulated to implement memcpy, we know that memcpy copies from front to back. If this place is copied from front to back, the data to be copied later will be overwritten at the beginning of the copy. For example, 3, put 1 to 3 at the beginning, 3 is overwritten. If you want to copy 3 later, when you take out the data from this location, you actually take out 1.
Since the copy method from the front to the back doesn't work, what about copying from the back to the front?

After analysis, it can be found that the back-to-front copy method is possible, and the data to be copied later will not be overwritten in advance.

However, if we copy 3 4 5 6 7 to 1 2 3 4 5, is the copy from front to back still feasible?
Is it found that the data will be overwritten in advance when copying from back to front. So at this time, we need to discuss the situation:

Case 1: if dest is on the right side of src, data will be overwritten in advance if the method is from back to front, so it can only be copied from front to back

Case 2: if dest is on the left of src and dest does not exceed src + num (the number of copied data, that is, the horizontal length of the purple box in the figure), if the data is overwritten in advance according to the front to back method, it can only be copied from back to front

Case 3: if dest > SRC + num (the number of copied data, that is, the horizontal length of the purple box in the figure), the data will not be overwritten in advance no matter from back to front or from front to back, so both methods are OK.

In order to facilitate our actual programming, we can combine case 2 and case 3 to get:

Function introduction: memmove void* memmove(void* dest, const void* src, size_t count);
Header file: string h
Function name: memmove
Function parameters:
Parameter 1: destination, type: char *, indicating the destination of memory movement
Parameter 2: source, type: char *, indicating the starting position of memory movement
Parameter 3: count, type: size_t. Indicates the number of bytes of memory moved
The return type of the function: void *, which is actually the starting position of the return destination
Function function: memory movement

Key content

(1) The difference from memcpy is that the source memory block and target memory block processed by memmove function can overlap.
(2) If the source space and target space overlap, you have to use the memmove function.

Simulate the implementation of memmove function

#include<stdio.h>
#include<assert.h>
#include<string.h>

void* my_memmove(void* dest, const void* src, size_t num)
{
	void* dest_start = dest;
	assert(dest && src);
	if (dest < src)
	{
		//Copy from front to back
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		//Copy back to front
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return dest_start;
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };

	my_memmove(arr1 + 2, arr1, 20);
	return 0;
}

13, memcmp (simple understanding)

int memcmp(const void* buf1, const void* buf2, size_t count);

(1) Compare num bytes starting from ptr1 and ptr2 pointers
(2) The return values are as follows:


give an example:

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[4] = { 1,2,3,5 };
	int arr2[4] = { 1,2,3,4 };
	int ret = memcmp(arr1, arr2, sizeof(arr1));
	if (ret > 0)
	{
		printf("arr1 > arr2");
	}
	else if (ret == 0)
	{
		printf("arr1 == arr2");
	}
	else
	{
		printf("arr1 < arr2");
	}
	return 0;
}

14, menset (simple understanding)

Functions: Sets buffers to a specified character (set the buffer to the specified character)
void* memset(void* dest, int c, size_t count);

Relevant information:

Set memory in bytes

give an example:

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "abcdefg";
	memset(arr, '*', 4);
	printf("%s", arr);
	return 0;
}

Topics: C string