Detailed explanation of C language - string and memory functions

Characters and strings are processed very frequently in C language, but C language itself does not have a string type. Strings are usually placed in
In constant strings or character arrays, string constants are suitable for string functions that do not modify it, which means that you can safely pass string constants to functions that do not try to modify their parameters.

1. Find the length of the string

  • strlen

 size_t strlen ( const char * str ); 

strlenis a library function used to calculate the length of a given string. It is <string.h>defined in the header file. strlenThe function accepts a pointer to a character array (a string) as argument and returns a size_tvalue of type representing the length of the string (excluding the terminating null character).

The end mark of the string is ' \0 ', and the strlen function returns the number of characters that appear before ' \0 ' in the string (excluding ' \0 ').

 example:

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

int main ()
{
  char szInput[256];
  printf ("Enter a sentence: ");
  gets (szInput);
  printf ("The sentence entered is %u characters long.\n",(unsigned)strlen(szInput));
  return 0;
}

Return results: 

 Simulation implementation:

size_t my_strlen(const char* str)
{
	int count = 0;
	while (*str++) {
		count++;
	}
	return count;
}

int main()
{
	size_t sz = my_strlen("aasaad");
	printf("%d\n", sz);
	return 0;
}

2. String functions with unlimited length

  • strcpy

char *strcpy(char *dest, const char *src);

strcpy Is a library function used to copy one string to another string. It is  <string.h> defined in the header file. strcpy The function accepts two parameters: a pointer to the destination character array and a pointer to the source string. It copies the source string to the destination character array and returns a pointer to the destination character array.

Notice! !

  • The source string must end with '\0' .
  • '\0' in the source string will be copied to the target space.
  • The target space must be large enough to accommodate the source string.
  • The target space must be variable.

 example:

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

int main() {
    char source[] = "Hello, World!";
    char destination[50];

    strcpy(destination, source);

    printf("Source: %s\n", source);
    printf("Destination: %s\n", destination);

    return 0;
}

 

 Simulation implementation: 

char* my_strcpy(char* dest, char* src)
{
	char* ret = dest;
	while (*dest++ = *src++);
	return ret;
}

  • screwed up

char *strcat(char *dest, const char *src); 

strcat is a library function used to append one string to the end of another string. It is defined in the <string.h> header file. strcat accepts two parameters, a pointer to the target character array and a source A pointer to a string that appends the source string to the end of the target string array and returns the characters of the target character array.

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

int main() {
    char destination[50] = "Hello";
    char source[] = ", World!";

    strcat(destination, source);

    printf("Combined string: %s\n", destination);

    return 0;
}

 

  • The source string must end with '\0' .
  • The target space must be large enough to accommodate the contents of the source string.
  • The target space must be modifiable.

 Simulation implementation: 

char* my_strcat(char* dest, char* src)
{
	assert(dest && src);
	char* ret = dest;
	while (*dest)
		dest++;
	while (*dest++ = *src++);
	return ret;
}

If you use a simulation function, you cannot append yourself , because the target string array and the source string array are the same, that is, after the first while loop, dest points to the last bit of the string '\0', and src equals dest and also points to the character The last bit of the string is '\0', so appending cannot be performed in the second while loop. 

If you use the string function strcat, you can append yourself as long as the target space is large enough. 

The assert here ensures the following two points:

  1. dest No.  NULL_
  2. src No.  NULL_

If either condition is not met (i.e., if   or yes dest  ),  an error message is triggered and the program is terminated. This is to prevent subsequent code from operating on an invalid pointer, potentially causing undefined behavior or program crashes.srcNULLassert

  • assert :

  •  In C programming, assert is a macro used to set assertions in a program. If the assertion fails (i.e., the expression is false), assertan error handling routine is called and usually terminates program execution. 
  •  assert The macro is used to ensure that the two string pointers passed to the function  dest and  src are neither  NULL.
  • assert Macros  <assert.h>are defined in header files.
  • strcmp

int strcmp(const char *str1, const char *str2); 

 strcmp) is a library function used to compare two strings. This function is <string.h>defined in the header file. strcmpThe function accepts two strings (character pointers) as parameters and returns an integer representing the relative order of the two strings.

  • If the first string is greater than the second string, a number greater than 0 is returned.
  • If the first string is equal to the second string, 0 is returned
  • If the first string is less than the second string, a number less than 0 is returned.
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()
{
	int ret = my_strcmp("bbq", "bbb");	
	if (ret > 0)
		printf("大于\n");
	else if (ret < 0)
		printf("小于\n");
	else
		printf("等于\n");

	return 0;
}

  Simulation implementation: 

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;
}

