Ten thousand words will give you a detailed explanation of C language character function, string function and memory function

🍳 preface

C language processes characters and strings frequently, but C language itself has no string type. Strings are usually placed in constant strings or character arrays.

1, Find string length

💦 strlen

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abc";
	char arr2[] = { 'a', 'b', 'c' };
	printf("arr1 The length of the is:%d\n", strlen(arr1));
	printf("arr2 The length of the is:%d\n", strlen(arr2));
	return 0;
} 

⭕ Output result:

📝 Analysis results:
   ▶ A string of the type "abc" has 4 elements - > 'a', 'b', 'c' \ 0 '
   this shows that strlen calculates the characters before '\ 0' when calculating the length of the string, and takes' \ 0 'as the end flag of the string
   ▶ {'a', 'b', 'c'} This type of string has only three elements - > 'a', 'b', 'c'
   the result here is a random number. Because there is no '\ 0' as the end flag in the string, it will continue to count down

❓ Observe the following code and what is the output result

#include<string.h>
#include<stdio.h>
int main()
{
	if(strlen("abc") - strlen("abcdef") > 0)
	{
		printf(">\n");
	}
	else
	{
		printf("<\n");
	}
	return 0;
}

⭕ Output result:

📝 Analysis results:


The return value type of the strlen function is unsigned

💨 Summary:
▶ The string ends with '\ 0'. The return value of strlen function is the number of characters that appear before '\ 0' in the string (excluding '\ 0')
▶ The character pointed to by the parameter must end with '\ 0'
▶ Note that the return value of the function is size_t. Is unsigned (error prone)

2, String function with unlimited length

💦 strcpy

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

#include<stdio.h>
int main()
{
	char arr[20] = { 0 };
	strcpy(arr, "hello");
	printf("%s\n", arr);
	return 0;
}

⭕ Output result: hello
📝 Analysis result: strcpy will copy the contents of the source string to the target space and return the starting position of the target space

❓ Does strcpy end with '\ 0' during copying

📐 The verification is as follows

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = "##########";
	char arr2[] = "ab\0cdef";
	strcpy(arr1, arr2);
	return 0;
}

⭕ result:

📝 analysis:
strcpy is marked with '\ 0' when copying strings, and will also copy '\ 0'

❓ When the space of the original string to be copied is larger than that of the target string

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[5] = { 0 };
	char* p = "hello world";
	strcpy(arr, p);
	printf("%s\n", arr);
	return 0;
}

⭕ result:

❓ When the target space is a constant string

#include<stdio.h>
#include<string.h>
int main()
{
	char* str = "xxxxxxxxxx";
	char* p = "hello world";
	strcpy(str, p);
	printf("%s\n", str);
	return 0;
}

⭕ result:

💨 Summary:
▶ The source string must end with '\ 0'
▶ strcpy ends with '\ 0' during copying, and will also copy '\ 0'
▶ The destination space must be large enough to hold the source string
▶ The target space must be variable

💦 strcat

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

#include<stdio.h>
int main()
{
	char arr1[20] = "hello";
	char arr2[] = "bit";
	strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

⭕ Output result:

📝 Analysis results:
From the result, we can know that the source string will find the last '\ 0' of the target string when appending, overwrite it, and then start appending

❓ When the source string is appended to the target string, will the '\ 0' of the source string also be appended

📐 The verification is as follows

#include<stdio.h>
int main()
{
	char arr1[20] = "hello\0xxxxxxxxxx";
	char arr2[] = "bit";
	strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

⭕ result:

❓ Can strcat add to itself

#include<stdio.h>
int main()
{
	char arr[20] = "abcd";
	strcat(arr, arr);//?
	printf("%s\n", arr);
	return 0;
}

⭕ result:


📝 analysis:

💨 Summary:
▶ The source string must end with '\ 0'
▶ The target space must be large enough to hold the string
▶ The destination string must be modifiable
▶ You can't add yourself

💦 strcmp

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

❌ String comparison

#include<stdio.h>
#include<string.h>
int main()
{
	char* p1 = "def";
	char* p2 = "abc";
	if(p1 > p2)
		printf(">\n");
	else 
		printf("<\n");
	return 0;
}

📝 analysis:

✔ String comparison

#include<stdio.h>
#include<string.h>
int main()
{
	char* p1 = "def";
	char* p2 = "abcdef";
	printf("%d\n", strcmp(p1, p2));
	return 0;
}

📝 analysis:

3, String function with limited length

💦 strncpy

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = "abcdef";
	char arr2[] = "qwer";
	strncpy(arr1, arr2, 2);
	printf("%s\n", arr1);
	return 0;
}

⭕ result:

❓ When the specified number num is greater than the source string

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = "abcdef";
	char arr2[] = "qwe";
	strncpy(arr1, arr2, 6);
	printf("%s\n", arr1);
	return 0;
}

