前言:

为了方便查看博客,特意申请了一个公众号,附上二维码,有兴趣的朋友可以关注,和我一起讨论学习,一起享受技术,一起成长。


1. memcpy

内存复制函数。

1.1 头文件

#include <string.h>

1.2 描述

void *memcpy(void *str1, const void *str2, size_t n) ;

从存储区 str2 复制 n 个字符到存储区 str1。

1.3 参数

str1: 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针;

str2: 指向要复制的数据源,类型强制转换为 void* 指针;

n: 要被复制的字节数。

1.4 返回值

该函数返回一个指向目标存储区 str1 的指针。

1.5 注意

(1)复制的内容不同。strcpy 只能复制字符串,而 memcpy 可以复制任意内容,例如字符数组、整型、结构体、类等;

(2)复制的方法不同。strcpy 不需要指定长度,它遇到被复制字符的串结束符 “\0” 才结束,所以容易溢出。memcpy 则是根据其第 3 个参数决定复制的长度;

(3)用途不同。通常在复制字符串时用 strcpy,而需要复制其他类型数据时则一般用 memcpy。

(4)str1指针要分配足够的空间,也即大于等于 n 字节的空间。如果没有分配空间,会出现断错误,造成空间溢出;

(5)str1 和 str2 所指的内存空间不能重叠(如果发生了重叠,使用 memmove() 会更加安全);

(6)memcpy 是按照字节进行拷贝。多字节数据的拷贝如下:

测试:

void memcpy_test(void)
{char src_buf[5] = {1, 2, 3, 4, 5};char dst_buf[10] = {0};int test_buf1[5] = {99, 8522, 987, 3467, 11027};int test_buf2[5] = {0};memcpy(dst_buf, src_buf, sizeof(src_buf));for (int i = 0; i < sizeof(src_buf); i++){printf("dst_buf: %d \r\n", dst_buf[i]);}memcpy(test_buf2, test_buf1, sizeof(test_buf1));   //sizeof(test_buf1) = 20字节for (int i = 0; i < 5; i++){printf("test_buf2: %d \r\n", test_buf2[i]);}
}

结果输出:

1.6 原型实现

void *Memcpy(void *dest, const void *src, unsigned int count)
{char *pdest = (char *)dest;char *psrc = (char *)src;if (pdest == NULL || psrc == NULL){return NULL;}if (pdest == psrc){return;}if (pdest > psrc){while (count--){*(pdest + count) = *(psrc + count);}}else{while (count--){*pdest++ = *psrc++;}}return pdest;
}

2. memset

将某一块内存中的内容全部设置为指定的值,它是对较大的结构体或数组进行清零操作的一种快捷方法。

2.1 头文件

#include <string.h>

2.2 描述

void *memset(void *str, int c, size_t n) ;

复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。

2.3 参数

str: 指向要填充的内存块

c: 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式;

n: 要被设置为该值的字节数。

2.4 返回值

该函数返回一个指向存储区 str 的指针。

2.5 注意

(1)memset 函数按字节对内存块进行初始化,所以不能用它将 int 数组初始化为 0 和 -1 之外的其他值(除非该值高字节和低字节相同);

(2)memset(void *str, int c, size_t n) 中 c 实际范围应该在 0——255,因为该函数只能取 c 的后八位赋值给你所输入的范围的每个字节。无论 c 多大只有后八位二进制有效,而后八位二进制的范围在(0~255)。而对字符数组操作时则取后八位赋值给字符数组,其八位值作为 ASCII 码。

测试:

void memset_test(void)
{char test_buf1[5];int test_buf2[5];memset(test_buf1, 1, sizeof(test_buf1));memset(test_buf2, 1, sizeof(test_buf2));for (int i = 0; i < sizeof(test_buf1); i++){printf("tset_buf1 is %x \r\n", test_buf1[i]);}for (int i = 0; i < 5; i++){printf("tset_buf2 is %x \r\n", test_buf2[i]);}
}

结果输出:

2.6 原型实现


void *MyMemset(void *dest, int n, unsigned int len)
{if (dest == NULL)return NULL;char *pdest = (char *)dest;while (len--){*pdest++ = n;}return dest;
}

3. memcmp

把存储区 str1 和存储区 str2 的前 n 个字节进行比较,按字节比较

3.1 头文件

#include <string.h>

3.2 描述

int memcmp(const void *str1, const void *str2, size_t n) ;

存储区 str1 和存储区 str2 的前 n 个字节进行比较。

3.3 参数

str1: 指向内存块的指针;

str2: 指向内存块的指针;

n: 要被比较的字节数。

3.4 返回值

如果返回值 < 0,则表示 str1 小于 str2;

如果返回值 > 0,则表示 str2 小于 str1;

如果返回值 = 0,则表示 str1 等于 str2。

3.5 注意

(1)该函数是按字节比较的,比较 str1 和 str2 的第一个字节的 ascII 码值。

测试:

void memcmp_test(void)
{char str1[] = "abcd";char str2[] = "abcd";int ret = 0;ret = My_Memcmp(str1, str2, 4);printf("ret val is %d \r\n", ret);memcpy(str1, "abce", 4);ret = My_Memcmp(str1, str2, 4);printf("ret val is %d \r\n", ret);memcpy(str1, "abcc", 4);ret = My_Memcmp(str1, str2, 4);printf("ret val is %d \r\n", ret);
}

结果输出:

3.6 原型实现

int My_Memcmp(void *str1, void *str2, int count)
{char *ptr1 = (char *)str1;char *ptr2 = (char *)str2;if (!count){return 0;}while (count--){if (*ptr1 == *ptr2){ptr1 = ptr1 + 1;ptr2 = ptr2 + 1;}else{return *ptr1 - *ptr2;}}return *ptr1 - *ptr2;
}

4. strlen

strlen 所作的是一个计数器的工作,它从内存的某个位置(可以是字符串开头,中间某个位置,甚至是某个不确定的内存区域)开始扫描,直到碰到第一个字符串结束符 ‘\0’ 为止,然后返回字符计数器值(长度不包含 '\0 ')。

4.1 头文件

#include <string.h>

4.2 描述

size_t strlen(const char *str) ;

计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。

4.3 参数

str: 要计算长度的字符串。

4.4 返回值

该函数返回字符串的长度。

4.5 注意

(1)注意 strlen 和 sizeof 的区别。

测试:

void strlen_test(void)
{char *ptr = "asdfghjl";printf("strlen length is %d \r\n", strlen(ptr));
}

结果输出:


输出字符串长度不包括 ‘\0’。

4.6 原型实现

unsigned int My_Strlen(const char *str)
{int str_len = 0;while (*str++ != '\0'){str_len++;}return str_len;
}

5. strcpy

strcpy 把含有 ‘\0’ 结束符的字符串复制到另一个地址空间,返回值的类型为 char*。

5.1 头文件

#include <string.h>

5.2 描述

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

把 src 所指向的字符串复制到 dest。

5.3 参数

dest: 指向用于存储复制内容的目标数组。;

src: 要复制的字符串。

5.4 返回值

该函数返回一个指向最终的目标字符串 dest 的指针。

5.5 注意

(1)若目标数组 dest 不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况;

(2)src 和 dest 所指内存区域不可以重叠。

测试:

void strcpy_test(void)
{char test_buf1[6] = "ABCDE";char test_buf2[100] = {0};strcpy(test_buf2, test_buf1);printf("strcpy test %s \r\n", test_buf2);
}

5.6 原型实现

char *My_Strcpy(char *dest, const char *src)
{char *tmp = (char *)dest;if ((dest == NULL) || (src == NULL)){return 0;}while (*src != '\0'){*tmp++ = *src++;}*tmp = '\0';return tmp;
}

6. strcmp

