字符函数和字符串函数

简介: 字符函数和字符串函数

0. 前言


C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在

常量字符串 中或者 字符数组 中。

字符串常量 适用于那些对它不做修改的字符串函数。


1.无限制长度的库函数类型


1.1 strlen


54c19d70b8244fe59e7602915446a4f1.png


库函数 strlen的作用就是计算某个字符串的大小。之前在操作符sizeof那一结就看到过strlen,之前就有稍稍做过一些简介。


从这个函数结构看,它返回的是一个size_t 类型的值,这里解释一下size_t。


size_t

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


那么我们可以来尝试模拟实现一下strlen。上代码

#include <stdio.h>
#include <assert.h>
size_t my_strlen(const char* str)
{
  assert(str);//对传进的数组进行断言,确保str不为'\0 '
  const char* start = str;
  const char* end = str;
  while (*end != '\0')
  {
    end++;
  }
  return end - start;
}
int main()
{
  char arr[] = "hello bit";
  printf("%d", my_strlen(arr));
  return 0;
}

介绍一下assert:断言


dc75253000ef4d1fb74696f76d07e664.png

如果具有函数形式的此宏的参数表达式比较等于零(即表达式为 false),则会将消息写入标准错误设备并调用,从而终止程序执行。


介绍一下const:


我们之前最开始就见过这个玩意,在常量与变量那一章节的时候。被const修饰过的变量,就无法修改了。

常量指针有两种定义:

const int * p = 20;
int * const p =20;


第一种定义:const在 * 的左边,表示指针指向的内容,不可以通过指针来改变,但指针本身是可以发生改变的,可以通过一个其他的来改变。


第二种定义:const在 * 的右边,表示,这里修饰的指针变量p,表示指针变量不能被改变,但是之指针所指向的内容是可以发生改变的。


我们这里不希望改变指针str的值,所以对它用const修饰。


1.2 strcpy


5444fa2acf514b99a37e486e2cd3c84a.png

指向的 C 字符串复制到目标所指向的数组中,包括终止 null 字符(并在该点停止)。

我们也对strcpy进行模拟实现

#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src)
{
  assert(dest);//对dest断言防止出现sdest为'\0'的情况
  assert(src);//对src断言防止出现src为'\0'的情况
  char* ret = dest;
  while (*dest++ = *src++)//每次循环将src赋给dest并且同时向后移动指针
  {
    ;//当src为\0时循环结束
  }
  return ret;
}
int main()
{
  char arr1[20] = "abc";
  char arr2[] =   "hello bit";
  printf("%s\n", my_strcpy(arr1, arr2));
  return 0;
}

c82e23382384444c92d581b9e91ddb4e.png


我们在对strcpy进行模拟实现或者是使用都必须注意几点


1.源字符串必须以 '\0' 结束。

2.会将源字符串中的 '\0' 拷贝到目标空间。

3.目标空间必须足够大,以确保能存放源字符串。

4.目标空间必须可变


否则就会发生各种各样的错误。


1.3 strcat


2a7f2dfc50954c66a4c2d45a55cc9d7c.png


字符串的副本追加到目标字符串。目标中的终止空字符被的第一个字符覆盖,并且空字符包含在由目标中两者的串联组成的新字符串的末尾。


注意事项:


源字符串必须以 '\0' 结束。


目标空间必须有足够的大,能容纳下源字符串的内容。

目标空间必须可修改。


模拟实现:

#include <stdio.h>
char* my_strcat(char* str1,const char* str2)
{
  char* ret = str1;//保存ch1的首元素地址
  while (*str1 != '\0')
  {
    str1++;
  }//表示找到了str1也就是ch1的结尾处
  while (*str1++ = *str2++)//追加
  {
    ;
  }
  return ret;
}
int main()
{
  char ch1[20] = "hello ";
  char ch2[] = "world";
  printf("%s", my_strcat(ch1, ch2));
  return 0;
}


看看结果:


3a76100674004bda8b46637dbeeb63ad.png


那我们是否可以自己给自己追加呢?


假设ch1 为  " hello " 根据上面代码的思路,我们先找到自己的 ' \0 ' 处,然后将 ‘ h ’ 给到 ' \0 ' ,当这一步进行以后,我们原来的ch1就不再是  " hello " 而是 " helloh "。那我们一直往后追加,就永远追不到结尾' \0 '。直到程序奔溃。


所以我们不可以用strcat给自己追加自己。


1.4 strcmp


b0ea7b0d3eb7498b89fb40a8cf4dbba4.png


对两个字符串的比较。

标准规定:


第一个字符串大于第二个字符串,则返回大于 0 的数字

第一个字符串等于第二个字符串,则返回 0

第一个字符串小于第二个字符串,则返回小于 0 的数字


#include <stdio.h>
#include <assert.h>
int my_strcmp(const char* str1, const char* str2)
{
  assert(str1 && str2);//断言
  while (*str1 == *str2)//判断str1 和 str2 每个对于的字符是否相等
  {
    if (*str1 == '\0')//这是在str1 和str2 相等的条件下进行的,当str1 ='\0'时,str2 ='\0'
    {
      return 0;
    }
    str1++;
    str2++;
  }
  return *str1 - *str2;//返回两个差值
}
int main()
{
  char ch1[] = "abc";
  char ch2[] = "abc";
  int key = my_strcmp(ch1, ch2);
  if (key > 0)
  {
    printf("ch1 > ch2\n");
  }
  else if (key < 0)
  {
    printf("ch1 < ch2\n");
  }
  else
  {
    printf("ch1 == ch2\n");
  }
  return 0;
}


2.限制长度的库函数类型