⭕ result:

💨 Summary:
▶ Copy num characters from source string to destination space
▶ If the length of the source string is less than num, after copying the source string, append 0 to the destination until num characters

💦 strncat

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

#include<stdio.h.>
#include<string.h>
int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";
	strncat(arr1, arr2, 3);
	printf("%s\n", arr1);
	return 0;
}

⭕ result:

❓ Can strncat add to itself

#include<stdio.h.>
#include<string.h>
int main()
{
	char arr1[20] = "hello";
	strncat(arr1, arr1, 6);
	printf("%s\n", arr1);
	return 0;
}

⭕ Results and analysis:

💦 strncmp

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

#include<stdio.h>
#include<string.h>
int main()
{
	char* p1 = "abcdef";
	char* p2 = "abcpdf";
	int ret = strncmp(p1, p2, 4);
	printf("%d\n", ret);
	return 0;
}

⭕ result:

4, String lookup

💦 strstr

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abcdefabcdef";
	char arr2[] = "bcd";
	char* ret = strstr(arr1, arr2);
	if(ret == NULL)
		printf("Can't find\n");
	else
		printf("eureka:%s\n", ret);
	return 0;
}

⭕ result:

📝 analysis:
strstr searches for substrings in the target string. If it is found, it returns the address of the source string that appears for the first time in the target string. Otherwise, it returns a null pointer

💦 strtok

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:


🔗 Function details:
▶ The strdelay parameter is a string that defines the set of characters used as delimiters
▶ strToken specifies a string that contains 0 or more tags separated by one or more separators in the strDelimit string
▶ The strtok function finds the next tag in strToken, 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)
▶ The first parameter of the strtok function is not NULL. The function will find the first tag in the strToken, and the strtok function will save its position in the string
▶ The first parameter of strtok function is NULL. The function will start at the position saved in the same string to find the next tag
▶ A NULL pointer is returned if there are no more tags in the string
▶ The strtok function is called once and will only be cut once. Therefore, if you want to cut multiple times, you need to call multiple times

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "wanghong@deboke.csdn";
	char* p = "@.";
	char temp[30] = { 0 };//Copy a copy of arr to temp and let temp cut it
	strcpy(temp, arr);
	char* ret = NULL;

	ret = strtok(temp, p);
	printf("%s\n", ret);
	
	ret = strtok(NULL, p);
	printf("%s\n", ret);
	
	ret = strtok(NULL, p);
	printf("%s\n", ret);
	
	return 0;
}

⭕ Results and analysis:

✔ But we usually use the loop to realize the operation of multiple segmentation. It's very wonderful!!!

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "wanghong@deboke.csdn";
	char* p = "@.";
	char temp[30] = { 0 };
	strcpy(temp, arr);
	char* ret = NULL;
	
	for(ret = strtok(temp, p); ret != NULL; ret = strtok(NULL, p))
	{
		printf("%s\n", ret);
	}
	return 0;
}

5, Error message report

💦 strerror

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

🔗 Function details:
The error code will be set when calling the library function fails
C language has a global error code - > int errno. As long as an error occurs in calling the library function, the error code will be put into errno
Here strerror will translate the error code into the corresponding error message, and then return the error message as the first address of the string
strerror is usually used with errno
Using errno requires the header file errno h

#include<stdio.h>
#include<string.h>
int main()
{
	printf("%s\n", strerror(0));
	printf("%s\n", strerror(1));
	printf("%s\n", strerror(2));
	printf("%s\n", strerror(3));
	printf("%s\n", strerror(4));
	printf("%s\n", strerror(5));
	return 0;
}

⭕ Results and analysis:

❓ How does it work
Note: the following functions for file operation will be understood later

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
	//Open test. As read Txt file. If this file does not exist, it will fail to open, and then return a null pointer
	FILE* pf = fopen("test.txt", "r");
	//If it fails, the reason for the failure and the error message will be output
	if(pf == NULL)
	{
		printf("%s\n", strerror(errno));								
		return 1;
	}
	//...
	fclose(pf);//Close file
	pf == NULL;
	
	return 0;
}

⭕ result:

💦 perror

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

#include<stdio.h>
#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if(pf == NULL)
	{
		perror("fopen");		
		return 1;
	}
	//...
	fclose(pf);
	pf == NULL;
	
	return 0;
}

⭕ Results and analysis:

6, Character manipulation function

1. Character classification function


🧿 Note: briefly introduce several functions, and others can follow suit

💦 isdigit

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

#include<stdio.h>
#include<ctype.h>
int main()
{
	char ch = '@';
	//If it is a numeric character, it returns a value other than 0; otherwise, it returns 0
	int ret = isdigit(ch);
	printf("%d\n", ret);
	return 0;
}