3. Introduction to string functions with limited length

  • strncpy

char * strncpy ( char * destination, const char * source, size_t num );

  • Copy num characters from the source string to the destination space.
  • If the length of the source string is less than num , after copying the source string, append 0 to the end of the target until num .
#include <stdio.h>
#include <string.h>
int main()
{
    char str1[20];
    char str2[20];
    strcpy(str1, "To be ");
    strcpy(str2, "or not to be");
    strncpy(str2, str1, 10);
    puts(str2);
    return 0;
}

 In this program, strncpy the function is used to  str1 copy the contents of into  str2 , but only up to 10 characters are copied.

Although the output result is   , the part that exceeds the length of the string is assigned a value of \0.

  • strncat

char * strncat ( char * destination, const char * source, size_t num );

  • Appends the first to num characters of the  source character to the end of the target space, plus a terminating null character  '\0' .
  • If the length of the C string in source characters is less than num, only the contents up to the terminating null character are copied.
  • strncmp

  • int strncmp ( const char * str1, const char * str2, size_t num );
  • strncmp is used to compare the first  num character of two strings.

4. String search

  • strstr

char * strstr ( const char *str1, const char * str2);

  • strstr returns a pointer to the first occurrence of str2 in str1
  • If str2 is not part of str1, a null pointer is returned.

Let’s look at two examples below: 

#include <stdio.h>
#include <string.h>
int main()
{
    char str[] = "This is a simple string";
    char* pch;
    pch = strstr(str, "simple");
    printf("%s\n", pch);
    strncpy(pch, "sample", 6);
    puts(str);
    return 0;
}

Output result: 

 


#include <stdio.h>
#include <string.h>
int main()
{
    char str[] = "This is a simple string";
    char* pch;
    pch = strstr(str, "smple");
    printf("%s\n", pch);
    return 0;
}

 Output result: 

 

Simulation implementation: 

char* my_strstr(char* str1, char* str2)
{
	char* s1 = str1;
	char* cp = str1;
	char* s2 = str2;
	if (*str2 == '\0')
		return str1;
	while (*cp) {
		s1 = cp;
		s2 = str2;
		while (*s1 == *s2 && *s1 && *s2) {
			s1++;
			s2++;
		}
		if (*s2 == '\0')
			return cp;
		cp++;
	}
	return NULL;
}

int main()
{
	char arr1[] = "abbbcdef";
	char arr2[] = "bbc";
	return 0;
}

  • strtok

char * strtok ( char * str, const char * sep );

  • The sep parameter is a string that defines the set of characters used as separators.
  • The first parameter specifies a string containing zero or more tokens separated by one or more delimiters in the sep string.

  • The strtok function finds the next token in str , terminates it with \0, and returns a pointer to this token. (Note: The strtok function will change the manipulated string, so the string split using the strtok function is generally a temporary copy and can be modified.)
  • The first parameter of the strtok function is not NULL , the function will find the first token in str , and the strtok function will save its position in the string.
  • The first parameter of the strtok function is NULL , and the function will start at the saved position in the same string and find the next token.
  • If no more tokens exist in the string, a NULL pointer is returned.
#include <stdio.h>
#include <string.h>

int main()
{
	char arr[] = "[email protected]@666#777";
	char copy[30];
	strcpy(copy, arr);

	char sep[] = "@.#";
	char* ret = NULL;

	for (ret = strtok(copy, sep); ret != NULL; ret = strtok(NULL, sep))
	{
		printf("%s\n", ret);
	}

	return 0;
}

5. Error message report

  • strerror

char * strerror ( int errnum );  

When an error occurs when a library function is executed, an error code will be stored in the variable errno. errno is a global variable provided by the C language. Enter the error code and corresponding error message.

int main()
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d: %s\n", i, strerror(i));//
	}
	return 0;
}

 

 What is the use of strerror? 

int main()
{
	//C语言中可以操作文件
	//操作文件的步骤
	//1. 打开文件
	//2. 读/写
	//3. 关闭文件

	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		printf("fopen: %s\n", strerror(errno));
		//通过错误码知道打印失败的原因。
        perror("fopen"); 
		return 1;
	}
	//读文件
	//...
	//关闭文件
	fclose(pf);

	return 0;
}

You can replace printf("fopen: %s\n", strerror(errno)); with perror("fopen"); and their output results will be the same.

perror is more powerful, it first prints fopen: plus error information.

The result is as follows:

