How can you be proficient in C language if you don't know these string operations? How to play with C++?

Hello everyone, I am KookNut39. I write an article on CSDN and share some things that I think are more important in the learning process. I am committed to helping beginners get started, and I hope to help you progress. I have recently updated the knowledge of C/C++. If you are interested, please follow the bloggers. You can go to the column to view the previous articles. I hope to discuss the technology with you in the future.

For students who are learning C language or C++, if they are not familiar with string manipulation, they cannot go further in the learning process, because this is a very basic and very important link. I hope the blogger will read this article Examples, can teach you how to handle string operations! For beginners, it is difficult to remember so many things at once, so [Recommended collection], it is convenient to find when you use it in the future.
Newly learned how to make animated pictures. The previous demonstrations were all dry screenshots. Today I inserted a new animated picture. It feels very cool, hhhhhhhhhhh. If you like the article, support the blogger Ou 🤞🤞🤞 with one click and three links ! ! !

Article Directory


Not much nonsense, let's get to the point. String manipulation is almost the place where we will encounter confusion in the process of learning C or C++. We can't get the output result we want, or we get it, but we don't get it completely . For example, we get the string we want, but then some garbled characters will be output. Similar to the situation shown in the figure:

Insert picture description here


then how should we fix these string manipulation bugs? Let's discuss in detail next:
For a string array or char pointer, we must initialize it, because if it is not initialized, there are some default initialized values, which can be considered as some "garbage" data, then Let's first introduce our first function:

1. Memory initialization memset

I generally use the memset function to initialize the dynamically requested memory, because if it is the stack area memory, we usually initialize it at the same time as the variable declaration, so we need to manually initialize the memory requested in the heap area. Let's take a look at the declaration of the function:

void *
memset (
   	 	void            *Dest,
    	int              Value,
    	ACPI_SIZE        Count)

From the function declaration, there are a total of three parameters, let's explain these three parameters:

void   *Dest:这是我们要进行初始化的指针,在这里被默认为void*指针
int    Value:一个int型变量,也就是我们需要给这片内存初始化的值,一般传0
ACPI_SIZE  Count:这是我们需要初始化的内存长度,一般是和申请内存的大小相同

We generally initialize a piece of requested memory to 0 before use for subsequent use. Special note : memset is not only for string pointers, other pointers can also be used . Let's look at a simple usage example:

	//对于栈区内存,我们在申请到的时候,就对其初始化
	char Des[15] = { 0 };
	
	//堆区内存,我们申请到之后,使用memset初始化为0
	char* ptr1 = (char*)malloc(15);
	memset(ptr1, 0, 15);//将我们申请到的15个字节初始化为0

For the initialization of the stack area memory , let's take a look at this picture:

Insert picture description here


For the heap area memory initialization , let's look at the effect of the initialization execution:

Insert picture description here

2. String length calculation strlen

What is the calculation of the length of a string used for? Maybe it will be used when copying strings, or to calculate how many characters are entered? Anyway, anyway, this is a very general string manipulation function, take a look at its declaration:

ACPI_SIZE
strlen (
    const char     *String)

We can see that the return value is a numeric type, and this function has only one parameter, which is somewhat perfunctory. . . But the process still has to go, so let's take a look at the meaning of the parameters:

const char   *String:特别注意是一个const char*。有关这个的概念,
在我之前讲C语言指针的时候讲过,意思就是字符串内容不允许修改,这是肯定的,我们传入字符串指针是为了让它计算长度,肯定不能被修改。

In fact, the implementation of strlen is very simple. It applies a local variable internally for counting, and then uses a while loop to judge. If the string is not'\0', then the pointer will move back and the counter is ++, otherwise, the character After the string length calculation is over, the value of this counter variable is returned.
Now let's use it to calculate the length of a string and take a look:

	//初始化为HelloWorld
	char Des[] = "HelloWorld";//注意这是11个字节,因为还有 \0 结尾
	//计算字符串的长度
	size_t StringLength = strlen(Des);
	return 0;

The result of calculating this string:

Insert picture description here


