目录

  • 前言
    • 函数介绍及模拟
      • strlen函数
        • 模拟实现
      • strcpy函数
        • 模拟实现
          • strncpy函数
      • strcat函数
        • 模拟实现
          • strncat函数
      • strcmp函数
        • 模拟实现
          • strncmp函数
      • strstr函数
        • 模拟实现
      • memcpy函数
        • 模拟实现
      • memmove函数
        • 模拟实现
      • strtok函数
      • strerror函数
      • 字符分类函数
      • 字符转换

前言

C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。
字符串常量适用于那些对它不做修改的字符串函数.

函数介绍及模拟

strlen函数

 size_t strlen ( const char * str );

1.字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中’\0’ 前面出现的字符个数(不包含 ‘\0’ )。
2.参数指向的字符串必须要以 ‘\0’ 结束。
3.注意函数的返回值为size_t,是无符号的整数。

例:

#include <stdio.h>
#include<string.h>
int main()
{const char*str1 = "abcdef";    //常量字符串后面默认带了个'\0'const char*str2 = "bbb";if(strlen(str2)-strlen(str1)>0)      // 6-3{printf("str2>str1\n");}else{printf("srt1>str2\n");}return 0;
}

模拟实现

 size_t strlen ( const char * str );
#include<stdio.h>
size_t my_strlen(const char* str)
{const char* start = str;const char* end = str;while (*end != '\0'){end++;}return end - start;     //指针相减等于两指针间的元素个数
}int main()
{char arr[] = "abcdef";int len = my_strlen(arr);printf("%d\n", len);return 0;
}

strcpy函数

 char* strcpy(char * destination, const char * source );

注:前面的指针指向目标字符串,后面指针指向源字符串

1.源字符串必须以 ‘\0’ 结束。
2.将源指向的字符串复制到目标所指向的数组中,包括 ‘\0’ 字符(并在该点停止)。
3.目标空间必须足够大,以确保能存放源字符串。
4.目标空间必须可变。(常量字符串不能修改,目标空间不能是常量字符串)

#include<stdio.h>
#include<string.h>
int main()
{char arr[20] = "abcdef";char* m = "fff";strcpy(arr, m);printf("%s", arr);    return 0;
}

输出:fff

模拟实现

 char* strcpy(char * destination, const char * source );

函数返回值为目标字符串起始地址

char* my_strcpy(char* dest, const char* src)
{char* ret = dest;while (*dest++ = *src++);  //后置加加,先解引用,再赋值,再加加,直到*dest=*src='\0',退出循环return ret;
}int main()
{char arr1[20] = "abc";char arr2[] =   "hello hello";printf("%s\n", my_strcpy(arr1, arr2));return 0;
}

输出:hello hello

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

1.拷贝num个字符从源字符串到目标空间。
2.如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。


我们可以看到,在拷贝完源字符串后又追加了3个0
模拟实现:

char* m_strncpy(char* destination, const char* source, size_t num)
{char* p = destination;int i = 1;while (*destination = *source){destination++;source++;i++;}destination++;num -= i;while (num--){*destination++ = '\0';}return p;
}
int main()
{char arr[20] = "abcdef";char* m = "abc";printf("%s", strncpy(arr, m, 6));return 0;
}

strcat函数

 char * strcat ( char * destination, const char * source );

1.将源字符串的内容追加到目标字符串(包括 ‘\0’ ),目标中的 ‘\0’ 字符被源的第一个字符覆盖。
2.源字符串必须以 ‘\0’ 结束。
3.目标空间必须有足够的大,能容纳下源字符串的内容。
4.目标空间必须可修改。

例:

#include<stdio.h>
#include<string.h>
int main()
{char arr[20] = "abcdef";char* m = "abc";printf("%s", strcat(arr, m));     //函数返回值为目标字符串起始地址return 0;
}

输出:abcdefabc

模拟实现

 char * strcat ( char * destination, const char * source );