6. Character classification function 

The #include <ctype.h> header file needs to be included  .

int main()
{
	printf("%d\n", isupper('a'));
	printf("%d\n", isdigit('2'));
	printf("%c\n", tolower('A'));
	printf("%c\n", tolower('s'));
	return 0;
}

 Output result:

int main()
{
	char arr[20] = { 0 };
	gets(arr);//遇到空格继续读
	char* p = arr;
	while (*p)
	{
		if (isupper(*p))// *p>='A' && *p<='Z'
		{
			*p = tolower(*p);//*p = *p+32;
		}
		p++;
	}
	printf("%s\n", arr);
	return 0;
}

 Output result: 

7. Character operation—memory operation function:

  • memcpy

void * memcpy ( void * destination, const void * source, size_t num );

  • The function memcpy copies num bytes of data starting from the source location to the destination memory location.
  • This function does not stop when it encounters '\0'.
  • If there is any overlap between source and destination, the results of copying are undefined.
  • After the function copy is completed, the starting address of the target space is returned.
  • Let’s look at the following example to understand
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	memcpy(arr2, arr1, 40);
	for (int i = 0; i < 20; i++)
		printf("%d ", arr2[i]);
	return 0;
}

 

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };

	float arr3[] = { 1.0,2.0,3.0 };
	float arr4[5] = { 0 };

	memcpy(arr2, arr1, 40);
	memcpy(arr4, arr3, 8);//8个字节:拷贝两个元素

	for (int i = 0; i < 20; i++)
		printf("%d ", arr2[i]);

	printf("\n");

	for (int i = 0; i < 5; i++)
		printf("%f ", arr4[i]);
	return 0;
}

 Simulation implementation:

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;
}
  • Negative elements cannot be copied, so it is defined as an unsigned integer size_t type. Negative elements cannot be copied, so it is defined as an unsigned integer size_t type  .
  • It cannot be converted to the (int*) type because the function function cannot be implemented if other types are passed in. For example, if num is 7, it means that the function requires 7 bytes, and the int* type adds one copy and four bytes, so it is converted to (char*) type, add one byte each time and copy it seven times to perfectly solve the above problem.
  • It cannot be written as (char*)dest++, the cast is temporary.

Notice! ! ! memcpy cannot copy any location of itself.

If there is any overlap between source and destination, the results of copying are undefined .

At this time we can use the memmove function.


  • memmove

void * memmove ( void * destination, const void * source, size_t num );

  • The difference with memcpy is that the source memory block and target memory block processed by the memmove function can overlap .
  • If the source space and target space overlap, you have to use the memmove function.
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr1, arr1+2, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}
Output result:


 Simulation implementation:

void* my_memmove(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);
	if (dest < src) {
		while (num--) {
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else {
		while (num--) {
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}

First of all, we have to consider three situations, which correspond to different copy modes. When dest is located in front of src, copy the value of the corresponding position of src from front to back to the corresponding position of dest. This will not cause the value of src to be copied before it is copied to dest. Change. The same goes for the second and third types.

 

 In the third case, both front-to-back and back-to-front are possible. We will choose the same method as the second case, from back to front. In this way, there are only two cases for judging the copy method.

Output result:

  • memcpy only needs to implement non-overlapping copy
  • But the memcpy function on VS implements overlapping copy
  • Overlapping memory copies are still left to memmove.
  • Of course, memmove can also copy non-overlapping copies.


  • memcmp

int memcmp ( const void * ptr1, const void * ptr2, size_t num );
Compare num bytes starting from the ptr1 and ptr2 pointers
The return value is as follows:

int main()
{
	int arr1[] = { 1,2,1,4,5,6 };
	int arr2[] = { 1,2,257 };
	int ret = memcmp(arr1, arr2, 10);
	printf("%d\n", ret);
	return 0;
}

Output result:

memset 

void * memset ( void * ptr, int value, size_t num )

    Set the first num bytes pointed to by ptr to the value we want

int main()
{
	char arr[] = "hello bit";
	memset(arr+1,'x',4);
	printf("%s\n", arr);
	return 0;
}

Set in bytes , the four bytes starting from arr+1 are assigned to 'x'.

Output result: 

We can understand that memset is set in bytes by looking at the results of the following example:

int main()
{
	int arr[10] = { 0 };
	memset(arr, 1, 40);

	return 0;
}

Okay, this is the introduction of string functions and memory functions. I hope this article can help you recall the knowledge you have learned.


Guess you like

Origin blog.csdn.net/m0_73800602/article/details/132894138