From the above figure, we should be able to see two problems. First, we initialized the Des string by default, which contains 11 characters, but in the end we found that the calculated StringLength only counted 10, for this reason It is because when strlen is implemented, the length of \0 is not calculated, so you need to pay attention : The length of the string calculated by strlen does not include \0 . This must be remembered, and it will be often used in the process of writing code in the future.

3. String copy strcpy

When we want to copy a source string to a backup, we still have string manipulation functions that can be used, and we can also expect that if we want to implement a copy operation, at least the source string And the target string, so that it can be said to be a copy, let's talk about the strcpy function first, let's take a look at its declaration first:

char *
strcpy (
    	char           *DstString,
    	const char     *SrcString)

We see that the return value of this function is a char pointer, but we generally don’t take its return value, because DstString points to the string value we want to return when passing parameters. Let’s take a look at these two parameters. What do they represent:

char  *DstString:目标字符串指针,需要拷贝到的地方
const char  *SrcString:源字符串指针,被拷贝的对象

Take a look at an example of use:

	//对于栈区内存,我们在申请到的时候,就对其初始化
	char SrcString[] = "HelloWorld";
	//堆区内存,15个字节的长度
	char* DstString = (char*)malloc(15);
	memset(DstString, 0, 15);//将我们申请到的15个字节初始化为0
	strcpy(DstString, SrcString);

Let's take a look at the effect of copying strings:

Insert picture description here


When using strcpy, you need to pay attention : that is the application for the target memory length, because when strlen calculated the length before, the end of the string was not counted as null, so apply When the memory is used, one more byte is required to store the end character of the string. This is because when strcpy is implemented internally, after the end of the string copy, there will be no \0 at the end of DstString, which is a null character to end, which requires one byte.

4. String copy memcpy

In the process of using strcpy, we found that we can only control the stop of the copy operation according to the null character end of the string, which seems a bit passive, then can we become proactive? Of course it is possible. The memcpy we will introduce next can control our control of the copy length:

void *
memcpy (
    	void               *Dest,
    	const void         *Src,
    	ACPI_SIZE          Count)

Let's take a look at the detailed meaning of each parameter:

void         *Dest:需要拷贝到的目标指针首地址
const void   *Src:被拷贝的指针首地址
ACPI_SIZE    Count:当前指针类型被拷贝的个数

For example, if we point to copy 5 characters from the source string, then we only need to pass the third parameter to 5 and it will be OK. Take a look at the following example:

	//对于栈区内存,我们在申请到的时候,就对其初始化
	char SrcString[] = "HelloWorld";
	
	//堆区内存,15个字节的长度
	char* DstString = (char*)malloc(15);
	memset(DstString, 0, 15);//将我们申请到的15个字节初始化为0

	//我们只想复制前五个字节 Hello,所以这样写
	memcpy(DstString, SrcString,5);

We can use memcpy to copy only Hello, but we cannot use strcpy to achieve this effect:

Insert picture description here


but this function will not be like strcpy. After the copy is completed, \0 is added as the end, because it is not only for string operations, so it is not Will add \0 to the end by default.
For this function, we must pay attention , it is not only for the operation of the string series, we can see from the parameter type, it is not the same as the str series of functions, the str series are all char type parameters, the parameters of this function They are all void parameters, so whatever type it means, it can be accepted. In fact, not only the current function, all mem series functions are not only for string operations .

5. String copy memmove

Okay, here we come to ask a new question, because some classmates like to play, and the current situation in various fields is serious. Of course, the string copy should also help the field. If we want to realize a copy of ourselves, then we What function is used? What is the effect if I use memcpy? I remember the memory overlap problem that has been talked about by everyone a long time ago. Memcpy is a typical example, but because I haven't tested it for a long time, when I tested it today, I actually found that the memory overlap problem of memcpy was solved ? ?

	//对于栈区内存,我们在申请到的时候,就对其初始化
	char SrcString[] = "HelloWorld";

	//我希望拷贝HelloWorld 中的前8个字节给字符串本身
	//也就是我希望拷贝之后字符串变为HeHelloWor 
	//但是我预计它会出现HeHeHeHeHe的情况
	memcpy(SrcString + 2, SrcString, 8);

Originally, I expected that I would do it myself, and then memory overlap would occur, output HeHeHeHeHe, and then lead memmove to solve this problem, but I didn't expect it. . . Does it actually work? ? In other words, the result was output correctly:

Insert picture description here


I was speechless . I didn't expect Microsoft to solve this problem, but I didn't know it! ! ! But, I am definitely not reconciled, I have to tell you how it was implemented before:

void *
my_memcpy(
	void                    *Dest,
	const void              *Src,
	size_t               Count)
{
	char                    *New = (char *)Dest;
	char                    *Old = (char *)Src;
	while (Count)
	{
		*New = *Old;
		New++;
		Old++;
		Count--;
	}

	return (Dest);
}

This is its original implementation logic, and according to the implementation logic of this function, let's test it again:

Insert picture description here


OK! ! nice! It has achieved the effect of the wrong demonstration that I want, and it is indeed achieved in this way before!

Insert picture description here

Next, let's "it is logical" to elicit our protagonist memmove! Let's take a look at the statement first:

void *
memmove (
    	void           *Dest,
    	const void     *Src,
    	ACPI_SIZE      Count)

We won’t explain the three parameters of this function, because these three parameters are the same as the three parameters of memcpy, so let’s take a look at the usage examples and renderings:

Insert picture description here


here is the implementation of this memmove. Logic to help everyone better understand why memory overlap can be avoided:

void *
memmove (
    void                    *Dest,
    const void              *Src,
    ACPI_SIZE               Count)
{
    char                    *New = (char *) Dest;
    char                    *Old = (char *) Src;
	//在这里对于两个地址的大小进行了比较,用来确定该如何去复制
    if (Old > New)
    {
        /*从头部复制*/
        while (Count)
        {
            *New = *Old;
            New++;
            Old++;
            Count--;
        }
    }
    else if (Old < New)
    {
        /*从尾部开始复制*/
        New = New + Count - 1;
        Old = Old + Count - 1;
        while (Count)
        {
            *New = *Old;
            New--;
            Old--;
            Count--;
        }
    }
    return (Dest);
}

6. String comparison strcmp

When two strings appear, sometimes we need to compare whether the two strings are the same, or to see where they are different, then we use the strcmp function:

int
strcmp (
    	const char     *String1,
   		const char     *String2)

The return value of this function is what we need to pay attention to, and its two parameters are easy to understand:

返回值:如果两个字符串相等,返回0,若String1>String2则返回 1,若String1<String2,则返回 -1
const char     *String1:第一个需要比较的字符串
const char     *String2:第二个需要比较的字符串

This function is relatively easy to understand, let's look at a small example:

	//初始化为HelloWorld
	char String1[] = "HelloWorld";
	//初始化为HelloChina
	char String2[] = "HelloChina";
	//预期返回1
	int index = strcmp(String1, String2);

The method of comparison is to start from the first character of the two incoming pointers, and then the comparison standard is based on the ASCII value. For example,'W' is greater than'C', and this is compared according to the ASCII table. In the above code, we expect the index value to be 1:

Insert picture description here

7. String comparison memcmp

When we use strcmp to compare, there is also a downside, that is, we cannot control the length of the comparison string. It is more comfortable to control the length of the string by ourselves. After all, sometimes it does not need to be too long. Now that we are provided with a chance, what are you still doing? Let’s take a look at memcmp:

int __cdecl 
memcmp(
		const void *s1, 
		const void *s2, 
		size_t n)

We have said that the mem series of functions are not only for strings, but we can see from its parameters. What do these three parameters mean? In fact, it is similar to memcpy:

返回值:如果两个字符串相等,返回0,若String1>String2则返回 1,若String1<String2,则返回 -1
void         *s1:第一个需要比较的指针地址
const void   *s2:第二个需要比较的指针地址
size_t 		 n:比较的个数

Its return value is the same as strcmp, 0, -1 or 1. For us, we want to compare the first 5 bytes of the two strings, because the first 5 characters are the same, let’s take a look effect:

	//初始化为HelloWorld
	char String1[] = "HelloWorld";
	//初始化为HelloChina
	char String2[] = "HelloChina";
	//预期输出0
	int index = memcmp(String1, String2, 5);
Insert picture description here


For the above two string comparison functions, this requires us to measure, when to use which, if we need to compare two complete strings, we can choose to use strcmp, if we compare part of the two strings, then we You can use memcmp.

