String and memory functions
1.1 strlen string length
size_t strlen(const char* str);
some compilers will report an error if they accept the return value of strlen with int, because size_t is an unsigned integer.
size_t sz=strlen(arr); printf("%u",arr);
- The string pointed to by str must contain '\ 0', otherwise the string length cannot be calculated.
- -The strlen function returns the problem of unsigned shaping:
int main() { if(strlen("abc")-strlen("abcedf")>0) { printf("hehe\n"); } else { printf("haha\n"); } //Because the strlen function returns an unsigned integer, 3-6 = - 3, but it will be understood as an unsigned integer, so it is still greater than 0. return 0; }
Three simulation implementations of strlen
1. recursion(No temporary variable is required to calculate the string length) size_t mystrlen(const char* arr) { assert(arr); if (*arr == '\0') { return 0; } else { arr++; return 1 + mystrlen(arr); } } 2.Address subtraction size_t mystrlen(const char* arr) { assert(arr); char* p = arr; while (*arr != '\0') { arr++; } return arr - p; } 3.Counter size_t mystrlen(const char* arr) { assert(arr); int count = 0; while (*arr != '\0') { count++; arr++; } return count; }
1.2 strcpy string copy
char* strcpy(char * destination, const char * source );
-
Copy the string pointed to by source to the space pointed to by destination, and return the address pointing to the first element of this space.
-
The source string must end with '\ 0'. The '\ 0' in the source string will be copied to the destination space.
-
The destination space must be large enough to hold the source string.
-
The target space must be variable. const char* p=“xxxxxxx”;
-
This function is not safe. It will be hard copied regardless of whether the memory is accessed out of bounds.
-
strcpy implementation
char* mystrcpy(char* des, const char* source) { assert(des && source); char* p = des; while (*des++ = *source++;) //When * source=' source = '\ 0'', the expression value is \ 0, //The ASCII value of \ 0 is 0, which stops the while loop. { ; } return p; }
1.3 strcat string link
char * strcat ( char * destination, const char * source );
- 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.
Implementation of strcat simulation
char* mystrcat(char* dest,const char* src) { assert(dest && src); char* ret = dest; while (*dest) { dest++; } while (*dest++ = *src++); return ret; }
1.4 strcmp string comparison
The size of the comparison is the content of the string (the ASCII value size of the corresponding character), not the length of the string.
int strcmp ( const char * str1, const char * str2 );
Standard provisions:
- 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 mystrcmp(const char* s1, const char* s2) { assert(s1 && s2); while (*s1 == *s2) { if (*s1 == '\0') { return 0;//It means the end is reached and the two are equal. } s1++; s2++; } return *s1 - *s2; }
The above three functions are string functions with unlimited length, which may cross the boundary to access memory, which is not safe enough.
Therefore, there are three string functions with limited length, strncpy, strncat and strncmp, which are relatively safe.
1.5 strncpy
char * strncpy ( char * destination, const char * source, size_t num ); //num number of copied characters.
-
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 num after the destination.
Implementation of strncpy simulation
char* mystrncpy(char* des, const char* src, size_t num) { assert(des && src); int sz = strlen(src); char* p = des; if (num <= sz) { for (int i = 0; i < num; i++) { des[i] = src[i]; } return p; } else { for (int i = 0; i < sz; i++) { des[i] = src[i]; } for (int j = sz; j < num; j++) { des[j] = '\0'; } return p; } }
1.6 strncat
char * strncat ( char * destination, const char * source, size_t num ); //num the number of characters appended.
- When appending, first find the first \ 0, then replace the first character, add subsequent characters in turn, and finally add a \ 0, so there must be at least num+1 positions after num characters.
- If the append string length is less than num, it will append only characters.
strncat Simulation Implementation
char* mystrncat(char* des, const char* src, size_t num) { assert(des && src); int len = strlen(src); char* p = des; while (*des != '\0') { des++; } if (num <= len) { int i = 0; for (i = 0; i < num; i++) { des[i] = src[i]; } des[num] = '\0'; } else { while (*des++ = *src++); } return p; }
1.7 strncmp
int strncmp ( const char * str1, const char * str2, size_t num ); //num number of strings compared
Compares the first num characters of two strings.
strncmp Simulation Implementation
int mystrncmp(const char* s1, const char* s2, size_t num) { assert(s1 && s2); int count = 0; while (count < num && *s1 == *s2) { if (*s1 =='\0') { return 0; } s1++; s2++; count++; } return *s1 - *s2; }
1.8 STR string lookup function
char * strstr ( const char *str2, const char * str1);
Returns a pointer to the first letter address of str2 in str1. If it does not appear, it returns NULL.
STR Simulation Implementation
char* mystrstr(const char* str1, const char* str2) { //Idea: save the first element address of string 1 with str1 and the first element address of string 2 with str2 //cp indicates where the comparison starts from in the str1 string //s1 is the pointer when string 1 is used for comparison //s2 is the pointer when string 2 is used for comparison char* cp = str1; char* s1 = str1; char* s2 = str2; if (*s2 == '\0')//If it is an empty character, just return it directly. { return str1; } while (*cp != '\0')//It's not over yet { s1 = cp; s2 = str2; //while (*s1!='\0' && *s2!='\0' && *s1 == *s2) while (*s1 && *s2 && *s1 == *s2) //There are three possibilities to jump out of the loop, //If the front of s1s2 is always equal, s2 reaches the tail = = \ 0, which indicates that the matching is successful and jumps out; //If s1 and s2 are always equal in front, but s1 has reached the tail, and s2 has not reached the tail, it can no longer match and jump out; //If it's not equal, jump out //We should control them not to compare to \ 0, or they may cross the border. { s1++; s2++; } if (*s2 == '\0') //This is the only case of successful matching { return cp; } cp++; } return NULL;//If you haven't come here for one return, it means that the search failed } //The above is the BF algorithm, which is also implemented in the library
In string search, there is an algorithm called KMP algorithm.
1.9 strtok string splitting function
char * strtok ( char * str, const char * sep );
- The sep parameter is a string, which is a collection of delimiters, such as 2587966900@qq.com , if you want to cut out 2587966900, QQ and com, the SEQ parameter must be equal to "@"
- For the first parameter str, its usage is
- The first time a non NULL pointer STR is passed, when the first parameter is not NULL, the first tag in the string str will be found, and the tag will be changed to \ 0. Then the strtok function will remember this position (the memory feature shows that the strtok function uses a static variable or a global variable) and return a pointer to the first element.
- All subsequent calls pass NULL pointers. When the first parameter is NULL, the strtok function will start from the first saved location, look for the marker later, update the saved location after finding it, and return a pointer to the next location of the saved location.
- When there are no more tags in the string, the strtok function returns NULL;
Based on the characteristics of strtok function, we can design the program as follows:
#include <stdio.h> #include <string.h> int main() { char arr[] = "2587966900@qq.com"; char arr1[100] = { 0 }; strcpy(arr1, arr); char* cunfang[3] = { 0 }; char* ret = NULL; char seq[] = "@."; int i = 0; for (ret = strtok(arr1, seq); ret != NULL; ret = strtok(NULL, seq)) { cunfang[i] = ret; i++; } for (int j = 0; j < 3; j++) { printf("%s\n", cunfang[j]); } return 0; }
1.10 strerror error message reporting function
char * strerror ( int errnum );
Header file that must be included < string. H > < errno. H >
Returns the error information corresponding to the error code.
When the C language library function call fails, the error code will be stored in the errno variable.
There is also a more direct library function perror, which is equivalent to printing the error information corresponding to the error code.
#include <stdio.h> #include <errno.h> #include <string.h> int main() { FILE* pf = fopen("text.txt", "r"); if (pf == NULL) { printf("%s", strerror(errno)); perror("test"); //The test: error message will be output. return -1; } else { printf("Open successfully"); } fclose(pf); pf = NULL; return 0; }
1.11 memcpy memory copy without duplication
void * memcpy ( void * destination, const void * source, size_t num ); //num bytes copied //You can copy directly in memory, not just strings, integers, structures, arrays, etc.
- The function memcpy copies num bytes of data back to the memory location of destination from the location of source.
- If there is any overlap between source and destination, the copied result is undefined.
- If there are overlapping copies, consider the memmove function.
//Simulation Implementation //Train of thought 1 for loop void* mymemcpy(void* des,const void* src, size_t num) { assert(des && src); char* p1 = (char*)des; char* p2 = (char*)src; for (int i = 0; i < num; i++) { p1[i] = p2[i]; } return des; } //Idea 2 while loop void* mymemcpy(void* des, const void* src, size_t num) { assert(des && src); void* p = des; while (num--) { *(char*)des = *(char*)src; des = (char*)des + 1; src = (char*)src + 1; } return p; }
Although memcpy can also copy when memory overlaps in vs environment, the requirement for memcpy function in C language standard is only to complete the copy when memory does not overlap. You should not know that memcpy can complete the copy when memory overlaps.
1.12 memmove can handle memory copies in case of duplication
void * memmove ( void * destination, const void * source, size_t num );
Function: it can realize memory copy in case of memory duplication
//Implementation idea 1: using dynamic memory allocation void* mymemmove(void* des, const void* src, size_t num) { assert(des && src); char* p1 = (char*)des; char* p2 = (char*)src; char* p = (char*)malloc(num); for (int i = 0; i < num; i++) { p[i] = p2[i]; } for (int i = 0; i < num; i++) { p1[i] = p[i]; } free(p); p = NULL; return des; } //Implementation idea without dynamic memory allocation: it is found that if des is in front of src, there will be no problem copying from front to back; If des is behind src, copy from back to front void* my_memmove(void* des, const void* src, size_t count) { void* p = des; if (des < src) { while (count--) { *(char*)des = *(char*)src; des = (char*)des + 1; src = (char*)src + 1; } } else { while (count--) { *((char*)des + count) = *((char*)src + count); //Count has been reduced by 1. des is strongly converted to char * and count is just the last element address. Similarly, src. } } return p; }
1.13 memcmp memory comparison
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
- Compare the first num bytes of two memory blocks, and return 0 if they are equal;
- Otherwise, compare the first two unequal bytes,
- If ptr1 is small, a number less than 0 is returned,
- If ptr2 is small, a number greater than 0 is returned.
memcpy Simulation Implementation
int mymemcmp(const void* s1, const void* s2, size_t num) { char* p1 = (char*)s1; char* p2 = (char*)s2; int i = 0; while (*p1 == *p2 && i<num) { p1++; p2++; i++; } if (i == num) { return 0; } else { return *p1 - *p2; } }
1.14 memset memory settings
void *memset( void *dest, int c, size_t count );
Set the bytes of count in the target space to a number a, which is an unsigned char in the range of 0 ~ 255. It is obtained by truncating int c and returns the starting address of the target space.
It is generally used to initialize some structures.
memset Simulation Implementation
void* mymemset(void* dest, int c, size_t num) { char* p = (char*)dest; size_t b = (size_t)c; for (int i = 0; i < num; i++) { p[i] = b; } return dest; }