学习C语言常见常用函数与模拟【深层理解】
函数快速查找
文章目录
- 函数快速查找
- 前言
- 一、strlen与模拟实现
-
- 模拟实现
- 二、strcpy与模拟实现
-
- 模拟实现
- 三、strcat
-
- 模拟实现
- 四、strcmp与模拟实现
-
- 模拟实现
- 五、strstr与模拟实现
-
- 模拟实现
- 六、strncpy
- 七、strncat
- 八、strncmp
- 九、strtok
- 十、strerror
-
-
- 字符分类函数
-
- 十一、memcpy
-
- 模拟实现
- 十二、memmove与模拟实现
-
- 模拟实现
- 总结
前言
本文收录了初学C语言时常见的有关字符串函数简介以及个别模拟实现,这些函数大大方便了编程工作,是收藏的不二选择
一、strlen与模拟实现
size_t strlen(const char * str);
字符串会以‘\0’作为结束标志,strlen则会返回’\0’以前出现的字符个数,(不包含\0).
- 字符串须以‘\0’为结束标志,否则会出现找不到\0返回随机值的情况
- 注意返回值为size_t,即unsigned int
模拟实现
1.指针-指针
int my_strlen(char *s){char *p = s;while(*p != ‘\0’ )p++;return p-s;}
2.计数器
int my_strlen(char* p){int count = 0;while (*p++){count++;}return count;}
3.不允许创建临时变量时常常采用递归
//不能创建临时变量计数器int my_strlen(const char * str){if(*str == '\0')return 0;elsereturn 1+my_strlen(str+1);}
二、strcpy与模拟实现
char* strcpy(char * destination, const char * source);
- 源字符串即待拷贝字符串,必须以’\0‘结束
- 会将源字符串中的’\0’拷贝到目标字符串
- 目标空间需要足够大,来确保能够存放源字符串.
- 目标空间必须可变
模拟实现
char* my_strcpy(char* p, const char* p1){char *ret = dest;assert(p && p1);while (*p++ = *p1++){;}return ret;}
三、strcat
char * strcat ( char * dest, const char * sour);
- 源字符串必须以’\0’为结束。
- 目标空间足够大。
- 目标空间可修改.
- 注意不可字符串自己给自己追加,会出现目标空间不足的情况
模拟实现
char* my_strcat(char* arr, const char* arr1){char* ret = arr;assert(arr && arr1);while (*arr){arr++;}while ((*arr++ = *arr1++)){;}return ret;}
四、strcmp与模拟实现
int strcmp ( const char * str1, const char * str 2);
- 第一个字符串大于第二个字符串,则返回大于0的数字
- 第一个字符串等于第二个字符串,则返回0
- 第一个字符串小于第二个字符串,返回小于0的数字
- 字符串比较时,对应位置一一比较
模拟实现
int my_strcmp(const char* p, const char* p1){int ret = 0;assert(p && p1);while (!(ret = *p - *p1) && p1){*++p;*++p1;}if (ret > 0){return 1;}else if (ret < 0){return -1;}}
更为严谨
int my_strcmp (const char * src, const char * dst){int ret = 0 ;assert(src != NULL);assert(dest != NULL);while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)++src, ++dst;if ( ret < 0 )ret = -1 ;else if ( ret > 0 )ret = 1 ;return( ret );}
五、strstr与模拟实现
char * strstr ( const char *str1, const char * str2);
- 寻找子集,看str1中是否存在str2.
- 若存在,返回str1中出现str2的地址
- 若不存在,返回NULL
模拟实现
char * strstr (const char * str1, const char * str2){char *cp = (char *) str1;char *s1, *s2;if ( !*str2 )return((char *)str1);while (*cp){s1 = cp;s2 = (char *) str2;while ( *s1 && *s2 && !(*s1-*s2) )s1++, s2++;if (!*s2)return(cp);cp++;}return(NULL);
六、strncpy
char * strncpy(char * dest, const char * sour, size_t num);
- 拷贝num个字符从源字符串到目标空间.
- 如果源字符串的长度小于num,则拷贝完字符串之后,在目标后边加0,直到num个.
七、strncat
char * strncat( char * dest, const char * sour, size_t num);
int main (){char str1[20];char str2[20];strcpy (str1,"To be ");strcpy (str2,"or not to be");strncat (str1, str2, 6);puts (str1);return 0;}
八、strncmp
int strncmp ( const char * str1, const char * str2, size_t num);
- 比较出现不一样的字符
- 一个字符串结束
- num个字符全部比完
九、strtok
char * strtok (char * str, comnst char * sep)
- sep 是个字符串,定义了用作分隔符的字符集合
- 第一个参数是字符串,包含了0个或多个sep中的一个或者多个分隔符分割的标记
- 函数会找到str中的下一个标记,用\0结尾,返回一个指向这个标记的指针(由此可见,会改变字符串,须先进行临时拷贝)
- 函数第一个参数不为NULL,找到第一个标记,函数会保存他在字符串中的位置
- 第一个参数是NULL,将在被保存的位置开始,寻找下一个标记
- 当没有标记,返回NULL
#include int main(){char *p = "zhangpengwei@bitedu.tech";const char* sep = ".@";char arr[30];char *str = NULL;strcpy(arr, p);//将数据拷贝一份,处理arr数组的内容for(str=strtok(arr, sep); str != NULL; str=strtok(NULL, sep)){printf("%s\n", str);}}
int main (){char str[] ="- This, a sample string.";char * pch;printf ("Splitting string \"%s\" into tokens:\n",str);pch = strtok (str," ,.-");while (pch != NULL){printf ("%s\n",pch);pch = strtok (NULL, " ,.-");}return 0;}
import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport seaborn as snsimport warningswarnings.filterwarnings('ignore')import sslssl._create_default_https_context = ssl._create_unverified_context
十、strerror
char * strerror (int errnum);
代码如下(示例):
#include #include #include //必须包含的头文件int main (){FILE * pFile;pFile = fopen ("unexist.ent","r");if (pFile == NULL)printf ("Error opening file unexist.ent: %s\n",strerror(errno));//errno: Last error numberreturn 0;}
data = pd.read_csv( 'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')print(data.head())
字符分类函数
函数 | 如果他的参数符合下列条件就返回真 |
---|---|
iscntrl | 任何控制字符 |
isspace | 空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’ |
isdigit | 十进制数字 0~9 |
isxdigit | 十六进制数字,包括所有十进制数字,小写字母a-f,大写字母A-F |
islower | 小写字母a~z |
isupper | 大写字母A~Z |
isalpha | 字母a-z或A-Z |
isalnum | 字母或者数字,a-z,A-Z,0-9 |
ispunct | 标点符号,任何不属于数字或者字母的图形字符(可打印) |
isgraph | 任何图形字符 |
isprint | 任何可打印字符,包括图形字符和空白字符 |
十一、memcpy
void * memcpy( void * dest, const void * sour, size_t num)
- 函数从sour的位置开始向后复制num个字节数据到dest的内存位置
- 遇到’\0’并不会停下来
- 不管有任何重叠,复制的结果是未定义的
模拟实现
void * memcpy ( void * dst, const void * src, size_t count){void * ret = dst;assert(dst);assert(src);/** copy from lower addresses to higher addresses*/while (count--) {*(char *)dst = *(char *)src;dst = (char *)dst + 1;src = (char *)src + 1;}return(ret);}
十二、memmove与模拟实现
void * memmove ( void * dest, const void * sour, size_t num);
- 和memcpy的区别是memmove函数处理的源内存块和目标内存块是可以重叠的
- 如果出现重叠,就使用memmove
模拟实现
void* my_memmove(void* s1, const void* s2, size_t count){void* ret = s1;assert(s1 && s2);if (s1 < s2){while (count--){*(char*)s1 = *(char*)s2; s1 = (char*)s1 + 1;s2 = (char*)s2 + 1;}}else{while (count--){*((char*)s1 + count) = *((char*)s2 + count);}}return ret;}
总结
以上就是今天要讲的内容,本文集锦好多了有趣有用常见的函数,是不是助学神器呢~~~
支持一下喽