适合初学者的字符函数和字符串函数(学不会打我)上
创始人
2025-05-28 08:09:24
0

目录

长度不受限制的字符串函数

strlen部分

strlen函数的易错小知识

strlen函数的实现

strcpy部分

strcat部分

 自己实现strcat

strstr函数部分

简单例子:

分析 

strcmp部分

 长度受限制的字符串函数

strncpy

简单例子

strncat

strncmp

简单例子

👉 本菜鸡&总结 👈

 

😎博客昵称:陈大大陈

😊座右铭:所谓觉悟,就是在漆黑的荒野上开辟出一条理当前进的光明大道。

😋博主简介:一名热爱C/C++和算法等技术,喜欢运动,爱胡思乱想却胸怀大志的小博主!

😚博主&唠嗑:早午晚哈喽Ciao!😄各位CSDN的朋友!😄我是博客新人陈大大陈,希望我的文章能为你带来帮助!欢迎大家在评论区畅所欲言!也希望大家多多为我提出您宝贵的建议!😘如果觉得我写的不错的话还请点个赞和关注哦~😘😘😘

10d810c44eb60ab102be7e5b2e50ff19.gif

长度不受限制的字符串函数

strlen部分

strlen函数的易错小知识

我们知道,strlen函数是用来求字符串的长度的。

size_t strlen( const char *string );

Each of these functions returns the number of characters in string, excluding the terminal NULL.

其中每个函数都返回字符串中的字符数,到\0为止(不包括\0),不包括NULL指针。

需要注意的是,strlen的返回类型是size_t.

size_t 是一些C/C++标准在stddef.h中定义的,size_t 类型表示C中任何对象所能达到的最大长度,它是无符号整数。

初学者很容易误以为strlen的返回类型是int,这点需要特别注意,看下面的代码来巩固。

#include 
#include
int main()
{const char* str1 = "chendada";const char* str2 = "chen";if (strlen(str2) - strlen(str1) > 0){printf("str2>str1\n");}else{printf("srt1>str2\n");}return 0;
}

运行结果如下: 

 嘻嘻,不知道有多少老铁踩坑了?😋可不能想当然地认为结果是个负数,切记strlen的返回类型是无符号整形!

这两个字符串长度相减的结果,如果从整形的角度来看,是-4没错,但是我们的返回类型是无符号整形,而无符号整形减去无符号整形的结果也是一个无符号整形。

也就是说,-4储存在内存中的补码并没有转换成源码来参与运算,而是直接被当成是一个数字来参与运算,我们知道,这个运算的结果一定是一个正数。

strlen函数的实现

strlen函数的实现更是多种多样,我在这里列出以下三种。

1.计数器

2.递归

3.指针-指针

//计数器方式
int my_strlen(const char * str)
{int count = 0;while(*str){count++;str++;}return count;
}
//递归,不需要创建临时变量计数器
int my_strlen(const char * str)
{if(*str == '\0')return 0;elsereturn 1+my_strlen(str+1);
}
//指针-指针的方式
int my_strlen(char* str)
{char* p = str;while (*p != '\0'){p++;}return p - str;
}

我们在这里将返回类型改成int,这样可以有效规避上面无符号整形导致误判的情况。 

在以上代码里,我们都可以加入const和assert断言函数来让程序更安全。

strcpy部分

函数的参数形式char* strcpy(char*destination,const char*source);

该参数说明了strcpy返回类型是char类型的指针,将源头(不能被改)拷贝到目的地。

strcpy特点和strlen类似,遇到‘\0’就停止。

看下面的代码,最后打印的是什么呢?

#include 
#include}
int main()
{char str1[100] = "chen\0dada";char str2[100] = "xxxxxxxxx";strcpy(str2, str1);printf("%s", str2);return 0;
}

运行结果如下:

正如上面所说,遇到\0就停止。

可以看到,strcpy会将\0也一并拷过去。

需要特别注意的是,目标空间必须可变,且必须足够大,用来确保能存放源字符串。

自己实现strcpy的方式非常多,在自制strcpy函数之前,我们需要知道,strcpy函数返回的是目标空间的起始地址,所以它的返回类型是一个指针,例如char *。

我们知道源头的地址不能改变,所以我们要加上const来修饰。

同时,为了确保指针有效,我们使用断言函数。

char* my_strcpy(char* dest, const char* src)
{char* ret = dest;//目标空间的起始地址assert(dest && src);while ((*dest++ = *src++)){;}return ret;
}

strcpy函数返回的是目标空间的起始地址,所以它的返回类型是一个指针,例如char *。

我们可以用这一点实现下面的代码。

#define _CRT_SECURE_NO_WARNINGS
#include
#include
char* my_strcpy(char* dest, const char* src)
{char* ret = dest;assert(dest != NULL);while ((*dest++ = *src++)){;}return ret;
}
int main()
{char a[10] = "";char b[] = "dada";printf("%s", my_strcpy(a, b));return 0;
}