2.1 strncpy


58d2caa6ff904848afad05c1a8ebf001.png


拷贝num个字符从源字符串到目标空间。


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


上代码:

#include <stdio.h>
int main()
{
  char str1[20] = "abcd";
  char str2[]="***";
  strncpy(str1, str2, 2);
  printf("%s\n",str1);
  return 0;
}


3cf7277e4f4848c4a096a992be69f1cc.png


但是需要注意:拷贝的大小尽量不要大于源字符串的大小,我们把上面的2改为8试试。


5b67bb00ac5b4378a02abf5704241f5a.png

我们默认添加 ' \0 '虽然对我们的目标影响不大,但是还是得尽量避免。


2.2 strcat


03a8f673144f499cb68f1d59324d0ad5.png


的前 num 个字符追加到目标,外加一个终止空字符。

如果中 C 字符串的长度小于 num,则仅复制到终止空字符之前的内容。

上代码:

#include <stdio.h>
int main()
{
  char str1[20] = "abcd\0hijkln";//为了区别追加字符串末尾的 '\0'是从str2中获取的还是本身自带的
  char str2[] = "***";
  strncat(str1, str2, 2);
  printf("%s\n", str1);
  return 0;
}

7b54c515f5c34208b3833952a7591c91.png


根据结果可以看见,原来的 ' h ' 被 ' \0 ' 替换了 。

我们之前用strcat自己给自己追加行不通,但是我们可以用strncat来完成,确定要追加多少个字符。

0b77f46a3bab46e69ebcebc420b60b58.png


2.3 strncmp


e3f7b8411eae4dfba1dec1f8d462e07b.png

将 C 字符串 str1 的最多数字字符与 C 字符串 str2 的字符进行比较。

此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续执行以下对操作,直到字符不同,直到达到终止空字符,或者直到两个字符串中的数字字符匹配,以先发生者为准。


它的返回值与strcmp一样。


看代码

#include <stdio.h>
int main()
{
  int ret = strncmp("abcdef","abc",2);
  printf("%d", ret);
  return 0;
}


4ad856f05a66439499ba7f93a493596b.png


我们把它改为比较前四个试试:


30cb4e71fe694491baef4a77f8848325.png


我们这一章先介绍这几个字符串函数,下一章主要讲讲内存函数等等。


相关文章
|
7天前
|
存储 关系型数据库 分布式数据库
PostgreSQL 18 发布,快来 PolarDB 尝鲜!
PostgreSQL 18 发布,PolarDB for PostgreSQL 全面兼容。新版本支持异步I/O、UUIDv7、虚拟生成列、逻辑复制增强及OAuth认证,显著提升性能与安全。PolarDB-PG 18 支持存算分离架构,融合海量弹性存储与极致计算性能,搭配丰富插件生态,为企业提供高效、稳定、灵活的云数据库解决方案,助力企业数字化转型如虎添翼!
|
17天前
|
弹性计算 关系型数据库 微服务
基于 Docker 与 Kubernetes(K3s)的微服务:阿里云生产环境扩容实践
在微服务架构中,如何实现“稳定扩容”与“成本可控”是企业面临的核心挑战。本文结合 Python FastAPI 微服务实战,详解如何基于阿里云基础设施,利用 Docker 封装服务、K3s 实现容器编排,构建生产级微服务架构。内容涵盖容器构建、集群部署、自动扩缩容、可观测性等关键环节,适配阿里云资源特性与服务生态,助力企业打造低成本、高可靠、易扩展的微服务解决方案。
1327 7
|
5天前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
本文讲解 Prompt 基本概念与 10 个优化技巧,结合学术分析 AI 应用的需求分析、设计方案,介绍 Spring AI 中 ChatClient 及 Advisors 的使用。
305 130
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
|
4天前
|
监控 JavaScript Java
基于大模型技术的反欺诈知识问答系统
随着互联网与金融科技发展,网络欺诈频发,构建高效反欺诈平台成为迫切需求。本文基于Java、Vue.js、Spring Boot与MySQL技术,设计实现集欺诈识别、宣传教育、用户互动于一体的反欺诈系统,提升公众防范意识,助力企业合规与用户权益保护。
|
16天前
|
机器学习/深度学习 人工智能 前端开发
通义DeepResearch全面开源!同步分享可落地的高阶Agent构建方法论
通义研究团队开源发布通义 DeepResearch —— 首个在性能上可与 OpenAI DeepResearch 相媲美、并在多项权威基准测试中取得领先表现的全开源 Web Agent。
1399 87
|
4天前
|
JavaScript Java 大数据
基于JavaWeb的销售管理系统设计系统
本系统基于Java、MySQL、Spring Boot与Vue.js技术,构建高效、可扩展的销售管理平台,实现客户、订单、数据可视化等全流程自动化管理,提升企业运营效率与决策能力。
|
5天前
|
人工智能 Java API
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
本文介绍AI大模型的核心概念、分类及开发者学习路径,重点讲解如何选择与接入大模型。项目基于Spring Boot,使用阿里云灵积模型(Qwen-Plus),对比SDK、HTTP、Spring AI和LangChain4j四种接入方式,助力开发者高效构建AI应用。
301 122
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
|
6天前
|
弹性计算 安全 数据安全/隐私保护
2025年阿里云域名备案流程(新手图文详细流程)
本文图文详解阿里云账号注册、服务器租赁、域名购买及备案全流程,涵盖企业实名认证、信息模板创建、域名备案提交与管局审核等关键步骤,助您快速完成网站上线前的准备工作。
234 82
2025年阿里云域名备案流程(新手图文详细流程)