💦 islower

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

#include<stdio.h>
#include<ctype.h>
int main()
{
	char ch = 'A';
	//If it is a lowercase letter, it returns a value other than 0; otherwise, it returns 0
	int ret = islower(ch);
	printf("%d\n", ret);
	return 0;
}

2. Character conversion function

functionfunction
tolowerCapital to lowercase
toupperTurn lowercase to uppercase

💦 tolower

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

#include<stdio.h>
#include<ctype.h>
int main()
{
	char arr[20] = { 0 };
	scanf("%s", arr);
	int i = 0;
	while(arr[i] != '\0')
	{
		printf("%c ", tolower(arr[i]));
		i++;
	}
	return 0;
}

⭕ result:

7, Memory operation function

💦 memcpy

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	memcpy(arr2, arr1, 20);//Note that the unit of the third parameter is bytes
	return 0;
}

⭕ result:

❓ We notice that the first two parameters of memcpy are of void * type. Does that mean that it can copy different data

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = { 0 };
	memcpy(arr2, arr1, 6);
	printf("%s\n", arr2);
	return 0;
}

⭕ result:

❓ For strcpy function, if it encounters' \ 0 'when copying a string, it will stop copying. Then think about whether memcpy will also stop when it encounters' \ 0' when copying a string

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abc\0def";
	char arr2[20] = { 0 };
	memcpy(arr2, arr1, 6);
	printf("%s\n", arr2);
	return 0;
}

⭕ result:

Here is a scene ❓

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memcpy(arr1 + 2, arr1, 20);
	return 0;
}

⭕ Results and analysis:

💦 memmove

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr1 + 2, arr1, 20);
	return 0;
}

⭕ Results and analysis:

💦 memset

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

#include<stdio.h>
#include<string.h>
int main()
{
	int arr[10] = { 0 };
	memset(arr, 1, 20);
	return 0;
}

⭕ Results and analysis:

❓ Use memset to set the element of a 10 element array to 1

#include<stdio.h>
#include<string.h>
int main()
{
	int arr[10] = { 0 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		memset(&arr[i], 1, 1);
	}
	return 0;
}

⭕ result:

💦 memcmp

🔗 Function prototype and header:

🔗 Return value of function:

🔗 Function:

#include<stdio.h>
#include<string.h>
int main()
{
	float arr1[] = { 1.0, 2.0, 3.0, 4.0 };
	float arr2[] = { 1.0, 3.0 };
	int ret = memcmp(arr1, arr2, 8);//Note that the unit of the third parameter is bytes
	printf("%d\n", ret);
	return 0;
}

8, Simulation Implementation of function

💦 strlen

1. Version of the counter (temporary variable required)

#include<stdio.h>
int my_strlen(char* str)
{
	int count = 0;
	while(*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	char arr[] = "abc";
	int len = my_strlen(arr);
	printf("%d\n", len);
	return 0;
}

❗ Defects and deficiencies:
❌ In my_ It is not safe to dereference the pointer directly in the strlen function, because the pointer must be valid
❌ my_ The function of strlen is to find the length of the string, and this is my_ The strlen function has permission to change the contents of the string, so it is not safe
❌ my_ The return value of strlen function is int. if it returns a negative number, it may be forced on the spot
💯 optimization
✔ To use assert, you need the header file < assert h>
✔ Use const to restrict str
✔ Change the return value int of the function to size_t
✔ More concise optimization of the whole code

#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{
	assert(str != NULL);
	int count = 0;
	while (*str++)
		count++;
	return count;
}
int main()
{
	char arr[] = "abc";
	printf("%d\n", my_strlen(arr));
	return 0;
}

2. Recursive version (no temporary variables)

#include<stdio.h>
#include<assert.h>
int my_strlen(const char* str)
{
	assert(str);
	if(*str)
		return 1 + my_strlen(str+1);
	else 
		return 0;
}
int main()
{
	char arr[] = "abc";
	printf("%d\n", my_strlen(arr));
	return 0;
}

3. Pointer Version (pointer pointer)

Address of string length = '\ 0' - address of the first element

#include<stdio.h>
#include<assert.h>
int my_strlen(char* first, char* end)
{
	assert(first);
	assert(end);
	return end - first;
}
int main()
{
	char arr[] = "abc";
	int left = 0;
	int right = sizeof(arr)/sizeof(arr[0]) - 1;
	printf("%d\n", my_strlen(&arr[left], &arr[right]));
	return 0;
}

💦 strcpy