strcat部分

char * strcat ( char * destination, const char * source );
Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.
  • 源字符串必须以 '\0' 结束。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。
简单的例子如下:
#include 
#include void main( void )
{char string[80];strcpy( string, "Hello world from " );strcat( string, "strcpy " );strcat( string, "and " );strcat( string, "strcat!" );printf( "String = %s\n", string );
}

strcat函数是从\0的位置开始,会将\0用第一个元素覆盖。

那strcat能不能将自己拷贝到自己后面,即函数的参数为同一字符串呢?

我们看下面的代码。

 自己实现strcat

char* my_strcat(char* dest, const char* src)
{char* ret = dest;assert(dest != NULL);assert(src != NULL);while (*dest){dest++;}while ((*dest++ = *src++)){;}return ret;
}

答案自然是不行的,调试会一直卡在这个位置,程序是死循环的结果。

为什么会死循环呢?请看我做的图。

一开始是这样,dest和src全都指向第一个字符。

然后dest找到\0的位置,准备开始拷贝。

 

紧接着\0被转化为c,且src向后位移一个字节。 

这样下去的结果是。

 dest应该去找下一个\0,可是\0已经在上面被字符'C'覆盖,也就是说,\0已经不复存在,程序崩溃。

strstr函数部分

char *strstr( const char *string, const char *strCharSet )

Each of these functions returns a pointer to the first occurrence of strCharSet in string, or NULL if strCharSet does not appear in string. If strCharSet points to a string of zero length, the function returns string.

Each of these functions returns a pointer to the first occurrence of strCharSet in string, or NULL if strCharSet does not appear in string. If strCharSet points to a string of zero length, the function returns string.

函数返回一个指针,指向字符串中第一次出现的地址,如果该地址未出现在字符串中,则返回 NULL。如果该地址指向长度为零的字符串,则该函数返回字符串。

简单例子:

#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include
char * my_strstr(char* a, char* b)
{assert(a && b);char* s1 = NULL;char* s2 = NULL;char* cp = a;while (*cp){s1 = cp;s2 = b;while (*a++ == *b++){;}if (*b == '\0'){return cp;}cp++;}return NULL;}int main()
{char a[10] = "bcdef";char b[10] = "cde";if (my_strstr(a, b) == NULL){printf("找不到");}else{printf("找到了,地址是%p", my_strstr(a, b));}return 0;
}

分析 

  • 假设有两个字符串,指针str1, str2分别指向字符串首字母。
  • 要在str1中查找str2并打印出来,先判断str1和str2指向的字符是否相等,此时有两种情况:第一种情况指向的字符不相等,str1要指向下一个字符,再判断,如此循环往复,当str1指向的是 '\0' 时,可以判断出str1中不存在str2,此时返回NULL;
  • 第二种情况下指向的字符相等,那么不仅str1要向后读取字符,str2也要向后读取字符,再判断是否相等。
  • 在向后读取字符的过程中,仍有两种情况:1.str1和str2指向的字符一直相等,直到str2指向'\0',这时可以知道str1中存在str2字符串,返回的是str1中的str2字串的第一个字符地址;
  • 2.str1和str2指向的字符不全相等,例如下图中,*(str1+1) == *str2,*(str1+2) == *(str2+1),*(str1+3) != *(str2+2),此时指针str2就要返回到字符串str2首字符的地址,而指针str1需要返回到第一次和str2指向的字符相等的后一个位置,即字符串str1中第二个 'b' 的地址。然后又回到一开始的判断。

strcmp部分

strcmp函数是专门用来字符串之间的的比较的
这个比较是比较两个字符串是否相同,如果不相同那就比较两个字符串的长度大小。

int strcmp( const char *string1, const char *string2 );

strcmp函数的参数是两个字符串,返回值为整形 

当如果字符串1与字符串2相等则返回值为0。
如果字符串不一样,并且字符串1>字符串2,则返回值>0。

反之返回值小于零。

strcmp函数比较的是两个字符串不相等的第一个字符的ASCII值。

如果有一方是\0,则非零的字符串较大。

模拟实现strcmp函数

我给出以下两种方法:

#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include
int my_strcmp(char* a, char* b)
{assert(a && b);while (*a == *b){if (*a == '\0'){return 0;}a++;b++;}return *a - *b;
}
int main()
{char a[10]="abcdef";char b[10]="abc";if (my_strcmp(a,b) > 0){printf("a>b");}if (my_strcmp(a, b) == 0){printf("a==b");}if(my_strcmp(a,b)==0){printf("a
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 );
}

 长度受限制的字符串函数

strncpy

char *strncpy( char *strDest, const char *strSource, size_t count );

  • 复制字符串src中的内容到字符串dest中,复制多少由size_t参数的值决定。
  • 如果src的前n个字符不含NULL字符,则结果不会以NULL字符结束。
  • 如果n需要我们再手动添加一个'\0'。
  • 如果src的长度小于n个字节,则以NULL填充dest直到复制完n个字节。src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符长度+'\0'。 

简单例子

#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
int main()
{char a[10]="******";char b[10]="chenda";strncpy(a, b, 2);printf("%s", a);return 0;
}

strncat

char *strncat( char *strDest, const char *strSource, size_t count );

#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
int main()
{char a[15]="hello \0 ******";char b[15]="world";strncat(a, b, 6);printf("%s", a);return 0;
}

如图所示 : 

 

调试过程如图所示。 

 我们可以看到,strncat会自动添加\0,且到\0为止,不会再去将其它字符化为\0。

strncmp

int strncmp ( const char * str1, const char * str2, size_t num );
比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完为止。

 

 返回值判断方法和strcmp基本相等。

简单例子

#include 
#include 
int main()
{char a[20]="hello world";char b[15]="hello";if (strncmp(a, b, 4) == 0){printf("相等");}elseprintf("不相等");return 0;
}

 前五个字符相等。

👉 本菜鸡&总结 👈

这篇博客旨在总结我自己阶段性的学习,要是能帮助到大家,那可真是三生有幸!😀如果觉得我写的不错的话还请点个赞和关注哦~我会持续输出编程的知识的!🌞🌞🌞 

相关内容

热门资讯

安卓如何操控苹果系统,揭秘跨平... 你知道吗?在这个科技飞速发展的时代,安卓和苹果两大操作系统之间的较量可是从未停歇。虽然它们各自有着忠...
安卓系统账户同步数据,畅享无缝... 你有没有遇到过这种情况:手机里存了那么多宝贝照片、重要文件,结果换了个新手机,却发现那些宝贝全都不翼...
安卓系统不停推送广告,安卓系统... 你有没有发现,最近你的安卓手机是不是越来越“热情”了?没错,就是那个不停在你屏幕上跳来跳去的广告!今...
airpods可以和安卓系统,... 你有没有想过,那些炫酷的AirPods竟然也能和安卓手机完美搭配?没错,就是那个我们平时只听说和iP...
安卓系统实体键盘不对,创新与挑... 你是不是也遇到了这个问题?安卓手机的实体键盘突然不对劲了,按下去没反应,或者反应迟钝,简直让人抓狂!...
汽车导航改装安卓系统,安卓系统... 你有没有想过,你的汽车导航系统是不是已经out了?现在,让我来给你揭秘如何给你的爱车来一次科技大变身...
安卓系统如何限制下载,安卓系统... 你有没有发现,手机里的安卓系统越来越智能了?不过,这也意味着有时候我们不小心就会下载一些不想要的软件...
安卓系统调成日语,概要の副標題... 你有没有想过,你的安卓手机竟然可以变成一个日式小天地呢?没错,就是那种动漫里常见的日语界面,是不是听...
男生耳机推荐安卓系统,男生耳机... 耳机可是现代生活中不可或缺的小玩意儿,尤其是对于喜欢听音乐的男生来说,一副好耳机简直就是灵魂的伴侣。...
安卓同版本升级系统,功能优化与... 你知道吗?最近手机界可是热闹非凡呢!各大品牌纷纷推出了安卓同版本升级系统,让我们的手机焕然一新。今天...
安卓更换别的手机系统,轻松切换... 你有没有想过,你的安卓手机用久了,是不是有点审美疲劳了呢?或者,你最近是不是对其他手机系统产生了浓厚...
安卓系统单机神雕侠侣,指尖重温 你有没有想过,在手机上也能体验一把江湖恩怨、侠骨柔肠?没错,就是那个让人心驰神往的《神雕侠侣》!今天...
安卓系统键盘语言切换,安卓系统... 你有没有发现,手机上的安卓系统键盘语言切换功能,简直就像是个神奇的魔法棒,轻轻一点,就能让文字飞舞在...
oppok1安卓系统,性能与体... 你有没有发现,最近手机圈里又掀起了一股热潮?没错,就是OPPO K1这款新机!这款手机不仅外观时尚,...
安卓系统环境的搭建,从零开始构... 想要在电脑上体验安卓系统的魅力,是不是已经跃跃欲试了呢?别急,今天就来手把手教你如何搭建一个属于自己...
【MySQL】锁 锁 文章目录锁全局锁表级锁表锁元数据锁(MDL)意向锁AUTO-INC锁...
【内网安全】 隧道搭建穿透上线... 文章目录内网穿透-Ngrok-入门-上线1、服务端配置:2、客户端连接服务端ÿ...
GCN的几种模型复现笔记 引言 本篇笔记紧接上文,主要是上一篇看写了快2w字,再去接入代码感觉有点...
数据分页展示逻辑 import java.util.Arrays;import java.util.List;impo...
Redis为什么选择单线程?R... 目录专栏导读一、Redis版本迭代二、Redis4.0之前为什么一直采用单线程?三、R...