C语言中字符串库函数
目录
- 1.求字符串长度
- strlen
- 模拟实现strlen
- 2.长度不受限制的字符串函数
- strcpy
- 模拟实现strcpy
- strcat
- 模拟实现strcat
- strcmp
- 模拟实现strcmp
- 3.长度受限制的字符串函数介绍
- strncpy
- 模拟实现strncpy
- strncat
- 模拟实现strncat
- strncmp
- 模拟实现strncmp
- 4.字符串查找
- strstr
- 模拟实现strstr
- strtok
- 5.错误信息报告
- strerror
C语言中,本身没有字符串类型的,字符串通常以字符数组和常量字符串的形式出现。
而有一些库函数可以对字符串进行操作,使我们对字符串的处理可以简单许多,但是注意的是:这些库函数不可以修改常量字符串
1.求字符串长度
strlen
size_t strlen ( const char * str );
strlen
函数计算的是字符串中'\0'
前面出现的字符个数,不包含'\0'
- 参数指向的字符串一定要以
'\0'
结尾,否则会计算出随机值 strlen
是求字符串长度的,求出的长度是不可能为负数,所以返回size_t
类型的值,size_t
其实就是无符号的整形unsigned int
由于
strlen
返回无符号整形,所以这里是一个易错点,以接下来的代码为例
#include <stdio.h>
#include <string.h>
int main()
{char str1[] = "abcdefg";char str2[] = "abcdefghijk";if (strlen(str1) - strlen(str2) < 0)printf("str1长度小于str2长度");elseprintf("str1长度大于str2长度");return 0;
}
str1
长度为7,str2
长度为11,7-11 = -3,但是这里的7和11是无符号整形,他们俩相减会得到一个非常大的数,而不是-3,所以这个程序会输出str1长度大于str2长度
模拟实现strlen
这里有三种方法进行模拟实现
第一种:常规方法:
#include <stdio.h>
#include<assert.h>
#include <string.h>int my_strlen1(const char* str)
{assert(str != NULL);int count = 0;while (*str != '\0'){count++;str++;}return count;
}
第二种:递归:
#include <stdio.h>
#include<assert.h>
#include <string.h>int my_strlen2(const char* str)
{assert(str != NULL);if (*str != '\0'){return 1 + my_strlen2(str+1);}else{return 0;}
}
第三种:指针相减:
#include <stdio.h>
#include<assert.h>
#include <string.h>int my_strlen3(const char* str)
{assert(str != NULL);const char* start = str;while (*str != '/0'){str++;}return str - start;
}
两个指向同一块空间的两个指针,两个指针相减得到这两个指针间的元素的个数
2.长度不受限制的字符串函数
strcpy
char* strcpy(char * destination, const char * source );
- 这个函数的作用是将
source
中的字符串拷贝到空间destination
中 destination
是目标空间,函数将复制的字符串放到这个目标空间中source
是源字符串,函数会复制源字符串,因为只是对源字符串进行复制,并不会改变它,所以可以将源字符串写成const
- 目标空间必须足够大,以确保能存放源字符串。
- 目标空间必须可变。
- 源字符串必须以 ‘\0’ 结束,因为源字符串读到\0就停止拷贝。
- 函数会将源字符串中的 ‘\0’ 拷贝到目标空间。
#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = {0};char arr2[] = "abcdef";strcpy(arr1, arr2);printf("%s\n", arr1);return 0;
}
#include <stdio.h>
#include <string.h>int main()
{char arr1[20] ="xxxxxxx";char arr2[] = "ab\0cdef";strcpy(arr1, arr2);return 0;
}
这里可以看到,在
arr2
中ab
后面放了一个\0
,则在函数拷贝时只会拷贝ab\0
我们可以调试函数看一下:拷贝前的
arr1
:
拷贝后的arr1
:
可以看到,只拷贝了ab\0
模拟实现strcpy
最常规写法:
#include <stdio.h>
#include<assert.h>
#include <string.h>char* my_strcpy(char* destination, const char* source)
{char* ret = destination;assert(destination && source );while (*source!='\0'){*destination = *source;destination++;source++;}*destination = *source;//拷贝\0return ret;
}
这么要注意的一点就是,
strcpy
拷贝过程中会源字符串中最后的\0
,但是如果以while (*source!='\0')
为循环条件的话,最后的\0
就不会被拷贝
所以要在循环外部额外再拷贝一次*destination = *source;
简化一点:
#include <stdio.h>
#include<assert.h>
#include <string.h>
char* my_strcpy(char* destination, char* source)
{char* ret = destination;assert(destination && source );while (*src != '\0'){*destination++ = *source++;}*destination = *source;//拷贝\0return ret;
}
再简化:
前面的两种写法都需要在循环外部额外再对
\0
进行拷贝,而下面的写法直接将\0
的拷贝也放到了循环中进行
#include <stdio.h>
#include<assert.h>
#include <string.h>
char* my_strcpy(char* destination,const char* source)
{char* ret = destination;assert(destination && source );while (*destination++ = *source++){;}return ret;
}
strcat
char * strcat ( char * destination, const char * source );
- 这个函数的作用是将
source
中的字符串追加到destination
的后面 - 目标空间要有\0结尾,因为要直到从哪开始追加
- 源字符串要有\0结尾,因为要知道何时结束追加
- 目标空间必须有足够的大,能容纳下源字符串的内容。
- 目标空间必须可修改。
#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "hello";char arr2[] = " world";strcat(arr1, " world");printf("%s", arr1);return 0;}
当一个字符串,自己对自己追加的时候会有问题:
以字符串abcdef
追加自己为例
从\0开始追加,a追加到f,本来f后面是\0,到了\0就停止追加,但是前面追加时已经就将\0覆盖了,所以不会停止
模拟实现strcat
#include <stdio.h>
#include<assert.h>
#include <string.h>char* my_strcat(char* des, char* src)
{assert(des && src);char* ret = des;while (*des != '\0'){des++;}while (*des++ = *src++){;}return ret;
}
strcmp
int strcmp ( const char * str1, const char * str2 );
标准规定(在非VS环境中):
- 第一个字符串大于第二个字符串,则返回大于0的数字
- 第一个字符串等于第二个字符串,则返回0
- 第一个字符串小于第二个字符串,则返回小于0的数字
而在VS环境中:
- 第一个字符串大于第二个字符串,则返回1
- 第一个字符串等于第二个字符串,则返回0
- 第一个字符串小于第二个字符串,则返回-1
对于两个字符串的大小,比较的并不是字符串的长度,而是一个一个比较组成字符串的字符,字符对应ASCII码值大的字符大。例如:'z'
大于'a'
模拟实现strcmp
#include <stdio.h>
#include<assert.h>
#include <string.h>int my_strcmp(char* str1,char* str2)
{assert(str1 && str2);while (*str1 == *str2){if (*str1 == '\0'){return 0;}str1++;str2++;}//VS环境下:if (*str1 > *str2)return 1;elsereturn -1;//非VS环境下://return *str1-*str2;
}
3.长度受限制的字符串函数介绍
上面介绍的都是没有长度限制字符函数,它们都是进行到\0
就停止,而接下来的三个函数有长度限制
strncpy
char * strncpy ( char * destination, const char * source, size_t num );
//验证strncpy是不会在拷贝后自动加'\0'的
#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "xxxxxxx";char arr2[] = "abcdef";strncpy(arr1, arr2,2);return 0;
}
将
arr2
前2个字符拷贝到arr1
中,在监视中看到:
所以可知:strncpy
不会自动添加\0
num
比源字符串要长,多出来的部分用\0来补
//验证num比源字符串要长,多出来的部分用\0来补
#include <stdio.h>
#include <string.h>int main()
{char arr1[20] = "xxxxxxxxxxxxx";char arr2[] = "abc";strncpy(arr1, arr2,6);return 0;
}
模拟实现strncpy
#include <stdio.h>
#include<assert.h>
#include <string.h>char* my_strncpy(char* str1, char* str2, int n)
{char* ret = str1;assert(str1 && str2);if (n < 0) return;while (n>0){if (*str2 == '\0'){*str1 = '\0';str1++;n--;}else{*str1 = *str2;str1++;str2++;n--;}}return ret;
}
这里模拟实现时,要注意当
num
大于源字符串长度时需要补\0这点,其余地方很简单
strncat
char * strncat ( char * destination, const char * source, size_t num );
模拟实现strncat
#include <stdio.h>
#include<assert.h>
#include <string.h>char* my_strncat(char* str1, char* str2, int n)
{char* ret = str1;assert(str1 && str2);if (n < 0) return;while (*str1 != '\0'){str1++;}while (n > 0){if (*str2 == '\0'){*str1 = '\0';str1++;n--;}else{*str1 = *str2;str1++;str2++;n--;}}*str1 = '\0';return ret;
}
strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
模拟实现strncmp
#include <stdio.h>
#include<assert.h>
#include <string.h>int my_strncmp(char* str1, char* str2, int n)
{assert(str1 && str2);if (n < 0) return;while (n > 0){while (*str1 == *str2){if (n == 1){return 0;}str1++;str2++;n--;}if (*str1 > *str2)return 1;elsereturn -1;}
}
4.字符串查找
strstr
char * strstr ( const char *str1, const char * str2);
模拟实现strstr
#include <stdio.h>
#include<assert.h>
#include <string.h>void* my_strstr(char* str1, char* str2)
{assert(str1 && str2);if (*str2 == '0'){return (char*)str1;}const char* s1 = str1;const char* s2 = str2;const char* cp = str1;while (*cp){s1 = cp;s2 = str2;while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2){s1++;s2++;}if (*s2 == '0'){return (char*)cp;}cp++;}return NULL;
}
strtok
char * strtok ( char * str, const char * sep );
#include <stdio.h>
#include <string.h>int main()
{char arr1[] = "abc#defa|gh";char arr2[] = "#|";strtok(arr1,arr2);
}
有一个字符串abc#defa|gh
,可以看出它被字符#
和|
分隔开,strtok
的作用是取出被字符#
和|
分隔开的每块字符串
#include <stdio.h>
#include <string.h>
int main()
{char arr1[] = "abc#defa|gh";char arr2[] = "#|";char arr3[20] = { 0 };strcpy(arr3, arr1);//防止strtok直接修改被操作的字符串,所以需要拷贝一份char* ret = strtok(arr3, arr2);printf("%s", ret);return 0;
}
取出第一块被分隔的字符串
abc
并且将#
改为\0
,此时的arr3
为abc\0defa|gh
,ret
为abc
的地址,输出ret
为:
- strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
- strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
- 如果字符串中不存在更多的标记,则返回 NULL 指针。
#include <stdio.h>
#include <string.h>
int main()
{char arr1[] = "abc#defa|gh";char arr2[] = "#|";char arr3[20] = { 0 };strcpy(arr3, arr1);//防止strtok直接修改被操作的字符串,所以需要拷贝一份char* ret = strtok(arr3, arr2);printf("%s\n", ret);ret = strtok(NULL, arr2);//为了取出剩下部分的字符串,第一个参数需要改为NULLprintf("%s\n", ret);ret = strtok(NULL, arr2);printf("%s\n", ret);return 0;
}
如果一个字符串被某些字符分隔为很多部分,如果我们一个一个地取出就会使代码冗长,这里我们可以使用循环解决
#include <stdio.h>
#include <string.h>
int main()
{char arr1[] = "abc#defa|gh";char arr2[] = "#|";char arr3[20] = { 0 };strcpy(arr3, arr1);char* ret = NULL;for (ret = strtok(arr3, arr2); ret != NULL; ret = strtok(NULL, arr2)){printf("%s\n", ret);}return 0;
}
输出结果:
5.错误信息报告
strerror
char * strerror ( int errnum );
int main()
{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));printf("%s\n", strerror(5));return 0;
}
我们通常将变量errno
传入函数中strerror(errno)
而这个errno
变量在头文件errno.h
中,使用前必须添加这个头文件。
另外还有一个
perror
函数,使用这个函数,可以直接将错误信息打印出来,并且如果perror
中传了字符串,这个函数会先将传过去的字符串打印出来,再打印一个冒号,最后打印错误信息
C语言中字符串库函数相关推荐
- B00009 C语言分割字符串库函数strtok
切割字符串是常用的处理. 这里给出一个使用函数strtok切割字符串的例子. 使用C语言的库函数strtok来切割字符串的好处在于,可以指定任意字符作为分隔符来切割单词.使用该函数,切割字符串的分隔符 ...
- c语言中字符串数组的地址存放以及%s输出单个字符导致程序崩溃的问题
代码 总结下c语言中字符串数组的地址存放问题 #include <iostream> using namespace std; #include<bits/stdc++.h>i ...
- Go语言中字符串的查找方法小结
这篇文章主要介绍了Go语言中字符串的查找方法小结,示例的main函数都是导入strings包然后使用其中的方法,需要的朋友可以参考下 1.func Contains(s, substr string) ...
- [工具]-C语言中字符串的形式打印16进制数据
C语言中字符串的形式打印16进制数据. 这样写,输出更直观些 #define PRINT_BUF_MAX (32) #define TAG_STRING_MAX (32) static void pr ...
- c语言中字符 12是多少,c语言中字符串的讲解(DOC可编).doc
c语言中字符串的讲解(DOC可编).doc 第一部分:字符串的概念 ---字符串:用双引号引起来的一串字符.在C语言,系统将自动的为字符串添加一个结束标志\0 ,该结束标志不作为字符串的实际长度,但作 ...
- C语言中字符串的处理方式(一)
写多了 Java 代码,对 String 类 很是喜爱,可惜经典的 C 语言没有...最近在做程序过程中,发现对C语言字符串的处理很模糊,一会儿用数组,一会儿用指针,一会儿又引入 string.h.. ...
- C语言中字符串的处理方式
http://www.cnblogs.com/robin-ty/archive/2010/09/03/1817294.html 交流纽带" --<C语言程序设计 现代方法> 写多 ...
- C语言中字符串和字符数组的区别
C语言中字符串和字符数组的区别 1.基本概念 2.代码分析 3.总结 1.基本概念 字符串和字符数组很相似,但是有本质上的区别. (1) C语言中,字符串是双引号括起来的单个或多个字符的集合,编译器自 ...
- 有关C语言中字符串入栈的理解
C语言中字符串的入栈 写在前面 对于C语言中变量入栈的顺序实际上需要具体情况具体分析,不同操作系统下的编译器可能对此有不同的解释,即使对于同一个C的编译器而言,参数设定的不同也会导致编译器调整局部变量 ...
最新文章
- 源码分析Handler机制
- CSS图片布局 flex(竖着的几张图片改为一排)
- 网线主管(信息学奥赛一本通-T1242)
- 之前画得太丑了,再来张好看的.我试着改小点.但是就看不清了
- 【ElasticSearch】Es 源码之 PersistedClusterStateService 源码解读
- WidsMob Viewer Pro Mac如何批量调整照片大小及格式
- matlab调用cplex
- kettle入门教程
- Android apps 拍立知-功能实现(百度tts语音合成使用)
- 虚拟服务器的真实ip,虚拟ip和真实ip区别(图文)
- AS13 facets cannot be loaded. you can mark them as ignored to suppress this error notification处理
- Unity3d Platformer Pro 2D游戏开发框架使用教程
- 网上赚钱风口,捡芝麻丢西瓜
- 关于数据库突然变得很卡,然后发现数据库文件变的超大的时候
- KM算法matlab实现
- 2015移动安全挑战赛MSC(第二届)第一题解题思路
- 2023-01-05 长亭科技 Go 后端开发实习生二面
- matlab演奏七里香,沈员外,起风了,未闻花名,卡农
- STM32 SD FatFs读写文件FR_DISK_ERR错误可能原因
- 120个huo源地址,快来收藏!
热门文章
- angular10 从私服中安装依赖
- win7 系统时间服务器地址,win7更新系统时间的服务器地址
- matlab静脉识别,GitHub - ChenShihuan/Finger-vein-recognition: 华南理工大学课程设计——手指静脉识别项目...
- 双一流学科计算机科学与工程,“双一流”建设高校及建设学科名单
- 从建筑角度来看软件体系结构
- 王者荣耀cpu测试软件,王者荣耀90帧模式实测:骁龙888对比骁龙865,谁最强?
- 用pry阅读ruby源码--以task方法为例
- [3]云计算概念、技术与架构Thomas Erl-第7章 云基础设施机制
- Oracle 队列锁类型 Oracle Enqueue Lock Type Reference including 11g new locks
- 千禧入队问题(2023版)