#include<stdio.h>
char* m_strcat(char* destination, const char* source)
{char* p = destination;while (*destination++);     destination--;            //destination指向了\0后面的元素,所以--while (*destination++ = *source++);return p;
}int main()
{char arr[20] = "abcdef";char* m = "abc";printf("%s", m_strcat(arr, m));     return 0;
}
strncat函数
 char * strncat ( char * destination, const char * source, size_t num );

1.将源的前 num 个字符追加到目标,外加一个终止空字符。
2.如果源中 C 字符串的长度小于 num,则仅复制到终止空字符之前的内容。

类似于前面的 strncpy 这里就不展开讲了。

strcmp函数

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

1.第一个字符串大于第二个字符串,则返回大于0的数字
2.第一个字符串等于第二个字符串,则返回0
3.第一个字符串小于第二个字符串,则返回小于0的数字

如何判断两个字符串呢?
假设有如下两个字符串:

 char* m = "abcdef";char* n = "abce";strcmp(m, n);

首先是两个字符串的第一个字符比较,很明显相等,再比较下一个字符,直到字符 ‘d’ 与 ‘e’ 比较,字符 ‘d’ 是小于 ‘e’ 的,所以m指向的字符串小于n指向的字符串。

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

输出:-1

模拟实现

#include<stdio.h>
int m_strcmp(const char* str1, const char* str2)
{while (*str1 == *str2){if (*str1 == '\0')return 0;str1++;str2++;}if (*str1 > *str2)return 1;if (*str1 < *str2)return -1;
}
int main()
{char* m = "abcdef";char* n = "abca";printf("%d", m_strcmp(m, n));return 0;
}

输出:1

strncmp函数
 int strncmp ( const char * str1, const char * str2, size_t num );

比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。

有兴趣可以自己实现一下。

strstr函数

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

1.返回指向 str1 中第一次出现的 str2 的指针,如果 str2 不是 str1 的一部分,则返回空指针。
2.匹配过程不包括终止空字符,但它在那里停止。

int main()
{char* m = "abcdef";char* n = "cde";printf("%s", strstr(m, n));return 0;
}

输出:cdef

模拟实现

 char * strstr ( const char *str1, const char * str2);
char* m_strstr(const char* str1, const char* str2)
{const char* s1 = str1;       //见下图,s1 标记目标字符串每次开始查找的首元素const char* s2 = str2;       // s2 标记源字符串每次开始查找的首元素const char* p = str1;       // p 标记每次从 s1 开始遍历的元素if (*str2 == '\0'){return str1;}while (*p){s1 = p;s2 = str2;        //每次循环开始将 s1 移到后一个元素处,s2 移到首元素处while (*s1 != '\0' && *s2 != '\0' && (*s1 == *s2)){s1++;s2++;}if (*s2 == '\0')      //当源字符串遍历完了后即找到了{return (char*)p;   }p++;}return NULL;   //找不到子串
}
int main()
{char* m = "abcdef";char* n = "cde";printf("%s", m_strstr(m, n));return 0;
}


当第一次没找到后,第二次循环 s1 、p指向如图:

若 p 指向 ‘\0’ ,则表示找不到该字符串,退出循环。

memcpy函数

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

1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
2.这个函数在遇到 ‘\0’ 的时候并不会停下来。
3.如果source和destination有任何的重叠,复制的结果都是未定义的。

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

我们来看看内存分配情况:

由图可以看出memcpy函数改变了20字节的内容,也就是5个整型,改变了5个整型数,那么它是什么方式改变这20字节的呢?

从左到右一个字节一个字节的依次复制,直到20个字节。

模拟实现

void* m_memcpy(void* destination, const void* source, size_t num)
{void* p = destination;while (num--)      //循环num次{*(char*)destination = *(char*)source;   //char型访问一个字节,方便逐个字节打印destination = (char*)destination + 1;source = (char*)source + 1;}return p;
}
int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 0 };m_memcpy(arr2, arr, 20);return 0;
}

memmove函数

不知道大家有没有想过,如果是自己复制自己,那memcpy为什么不能用呢?什么函数可以实现呢?
memcpy函数会改变目标数据,如果目标数据与源数据有重叠,可能导致
如下情况:


假设我要把1 2 3 4 复制到3 4 5 6 的位置上,那么从前往后就是如图,我们可以看到原来的3 4 变为了1 2 ,然后1 2 再复制到5 6 处,原来的3 4 5 6 就变为了1 2 1 2,这与我们要的结果不同,所以不能用该函数了,那么我们应该如何才能正确打印呢?

我们发现如果从后往前复制就可以很好的避免这种情况发生,即从两数据重叠处开始复制。而memmove函数就很好的解决了这点。

我们来看看memmove函数:

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

1.和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
2.如果源空间和目标空间出现重叠,就得使用memmove函数处理

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

模拟实现

void* m_memmove(void* destination, const void* source, size_t num)
{void* p = destination;if (destination < source){while (num--){       //从前往后复制*(char*)destination = *(char*)source;destination = (char*)destination + 1;source = (char*)source + 1;}}else{while (num--){       //从后往前复制*((char*)destination+num) = *((char*)source+num);}}return p;
}
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };m_memmove(arr1 + 2, arr1, 20);return 0;
}

strtok函数

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

1.sep参数是个字符串,定义了用作分隔符的字符集合。
2.第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
3.strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
4.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
5.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。(该函数具有记忆功能)
6.如果字符串中不存在更多的标记,则返回 NULL 指针。

我们来具体看看:

#include<stdio.h>
#include<string.h>
int main()
{char arr[] = "zhangsan@baidu.com";char buf[200] = { 0 };strcpy(buf, arr);     //将arr的内容复制到buf中const char* p = "@.";char* str = strtok(buf, p);  //找到第第一个标记字符'@',并将其改为'\0',返回指向这个字符串的指针printf("%s\n", str);   //打印: zhangsanstr = strtok(NULL, p);   //从上次标记的'\0'开始查找下一个标记符号,重复以上操作printf("%s\n", str);    //打印: baidustr = strtok(NULL, p);printf("%s\n", str);     //打印: comreturn 0;
}

简化一下:

int main()
{char arr[] = "zhangsan@baidu.com";char buf[200] = { 0 };strcpy(buf, arr);const char* p = "@.";char* str = NULL;for (str=strtok(buf, p); str!=NULL; str=strtok(NULL, p)){printf("%s\n", str);}return 0;
}

strerror函数

 char * strerror ( int errnum );

返回错误码,所对应的错误信息。

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{                  //errno - C语言提供的全局的错误变量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));return 0;
}

输出:
其他的错误变量对应的错误码可以自己输出试试。

字符分类函数


返回真就是返回大于0的数,可用于条件判断。

字符转换

 int tolower ( int c );   //大写转小写int toupper ( int c );   //小写转大写

我们来看下面一段小写转大写的代码:

#include<stdio.h>
#include <ctype.h>
int main()
{char arr[] = "Are you ok?";char* p = arr;while (*p){if (islower(*p))   //判断是否是小写{*p = toupper(*p);    //小写转大写}p++;}printf("%s\n", arr);return 0;
}

输出:ARE YOU OK?

本希望本期内容对大家能有所帮助,下期见了~

字符函数和字符串函数详解相关推荐

  1. 字符数组和字符串的区别,C语言字符数组和字符串区别详解

    C 语言中并不存在字符串这个数据类型,而是使用字符数组来保存字符串.那么,字符数组就一定是字符串吗? 不一定,字符数组和字符串千万不要混淆.字符串是一种特殊的字符数组,并且C语言提供了大量适用于字符串 ...

  2. php和c语言的字符数组中,字符数组和字符串的区别,C语言字符数组和字符串区别详解...

    C 语言中并不存在字符串这个数据类型,而是使用字符数组来保存字符串.那么,字符数组就一定是字符串吗? 对于这个问题,大多教科书中的回答是"是".其实不然,字符数组和字符串是完全不相 ...

  3. 字符函数和字符串函数详解(二)strncpy strncat strncmp strstr strtok(及其模拟实现)

     系列文章目录 字符函数和字符串函数详解(一)strlen strcpy strcat strcmp 字符函数和字符串函数详解(二)strncpy strncat strncmp strstr str ...

  4. C语言字符串库函数详解模拟实现(strlen、strcpy、strcat、strcmp)+字符操作函数+字符转换函数

    字符串库函数详解 一.无字符串长度限制的字符串函数 1. strlen 计算字符串长度函数 2. strcpy 字符串拷贝函数 3. strcat 字符串追加函数 4. strcmp 字符串比较函数 ...

  5. 字符串拷贝函数:strcpy的详解及模拟实现

    字符串拷贝函数:strcpy的详解及模拟实现!!! 对于字符串拷贝函数,之前在学习字符串时候,就已经学习过,但那只是片面的学习了一下,并没有经过系统的分析!只是大概的学习了一下!在关键的地方有时候还不 ...

  6. mysql strcmp s1 s2_MySQL函数基础——字符串函数详解

    昨天,咱们对MySQL的数学函数进行了讲解,今天,咱们再来解析MySQL字符串函数. 字符串函数主要用来处理数据库中的字符串数据,MySQL中字符串函数有:计算字符串长度函数.字符串合并函数.字符串替 ...

  7. mysql函数编写格式_MySQL函数基础——字符串函数详解

    昨天,咱们对MySQL的数学函数进行了讲解,今天,咱们再来解析MySQL字符串函数. 字符串函数主要用来处理数据库中的字符串数据,MySQL中字符串函数有:计算字符串长度函数.字符串合并函数.字符串替 ...

  8. php。defined,PHP defined()函数的使用图文详解

    PHP defined()函数的使用图文详解 PHP defined() 函数 例子 定义和用法 defined() 函数检查某常量是否存在. 若常量存在,则返回 true,否则返回 false. 语 ...

  9. Delphi Format函数功能及用法详解

    DELPHI中Format函数功能及用法详解 DELPHI中Format函数功能及用法详解function Format(const Format: string; const Args: array ...

  10. python实现排序函数_Python排序函数的使用方法详解

    Python排序函数完美体现了Python语言的简洁性,对于List对象,我们可以直接调用sort()函数(这里称为"方法"更合适)来进行排序,而对于其他可迭代对象(如set,di ...

最新文章

  1. DoS***原理和防御方法
  2. Django_ORM数据表查询总结
  3. vim自动跳转到引用的函数
  4. 多进程减少多个文件的内存占用
  5. M理论能否成为解释一切的“万有理论”?
  6. 三角形垂点坐标js算法(三点定圆求圆心)
  7. Centos7安装32位库用来安装32位软件程序
  8. pmp 资料_1年 = 15300订阅 + 超100万次收听 (感恩有您,这些PMP备考资料您值得拥有!)...
  9. 李宏毅机器学习笔记第5周_逻辑回归
  10. 启动计算机管理服务,win10系统打开服务管理器的五种方法
  11. TextView 设置显示省略号
  12. python网络爬虫之淘宝订单提取
  13. Java中正则表达式的基本使用
  14. Facebook产品功能以及营销
  15. scratch设计跑酷游戏_我如何使用Scratch设计游戏
  16. OpenGL应用:天空盒子(SkyBox)
  17. freetype 使用解析---矢量字体
  18. [数学建模(四)]MATLAB神经网络工具箱的简单应用
  19. 【网安神器篇】——enum4linux枚举工具
  20. 从顶会论文看2022年推荐系统序列建模的趋势

热门文章

  1. API_2 安装详细流程
  2. Ruby 学习(六)数组Array
  3. Charles抓取微信小程序https请求(附注册激活码教程)
  4. 论文阅读:Deep Learning–Based Segmentation andQuantification in Experimental Kidney Histopathology
  5. sikuli python java_Sikuli 基于图形识别的自动化测试技术
  6. shell dd命令在bs参数太大的时候出现异常的解决方法
  7. js---BOM 的理解方法
  8. 树莓派Pi Pico套件 MicroPython编程
  9. android hprof,Android Hprof 分析
  10. 图论(十)——欧拉图和哈密尔顿图