摘要:字符串常量适用于那些对它不做修改的字符串函数。同时,语言提供了一系列库函数来对操作字符串,这些库函数都包含在头文件中。目标空间必须足够大,以确保能存放源字符串。拷贝个字符从源字符串到目标空间。
前言:
字符串是一种非常重要的数据类型,但是C语言不存在显式的字符串类型,C语言中的字符串都以字符串常量的形式出现或存储在字符数组中。字符串常量适用于那些对它不做修改的字符串函数。同时,C 语言提供了一系列库函数来对操作字符串,这些库函数都包含在头文件 string.h 中。
目录
</>复制代码
size_t strlen ( const char * str );
源字符串必须以 "/0" 结束。 会将源字符串中的 "/0" 拷贝到目标空间。 目标空间必须足够大,以确保能存放源字符串。 目标空间必须可变。 学会模拟实现。
例1:
</>复制代码
#include #include int main(){ int len1 = strlen("abcdef"); printf("%d/n", len1); //6 char arr[] = {"a","b","c","d","e","f"}; //错误写法 int len2 = strlen(arr); printf("%d/n", len2); //随机值 return 0;}
执行结果:
例2:
</>复制代码
int main(){ if(strlen("abc") - strlen("abcdef") > 0) printf("hehe/n"); else printf("haha/n"); system("pause"); return 0;}
执行结果:
由于此时的strlen没有进行定义,它的默认类型为无符号类型,那么两个无符号数相加减最后得出的数是一个很大的数,所以最后的结果必然是大于0的
(1)计数器
</>复制代码
#include #include int my_strlen(const char *str){ int count = 0; assert(str != NULL); while(*str != "/0") { count++; str++; } return count;}int main(){ int len = my_strlen("abcdef"); printf("%d/n", len); return 0;}
(2)指针-指针
</>复制代码
#include int my_strlen(const char *str){
const char *p = str;
while(*p != "/0")
{
p++;
}
return p-str;}int main(){
int len = 0;
char arr[10]="abcdef";
len = my_strlen(arr);
printf("%d/n", len);
return 0;}
(3)递归
不创建临时变量求字符串长度
</>复制代码
#includeint my_strlen(const char *str){
if(*str=="/0")
return 0;
else
return 1+my_strlen(str+1);}int main(){ int len = 0;
char arr[10]="abcdef";
len = my_strlen(arr);
printf("%d/n", len); return 0;}
</>复制代码
char* strcpy(char * destination, const char * source);
例:
</>复制代码
#include int main(){ char arr1[] = "abcdefghi"; char arr2[] = "bit"; //错误示范 //char *arr1 = "abcdefghi"; //p指向常量字符串,而常量字符串无法被修改 //char arr2[] = {"b","i","t"}; //由于此时没有给"/0",由于找不到"/0"会导致向后越界访问 strcpy(arr1, arr2); printf("%s/n", arr1); return 0;}
</>复制代码
#include #include char *my_strcpy(char *dest, const char *src){ assert(dest != NULL); assert(src != NULL); char *ret = dest; //拷贝src指向的字符串到dest指向的空间,包含"/0" while(*dest++ = *src++) { ; } //返回目的的空间的初始地址 return ret;//"/0"}int main(){ char arr1[] = "abcdefgh"; char arr2[] = "bit"; my_strcpy(arr1, arr2); printf("%s/n", arr1); return 0;}
</>复制代码
char * strcat ( char * destination, const char * source );
例:
</>复制代码
#include int main(){ char arr1[30] = "hello/0xxxxxxx"; char arr2[] = "wolrd"; strcat(arr1, arr2); printf("%s/n", arr1); //错误示范 char arr3[] = "hello"; char arr4[] = "world"; strcat(arr3, arr4); printf("%s/n", arr3); //由于arr3数组没有定义空间大小 //此时就开辟了"hello/0"6个字节 //当arr4数组追加过去后就产生了越界访问,产生报错 return 0;}
调试结果:
执行结果:
总结:此时我们可以看到,arr2数组内的的字符串从arr1数组中的"/0"开始进行追加
当arr2数组内的字符串追加过去后,后面的‘/0’也一并追加了过去
当目标空间不够大时,就会造成访问越界
</>复制代码
#include #include char *my_strcat(char *dest, const char *src){ assert(dest != NULL); assert(src); char *ret = dest; //1.找到目的字符串的"/0" while(*dest != "/0") { dest++; } //2.追加 while(*dest++ = *src++) { ; } return ret;} int main(){ char arr1[30] = "hello"; char arr2[] = "wolrd"; my_strcat(arr1, arr2); printf("%s/n", arr1); return 0;}
</>复制代码
int strcmp (const char * str1, const char * str2 );
此函数开始比较每个字符串的第一个字符。 如果它们彼此相等,则继续使用以下对,直到字符不同或到达终止空字符为止。
标准规定:
</>复制代码
#include #include int main(){ char *p1 = "qbc"; char *p2 = "abc"; // int ret = strcmp(p1, p2); // printf("%d/n", ret); if(strcmp(p1, p2) > 0) { printf("p1 > p2/n"); } else if(strcmp(p1, p2) == 0) { printf("p1 == p2/n"); } else if(strcmp(p1, p2) < 0) { printf("p1 < p2/n"); } return 0;}
</>复制代码
#include #include int my_strcmp(const char *str1, const char *str2){ assert (str1 && str2); // 比较 while(*str1++ == *str2++) { if(*str1 == "/0") { return 0;//等于 } } if(*str1 > *str2) return 1;//大于 else return -1;//小于 //return (*str1 - *str2); //通过相减判断大于或小于}int main(){ char *p1 = "abcdef"; char *p2 = "abqwe"; int ret = my_strcmp(p1, p2); printf("ret = %d/n", ret); return 0;}
</>复制代码
char * strncpy ( char * destination, const char * source, size_t num );//单位是字节
例1:
</>复制代码
int main(){ char arr1[10] = "abcdefgh"; char arr2[] = "bit"; stcncpy(arr1, arr2, 6); return 0;}
调试结果:
例2:
</>复制代码
#include #include int main(){ char arr1[10] = "abcdefgh"; char arr2[] = "bit"; strncpy(arr1, arr2, 6); return 0;}
调试结果:
由此可见,strncpy函数能拷贝任意长度的字符,当拷贝的字符长度不够拷贝数时,用 "/0" 进行补充,直到拷贝数相等
</>复制代码
#include #include void my_strncpy(char *dest, const char *src, int n){ assert(src); char* p1 = dest; const char* p2 = src; while (n--) { *p1++ = *p2++; }}int main(){ char arr1[20] = "hello" char arr2[] = "world"; my_strncpy(arr1, arr2, 3); return 0;}
</>复制代码
char * strncat ( char * destination, const char * source, size_t num );
例1:
</>复制代码
#include #include int main(){ char arr1[30] = { "hello/0xxxxxx" }; char arr2[] = "world"; strncat(arr1, arr2, 4); return 0;}
调试结果:
例2:
</>复制代码
int main(){ char arr1[30] = { "hello/0xxxxxxxxx" }; char arr2[] = "world"; strncat(arr1, arr2, 8); return 0;}
调试结果:
由此可见,不管追加几个数,都会在追加字符串后加上 "/0",而一旦追加数超过了追加字符串的长度,在追加完整字符串后面再加上"/0"后便结束了
</>复制代码
#include#include#includevoid my_strncat(char* dest, const char* src, int len1, int len2, int n){
char* ret = dest + len1;
assert(src);
assert(n <= len2);
while ((n--) && (*ret++ = *src++)) {
; }}int main(){
char arr1[20] = "abcd";
char arr2[] = "efghi";
int len1 = strlen(arr1);
int len2 = strlen(arr2);
int n = 0;
scanf("%d", &n);
my_strncat(arr1, arr2, len1, len2, n);
return 0;}
</>复制代码
int strncmp ( const char * str1, const char * str2, size_t num );
例:
</>复制代码
#include #include int main(){ const char* p1 = "abcdef"; const char* p2 = "abcqwer"; int ret = strncmp(p1, p2, 4); printf("%d/n", ret);}
执行结果:
</>复制代码
#include#include#includeint my_strncmp(const char *dest, const char *src, int n){
int ret = 0;
assert(dest);
assert(src);
assert(n);
while( (n--) && !(ret = (unsigned char)*dest-(unsigned char)*src) && *dest )
{
dest++;
src++;
}
return ret;}int main(){
char arr1[] = "abcdef";
char arr2[] = "abcedef";
int n = 0;
int ret = 0;
int i = 0;
scanf("%d",&n);
ret = my_strncmp(arr1, arr2, n);
if(ret == 0)
{
for(i=0; i- for(i=0; i
- printf(" %c",arr2[i]);="" }="" else="" if(ret="" <="" 0)="" {="" for(i="0;" i
");
for(i=0; i
四、字符串查找
strstr
</>复制代码
char * strstr ( const char *, const char * );
- 返回指向 str1 中第一次出现 str2 的指针,如果 str2 不是 str1 的一部分,则返回空指针。
例:
</>复制代码
int main(){ char *p1 = "abcdefabcdef"; char *p2 = "def"; char * ret = strstr(p1, p2); if(ret == NULL) { printf("子串不存在"); } else { printf("%s/n", ret); } system("Pause"); return 0;}
执行结果:
由此可得出,当有主字符串中存在两个及以上子串时,优先按第一次出现相同的地址进行打印,并且会一直打印完剩下的字符串
strstr函数的模拟实现
</>复制代码
#include #include //KMP 算法char *my_strstr(const char *p1, const char *p2){ assert(p1 != NULL); assert(p2 != NULL); char *s1 = NULL; char *s2 = NULL; char *cur = (char*)p1;//当前指针current if(*p2 == "/0") { return (char*)p1; } while(*cur) { s1 = cur; s2 = (char*)p2; while(*s1 && *s2 && (*s1 == *s2)) { s1++; s2++; } if(*s2 == "/0") { return cur;//找到子串 } cur++; } return NULL;//找不到子串}int main(){ char *p1 = "abcdef"; char *p2 = "def"; char * ret = my_strstr(p1, p2); if(ret == NULL) { printf("子串不存在/n"); } else { printf("%s/n", ret); } return 0;}
strtok
</>复制代码
char * strtok (char *str, const char *sep);
- sep参数是个字符串,定义了用作分隔符的字符集合
- 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
- strtok函数找到str中的下一个标记,并将其用 /0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改 变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
- strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
- strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
- 如果字符串中不存在更多的标记,则返回 NULL 指针。
例:
</>复制代码
#include #include int main(){ char arr[] = "qpzyahxf@163.com"; char *p = "@."; char buf[1024] = {0}; //strtok会改变字符串内容,buf防止原字符串被切割(保护原始数据) strcpy(buf, arr); //切割buf中的字符串 char *ret = NULL; for(ret = strtok(arr, p); ret != NULL; ret = strtok(NULL, p)) { printf("%s/n", ret); } // char *ret = strtok(arr, p); // printf("%s/n", ret); // ret = strtok(NULL, p); // printf("%s/n", ret); // ret = strtok(NULL, p); // printf("%s/n", ret); return 0;}
执行结果:
strtok函数的模拟实现
</>复制代码
#include char *my_strtok(char *str1 ,char *str2){ static char *p_last = NULL; if(str1 == NULL && (str1 = p_last) == NULL) { return NULL; } char *s = str1; char *t = NULL; while(*s != "/0") { t = str2; while(*t != "/0") { if(*s == *t) { p_last = s + 1; if( s - str1 == NULL) { str1 = p_last; break; } *s = "/0"; return str1; } t++; } s++; } return NULL;}int main() { char arr[] = "qpzyahxf@163.com"; char *ret = NULL; char *p = "@."; for(ret = my_strtok(arr, p); ret != NULL; ret = my_strtok(NULL, p)) { printf("%s/n", ret); } return 0; }
五、错误信息报告
strerror
</>复制代码
char * strerror(int errum);
返回错误码,所对应的错误信息。
例1:
</>复制代码
#include #include int main(){ int i = 0; //1-10错误码的返回返回信息 for(i = 0; i <= 10; i++) { printf("%d %s/n", i, strerror(i)); } system("pause"); return 0;}
执行结果:
在实际在使用的时候,错误码并非由我们来控制的,而是接收系统返回的错误信息
例2:
</>复制代码
#include #include string.h>#include char *str = strerror(errno);//需引用头文件errno.h printf("%s/n", str); //errno 是一个全局的错误码的变量 //当c语言的库函数在执行过程中,发生了错误,就会把对应的错误码,复制到errno中
例3:
</>复制代码
#include #include int main(){ //打开文件 FILE *pf = fopen("test.txt", "r"); if(pf == NULL) { printf("%s/n", strerror(errno));//知道错误的原因 } else { printf("open file success./n"); } return 0;}
执行结果:
六、字符操作
字符分类函数
函数 如果他的参数符合下列条件就返回真 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 任何可打印字符,包括图形字符和空白字符
注:0位假,非0为真
字符转换
</>复制代码
int tolower ( int c ); //tolower 转小写字母int toupper ( int c );//toupper 转大写字母
例1:
</>复制代码
#include #include int main(){ char ch = tolower("Q"); putchar(ch); system("pause"); return 0;}
执行结果:
例2:
</>复制代码
#include #include int main(){ //大写字母转小写 char arr[] = "No Mercy"; int i = 0; while(arr[i]) { if(isupper(arr[i])) { arr[i] = tolower(arr[i]); } i++; } printf("%s/n", arr); return 0;}
执行结果:
七、内存操作函数
在之前的学习中,我们了解了字符串拷贝可以使用strcpy函数,但是strcpy函数具有局限性。
当拷贝的数据不是字符串时,比如说int类型、float类型,还能使用strcpy函数吗?
strcpy函数在拷贝的时候是以/0为字符串拷贝的结束标志,那么在拷贝其它类型数据的时候,拷贝该结束的时候不一定存在/0。所以使用strcpy函数肯定是行不通的。那怎么办呢?
此时我们就可以使用memcpy函数-- - 内存拷贝函数,用来拷贝任意类型数据。
memcpy
</>复制代码
void *memcpy ( void * destination, const void * source, size_t num );//void* - 通用类型的指针-无类型指针//dest destination 表示内存拷贝的目的位置//src source 表示内存拷贝的起始位置//size_t num 表示内存拷贝的字节数
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置
- 这个函数在遇到 "/0" 的时候并不会停下来
- 如果source和destination有任何的重叠,复制的结果都是未定义的。
例:
</>复制代码
int main(){ int arr1[] = { 1,2,3,4,5 }; int arr2[5] = { 0 }; memcpy(arr2, arr1, sizeof(arr1)); return 0;}
调试结果:
memcpy函数的模拟实现
</>复制代码
void *my_memcpy ( void *dest, const void *src, size_t num) { void *ret = dest; assert(dest && src); while (num--) { //*(char*)dest = *(char*)src;
//dest = (char*)dest + 1;//++(char*)dest
//src = (char*)src + 1;//++(char*)src *((char*)dest)++ = *((char*)src)++; } return ret; }int main(){ int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
my_memcpy(arr2, arr1, 20); return 0;}
memmove
</>复制代码
void * memmove ( void * destination, const void * source, size_t num ); //void* - 通用类型的指针-无类型指针//dest destination 表表示内存移动的目的位置//src source 表示内存移动的起始位置//size_t num 表示移动内存的字节数
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的
- 如果源空间和目标空间出现重叠,就得使用 比特科技 memmove函数处理
memmove函数的模拟实现
</>复制代码
void *my_memmove( void *dest, const void *src, size_t num) { void * ret = dest; assert(dest && src); if (dest <= src || (char *)dest >= ((char *)src + num)) { while (num--) { *(char*)dest = *(char*)src; dest = (char*)dest + 1;
src = (char*)src + 1; } } else { //从后向前拷贝 while (num--) { *((char*)dest + num) = *((char*)src + num); } } return ret; } int main(){ int arr1[10] = {0,1,2,3,4,5,6,7,8,9}; int arr2[10] = {0}; my_memmove(arr1 + 2, arr1, 20); return 0;}
memset
</>复制代码
void* memset(void* dest, int c, size_t count);
作用:Sets buffers to a specified character.(将缓冲区设置为指定的字符)
以字节为内存设置单位
例:
</>复制代码
#include#includeint main(){
char arr[] = "abcdefg";
memset(arr, "*", 4);
printf("%s", arr);
return 0;}
执行结果:
memcmp
</>复制代码
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
- 比较从ptr1和ptr2指针开始的num个字节
- 返回值如下
例:
</>复制代码
#include#includeint main(){
int arr1[5] = { 1,2,3,4,5 };
int arr2[5] = { 1,2,3,4,8 };
int ret = memcmp(arr1, arr2, sizeof(arr1));
if (ret > 0)
{
printf("arr1 > arr2");
}
else if (ret == 0)
{
printf("arr1 == arr2");
}
else
{
printf("arr1 < arr2");
}
return 0;}
执行结果:
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/118797.html
相关文章
-
【C语言进阶】☀️数据类型&amp;&amp;整型在内存中的存储
目录 一、数据类型介绍 二、类型的意义 三、类型的基本归类 整型家族 浮点数家族 构造类型(自定义类型) 指针类型 空类型 四、整形在内存中的存储 原码、反码、补码 大小端字节序 为什么有大端和小端? 一道经典笔试题 一、数据类型介绍 数据从大的方向分为两类: 内置类型自定义类型内置类型我们前面已经学习过,如下: char //字符数据类型 short ...
-
【C语言进阶】自定义类型(2)枚举&amp;联合
目录 一、枚举 (一)枚举类型的定义 (二)使用枚举的原因 (三)枚举的优点 (四)枚举的大小 (五)枚举的使用 二、联合(共用体) (一)联合类型的定义 (二)联合的特点 (三)面试题 (四)联合大小的计算 一、枚举 枚举顾名思义就是:列举 。 即把可能的取值一一列举出来。 比如我们现实生活中: 一周当中从周一至周日的7天,可以一一列举;性别有:男、女、保密,可以一一列举;月份有...
-
JavaScript进阶之函数和对象知识点详解
在过往学习的JavaScript都是在基础,现在为大家介绍更为深入的JavaScript知识。 JavaScript函数 JavaScript函数和Java函数是有一部分相似的,所以学习起来也会相对简单 基本构造 1.直接构造 //function代表函数标志,name为函数名称,参数可有可无
functionname(参数){
//...
return;
} 2....
-
python数学建模Numpy应用介绍与Pandas学习
小编写这篇文章的主要目的,主要是来给大家解答下关于python数学建模的一些相关的介绍,涉及到内容涵盖Numpy的一些相关的应用具体的一些介绍。另外,还会涉及到相关的Pandas学习知识,具体内容下面给大家详细解答下。 1 Numpy介绍与应用 1-1Numpy是什么 NumPy是一个运行速度非常快的数学库,一个开源的的python科学计算库,主要用于数组、矩阵计算,包含: 一个强大的...
-
python数学建模之Numpy应用介绍与Pandas学习
小编写这篇文章的一个主要目的,主要是来给大家去做一个介绍。介绍的内容主要是关于建模知识的一些相关介绍,包括其Pandas的一些相关学习,就具体的操作内容,下面就给大家详细解答下。 Numpy学习 1 Numpy介绍与应用 1-1Numpy是什么 NumPy是一个运行速度非常快的数学库,一个开源的的python科学计算库,主要用于数组、矩阵计算,包含: 一个强大的N维数组对象ndarr...
发表评论
0条评论
pingan8787
男|高级讲师
TA的文章
阅读更多
查询tensorflow版本
阅读 827·2023-04-25 22:50
记录不存在则插入,存在则更新 → MySQL 的实现方式有哪些?
阅读 1665·2021-10-08 10:05
阿里云存储,让更多的创新在身边发生
阅读 1092·2021-09-30 09:47
自动化测试系列(三)|UI测试
阅读 2050·2021-09-28 09:35
C++入门—namespace的使用傻傻分不清楚&C++中函数的参数也可以配备胎&a
阅读 950·2021-09-26 09:55
大数求余C++(超级牛逼)
阅读 3529·2021-09-10 10:51
【C语言进阶】字符串&内存函数
阅读 3589·2021-09-02 15:15
80VPS:日本/香港CN2服务器首月420元(续费600元),E5/16G/1TB/20M带宽
阅读 3391·2021-08-05 09:57
阅读需要支付1元查看
<