8. String splicing strcat

We always hope that we can have the opportunity to change ourselves. Why shouldn't strings be like this? ? It may also want to become powerful and indestructible, but it has no way to settle itself, and finally, it waits for the arrival of the strcat function:

char *
strcat (
    	char           *DstString,
    	const char     *SrcString)

We can see that the two parameters of this function are the same as those of strcpy. The first parameter is a char pointer, and the second parameter is a const char* pointer, which means that the string pointed to by the second parameter is not allowed to be modified. :

char  *DstString:目标字符串指针,需要拼接到的目标字符串地址
const char  *SrcString:源字符串指针,拼接在DstString之后

The return value is a pointer that points to the first address of the target string. Let's see if we can smoothly transform the string after splicing, how about a strong self?

	//初始化为Hello
	char String1[] = "Hello";
	//初始化为KookNut39
	char String2[] = "KookNut39";
	//预期最终String1变为HelloKookNut39
	strcat(String1, String2);
Insert picture description here


But ! ! ! It must be said that this is wrong. This is a stack area memory. We only have 6 bytes of space. Now after adding this string, it is obvious that the stack area memory is out of bounds! ! ! This is definitely not allowed.
If you want to strengthen yourself, this is correct, but it depends on whether it has this ability, so we now need to let it have the ability to strengthen itself first, that is, it has enough memory space! !

	//动态申请20个字节,并且初始化为0
	char* String1 = (char*)malloc(20);
	memset(String1, 0, 20);
	//修改String1为Hello
	strcpy(String1, "Hello");
	//初始化为KookNut39
	char String2[] = "KookNut39";
	//预期最终String1变为HelloKookNut39
	strcat(String1, String2);

With a slight modification, dynamically apply for memory, so that we have enough memory space to store the added string, the result is as follows:

Insert picture description here

9. Search for the character strchr in the string

Searching for specific characters in a string is also a small function we may use. In fact, this function is much simpler than the previous functions. Let's take a look at the declaration of this function:

char *
strchr (
    	const char    *String,
    	int           ch)

For the two parameters and return value, we understand it this way:

返回值,当字符ch与源串String第一次匹配的时候的地址,如果串中所有字符都不匹配,那么返回NULL地址
const char    *String:源串,匹配的来源
int           ch:目标字符,用在再源串中匹配的

We write a simple small example to end the explanation of this function, we involve two cases of successful matching and unsuccessful matching:

	char String1[] = "KookNut39";
	//字符串中没有 Y 预期返回NULL
	char* ptr1 = strchr(String1, 'Y');
	//预期返回 N 第一次出现的地址
	char* ptr2 = strchr(String1, 'N');

Take a look at the results:

Insert picture description here

10. Search for substring strstr in a string

Can search and match the specified character in the string? So if I want to search for a string, is there any way to achieve it? Of course, you can find the position of the substring in the string by directly coming to a strstr:

char *
strstr (
    	const char     *String1,
   		const char     *String2)

Let's take a look at the specific meaning of these parameters in this string:

返回值:如果String2是String1的子串,那么返回第一次匹配的地址,否则返回NULL
const char     *String1:目标字符串
const char     *String2:需要在目标串中寻找的子串

We are still the same. Here we perform two tests for the matched substring and the unmatched substring to see if the return value meets our expectations:

	//初始化为HelloKookNut39
	char String1[] = "HelloKookNut39";
	//寻找我的名字KookNut39
	char String2[] = "KookNut39";
	//预期返回第一次匹配到的地址
	char* ptr1 = strstr(String1, String2);
	//预期返回NULL
	ptr1 = strstr(String1, "Kt39");
	return 0;
Insert picture description here
This concludes the introduction of commonly used string manipulation functions. It is better to teach people how to fish than to teach people how to fish. I think this sentence is always okay. Here I hope that by introducing a simple example of use to everyone, I can Let everyone be comfortable with string manipulation in the future learning days! ! If this blog post can be helpful to your study, please give the blogger a like + comment + favorite to provide motivation for the blogger to continue to create, thank you!

Today I share my encouragement with you: "When autumn comes on September 8th, I will kill a hundred flowers after the flowers bloom."

Insert picture description here