比较两个字符串并根据比较结果返回整数。基本形式为 strcmp(str1, str2),若 str1 = str2,则返回零;若 str1 < str2,则返回负数;若 str1 > str2,则返回正数。

6.1 头文件

#include <string.h>

6.2 描述

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

把 str1 所指向的字符串和 str2 所指向的字符串进行比较。

6.3 参数

str1: 要进行比较的第一个字符串;

str2: 要进行比较的第二个字符串。

6.4 返回值

如果返回值小于 0,则表示 str1 小于 str2;

如果返回值大于 0,则表示 str1 大于 str2;

如果返回值等于 0,则表示 str1 等于 str2。

6.5 注意

(1)两个字符串自左向右逐个字符相比(按 ASCII 值大小相比较),直到出现不同的字符或遇 ‘\0’ 为止;

(2)只能比较字符串,即可用于比较两个字符串常量或比较数组,不能比较数字等其他形式的参数。

测试:

void strcmp_test(void)
{int ret = 0;
//  char test_buf1[6] = "ABCBE";
//  char test_buf2[3] = "AB";char test_buf1[6] = {1, 2, 3, 4, 5, 6};char test_buf2[6] = {1, 2, 3, 7, 5, 6};ret = My_Strcmp(test_buf1, test_buf2);printf("ret val is %d \r\n", ret);
}

6.6 原型实现

int My_Strcmp(const char *str1, const char *str2)
{if (str1 == NULL || str2 == NULL){return NULL;}while (*str1 == *str2){str1++;str2++;if (*str1 == '\0' || *str2 == '\0'){break;}}return *str1 - *str2;
}

7. sprintf

字符串格式化命令。函数声明为 int sprintf(char *string, char *format [,argument,…]);,主要功能是把格式化的数据写入某个字符串中,即发送格式化输出到 string 所指向的字符串。

7.1 头文件

#include <stdio.h>

7.2 描述

int sprintf(char *str, const char *format, ...);

发送格式化输出到 str 所指向的字符串。

7.3 参数

str: 指向一个字符数组的指针,该数组存储了 C 字符串;

format : 字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags] [width] [.precision] [length]specifier,具体介绍如下:

flags(标识):

width(宽度):

.precision(精度):

length(长度):

specifier(说明符):

附加参数 – 根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。

7.4 返回值

如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。

7.5 注意

(1)格式化数字字符串 sprintf 最常见的应用之一是把整数打印到字符串中;

(2)sprintf 的返回值是字符数组中字符的个数,即字符串的长度,不用在调用 strlen(str) 求字符串的长度;

测试:

void sprintf_test(void)
{char buf[100] = {0};double data = 3.141593;uint16_t len = 0;uint8_t test_buff[5] = {55, 22, 66, 77, 99};len = sprintf((char *)buf, "%f", data);printf("----------------------------------------------------------------- \r\n");printf("buf is %s \r\n", buf);printf("sprintf return len is %d \r\n", len);len = 0;for (uint16_t i = 0; i < sizeof(test_buff); i++){len += sprintf((char *)buf + i * 2, "%d", test_buff[i]);  //数组数据转换为字符串}printf("test_buff val is %s \r\n", buf);printf("sprintf return len is %d \r\n", len);printf("----------------------------------------------------------------- \r\n");
}

结果输出:


参考:

  1. C 库函数
  2. Cplusplus.com
  3. memcpy
  4. (C语言)memcpy函数原型的实现
  5. C函数库中的memcmp实现
  6. strlen (C/C++语言函数)

C语言再学习25——常用字符串函数归纳相关推荐

  1. C语言再学习 -- EOF、feof函数、ferror函数

    EOF详解 EOF是end of file的缩写,表示"文字流"(stream)的结尾.这里的"文字流",可以是文件(file),也可以是标准输入(stdin) ...

  2. C语言再学习 -- vim常用快捷键(转)

    参看:[Linux]vim常用快捷键 Linux中vim编辑器的功能非常强大,许多常用快捷键用起来非常方便,这里将我学vim入门时学的一些常用的快捷键分享给大家一下,希望可以帮助你们. 这个是我将鸟哥 ...

  3. C语言再学习 -- 打印长字符串

    如果必须分割一个字符串,有三个钟方法 #include <stdio.h> int main (void) { printf ("hhhhhhhh"); printf ...

  4. C语言再学习 -- 文件

    文件是什么 一个文件(file)通常就是磁盘上的一段命名的存储区.C 将文件看成是连续的字节序列,其中每一个字节都可以单独地读取. 二进制和文本模式 1.在windows系统中,文本模式下,文件以&q ...

  5. C语言再学习 -- 输入/输出

    一.缓冲区 输入字符的立即回显是非缓冲或直接输入的一个实例,它表示你说键入的字符被收集并存储在一个被成为缓冲区的临时存储区域中.按下回车可使你所键入的字符块对程序变成可用. 为什么需要缓冲区?首先,将 ...

  6. C语言再学习 -- 字符串和字符串函数

    最近身体很不给力,很乏累!白天没精神,晚上睡不着,心情还很烦躁.看书都有点看不下去的样子,到了C语言最难掌握的部分了,数组.指针.字符串.硬着头皮看书总结吧. 一.字符串 1.字符串介绍 字符串是以空 ...

  7. C语言再学习 -- 时间函数

    在软件设计中经常会用到关于时间的处理,用来计算语句.函数的执行时间,这时就需要精确到毫秒甚至是微妙的时间.我们首先来介绍一下,时间单位: 时间单位还有:秒(s).毫秒(ms).微秒 (μs).纳秒(n ...

  8. C语言再学习 -- 关键字return和exit ()函数

    终于到了最后一个关键字 return 了.感觉时间过的飞快,转眼间又是一年,如果时间可以 return 就好了. 一.return 介绍 参看:C语言中return 用法 1.含义: return 表 ...

  9. C语言常用字符串函数strlen、strcpy、strcat、strcmp、strchr

    C语言常用字符串函数,求串长strlen(char *s).串复制strcpy(char *s1,char *s2).串连接strcat(char *s1,char *s2).串比较strcmp(ch ...

最新文章

  1. 现在计算机学什么好找工作吗,计算机专业都学什么 毕业好找工作吗
  2. java geom_java.awt.geom 类 Area - Java 中文参考手册
  3. java实用教程——组件及事件处理——ItemEvent事件(设置字体类型)
  4. c++循环执行一个函数_Python—程序的循环结构
  5. 人脸识别的Python库
  6. @transactional可以用在controller层吗_石晶地板可以用在浴室吗?
  7. Thinkphp if标签不支持3层以上嵌套
  8. 配置防盗链 访问控制Directory 访问控制FilesMatch
  9. MySql5.7 + Linux 修改数据库密码
  10. 程序员真的是吃青春饭的行业吗?
  11. 在python中实现输出易经六十四卦
  12. 不可不学的摄影技巧之三(摄影小窍门)
  13. 阿里要收购陌陌了,可来往该怎么办?
  14. Python番外篇:电脑读心术程序 快给你的同事朋友玩一玩
  15. Rufus 3.19 beta 引入自定义 Windows 11 安装对话框
  16. Cityscapes数据集的深度完整解析
  17. CSS设置元素隐藏显示透明度
  18. Excel数据分列的详细用法
  19. SPSS统计软件学习
  20. 怎样培养自己的自信心?

热门文章

  1. 大数据挖掘课程案例资源介绍
  2. 媒体邀约得3个步骤和5个注意事项
  3. CodeForces 1438D
  4. java8 joda_Joda Time和Java8时差
  5. SSD固态硬盘怎么选?选对接口是关键
  6. 月入3000万 估值一亿美金的微信公众号
  7. python实现真正的多线程
  8. 2021年化工自动化控制仪表免费试题及化工自动化控制仪表考试总结
  9. 页面插件集成:博客详情页
  10. 利用python爬取实习僧网站上的数据