#include<stdio.h>
#include<assert.h>
void my_strcpy(char* dest, char* src)
{
	while(*src != 0)
	{
		*dest = *src;
		dest++;
		src++;
	}
	src = 0;//Copy the last element of str1 to 0
}
int main()
{
	char arr1[20] = { 0 };
	char arr2[] = "hello bit";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

❗ Defects and deficiencies:
❌ In my_ It is not safe to dereference the pointer directly in the strcpy function, because the pointer must be valid
❌ For my_ The two parameters of strcpy function are the target string and the source string. The target string must be modifiable, but the source string cannot be modified
❌ Here is to copy characters other than '\ 0' first and then '\ 0'
❌ The return value of this function is void and char * in the library. It returns the first address of the target string:

💯 optimization
✔ To use assert, you need the header file < assert h>
✔ Use const to restrict str2
✔ Copy '\ 0' with other characters
✔ Set the return value of the function to char*

#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
	assert(dest);
	assert(src);
	char* temp = dest;//Back up a first address
	while (*dest++ = *src++)
	{
		;
	}
	return temp;//Returns the first address of the backup 
}
int main()
{
	char arr1[20] = { 0 };
	char arr2[] = "hello bit";
	printf("%s\n", my_strcpy(arr1, arr2));
	return 0;
}

💦 strcat

#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	char* temp = dest;//Back up a first address 
	//Found '\ 0' in target string
	while(*dest)
	{
		dest++;
	}
	while(*dest++ = *src++)
	{
		;
	}
	
	return temp;//Return to first address 
}
int main()
{
	char arr1[20] = "hello";
	char arr2[] = "bit";
	printf("%s\n", my_strcat(arr1, arr2));
	return 0;
}

💦 strstr

#include<stdio.h>
#include<assert.h>
char* my_strstr(const char* father, const char* son)
{
	assert(father && son);
	const char* f1 = NULL;						
	const char* s2 = NULL;
	const char* ret = father; 
		
	while(*ret)
	{
		f1 = ret;
		s2 = son;
		if(*son == '\0')
		{
			return (char*)father;
		}
		while(*f1 && *s2 && (*f1 == *s2))
		{
			f1++;
			s2++;	
		}
		if(*s2 == '\0')
		{
			return (char*)ret;
		}
		ret++;
	}
	return NULL;
}
int main()
{
	char arr1[] = "abbbcdef";
	char arr2[] = "bbc";
	char* ret = my_strstr(arr1, arr2);
	if(ret == NULL)
	{
		printf("Can't find\n");
	}		
	else
	{
		printf("eureka:%s\n", ret);
	}
	return 0;
}

⭕ analysis:

▶ Considering that if the search fails, it is not necessarily that the substring cannot be found, so the substring cannot be found until * father == ' father = = '\ 0''
▶ We need to define two pointers F1 (pointing to the first address of father) and S2 (pointing to the first address of son) to help us match down
▶ If the match fails, the pointer will return to the place to return
For s2: s2 = son
For f1: another pointer RET (pointing to the first address of fther) is needed to record. Every time the matching fails, let RET + +, and then f1 = ret

🍳 Expansion: KMP algorithm - string search algorithm - you can learn about it

💦 strcmp

#include<stdio.h>
#include<assert.h>
int my_strcmp1(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while(1)
	{
		if(*str1 > *str2)
			return 1;
		else if(*str1 < *str2)
			return -1;
		else
		{
			if(*str1 == *str2 && *str1 == '\0')
				return 0;
			else
			{
				str1++;
				str2++;	
			}
		}	
	}
}
int my_strcmp2(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while(*str1 == *str2)
	{
		if(*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}	
	if(*str1 > *str2)
		return 1;
	else
		return -1;
}
	
int main()
{
	char* p1 = "def";
	char* p2 = "abcdef";
	//int ret = my_strcmp1(p1, p2);// Version 1
	int ret = my_strcmp2(p1, p2);//Version 2
	if(ret > 0)
		printf("p1 > p2\n");
	else if (ret < 0)
		printf("p1 < p2\n");
	else 
		printf("p1 = p2\n");
	return 0;
}

⭕ Optimize redundancy:

#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while(*str1 == * str2)
	{
		if(*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;
}
int main()
{
	char* p1 = "def";
	char* p2 = "abcdef";
	int ret = my_strcmp(p1, p2);
	if(ret > 0)
		printf("p1 > p2\n");
	else if (ret < 0)
		printf("p1 < p2\n");
	else 
		printf("p1 = p2\n");
	return 0;
}

💦 memcpy

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

❗ be careful:

❓ my_ Can memcpy copy overlapping memory space

#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;
	while(num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memcpy(arr1 + 2, arr1, 20);
}

⭕ result:

💦 memmove

❓ I believe all my friends are curious about how memmove handles memory overlap
🔎 Analyze a wave

#include<stdio.h>
#include<assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;
	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 ret;
}	
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1 + 2, arr1, 20);
	return 0;
}

Keywords: C

Added by BhA on Mon, 31 Jan 2022 22:33:25 +0200