【C语言】字符串函数详细讲解

news2024/9/20 9:33:35

文章目录

  • 前言
  • 求字符串长度(strlen)
    • strlen的声明和使用
    • strlen模拟实现
  • 字符串拷贝(strcpy)
    • strcpy的声明和使用
    • strcpy模拟实现
  • 字符串追加函数(strcat)
    • strcat的声明和使用
    • strcat模拟实现
  • 字符串比较函数(strcmp)
    • strcmp的声明和使用
    • strcmp模拟实现
  • strncpy
    • strncpy的声明和使用
  • strncat
    • strncat的声明和使用
  • strncmp
    • strncmp的声明和使用
  • 字符串查找函数(strstr)
    • strstr的声明和使用
    • strstr模拟实现
  • 字符串分隔函数(strtok)
    • strtok的声明和使用
  • 最后

前言

本片来深入讲解C语言中经常使用的字符串函数,使用字符串函数时都要包含头文件<string.h>。

求字符串长度(strlen)

strlen的声明和使用

size_t  strlen  ( const char * str )

在这里插入图片描述

使用strlen注意点:

  • 字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )
  • 参数指向的字符串必须要以 ‘\0’ 结束。
  • 注意函数的返回值为size_t,是无符号的( 易错 )
    请看下面代码,输出的结果是什么?
int main()
{
	char arr1[] = { "abc" };
	char arr2[] = { "abcde"};
	if (strlen(arr1) - strlen(arr2)>0)
	{
		printf("arr1>arr2\n");//执行
	}
	else
		printf("arr1<=arr2\n");
	return 0;
}

本题看似简单其实不认真就会出错,认为会输出arr1<=arr2,但答案是arr1>arr2。
因为strlen返回值为size_t无符号整形,两个无符号整形相减得到的结果是无符号整形,arr1的长度为3减去arr2的长度5结果为-2,但-2为无符号整数,计算机会把它认为是一个很大的正数,所以输出前者。
所以在使用strlen时要注意strlen的返回值为无符号整形。

strlen模拟实现

主函数

int main()
{
	char arr[] = { "abcdef" };
	// 计算
	int ret = my_strlen(arr);
	//输出
	printf("%d ", ret);
	return 0;
}

my_strlen实现代码
迭代实现

size_t my_strlen(const char* str)
{
	assert(str);
	int count = 0;
	while (*str)
	{
		count++;
		str++;
	}
	return count;
}
  • str字符串只是计算大小,而不用修改值,所以用const修饰char *指针,只能访问内容,而不能修改。
  • assert断言,用于判断指针不为空。
    希望读者们写代码时也能这样写,增强代码的健壮性,对后续检查代码有帮助。
    递归实现
size_t my_strlen(const char* str)
{
	assert(str);
	if (*str)
		return 1 + my_strlen(str + 1);
	else
		return 0;
}

指针 - 指针实现

size_t my_strlen(const char* str)
{
	assert(str);
	const char* p = str;
	while (*p)
	{
		p++;
	}
	return p - str;
}

字符串拷贝(strcpy)

strcpy的声明和使用

char* strcpy(char * destination, const char * source);

在这里插入图片描述
使用strcpy注意点:

  • 源字符串必须以 ‘\0’ 结束。
  • 会将源字符串中的 ‘\0’ 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间内容必须可变。

strcpy模拟实现

char* my_strcpy(char* destination, const char* source)
	{
	char* ret = destination;
	while (*destination = *source)
	{
		destination++;
		source++;
	}
	return ret;
	}

字符串追加函数(strcat)

strcat的声明和使用

char * strcat ( char * destination, const char * source );

在这里插入图片描述

  • 源字符串必须以 ‘\0’ 结尾。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。

注意:
字符串自己给自己追加会有问题.
在这里插入图片描述
<font size= face=‘正楷’ color=green>source的内容会覆盖掉destination的内容,导致字符串没有结束标志,会死循环下去,所以最好不要字符串自己追加。

strcat模拟实现

//strcat模拟实现
char* my_strcat(char* des, const char* sour)
{
	char* ret = des;
	//参数不能为空
	assert(des && sour);
	//找到des的\0
	while (*des++);
	des--;
	//循环赋值
	while (*des++ =*sour++);
	return ret;
}
int main()
{
	char arr1[] = { " bit"};
	char arr[20] = {"hello"};
	char *ret=my_strcat(arr, arr1);
	printf("%s\n", ret);
	return 0;
}

字符串比较函数(strcmp)

strcmp的声明和使用

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

在这里插入图片描述
规定

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

怎么判断两个字符串的大小呢?
按顺序比较两个字符串的内容,如果相等就比较下一个字符,如果两个字符不相等就比较两个字符的ACLL码值,按标准返回值。

strcmp模拟实现

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
		while (*str1 == *str2 && *str1!='\0')
		{
			str1++;
			str2++;
		}
		if (*str1 > *str2)
		{
			return 1;
		}
		if (*str1 < *str2)
		{
			return -1;
		}
		return 0;
}
int main()
{
	char arr1[] = { "abc" };
	char arr2[] = { "abc" };
    int ret = my_strcmp(arr1, arr2);
	printf("%d\n", ret);
	return 0;
}


前面学习的字符串函数都是没有限制长度的,在使用时不注意就会有越界的风险,所以下面学习一下相对比较安全的函数,增加了限制长度的字符串函数。

strncpy

strncpy的声明和使用

char * strncpy ( char * destination, const char * source, size_t num );

在这里插入图片描述

  • 拷贝num个字符从源字符串到目标空间。
  • 当源字符串的长度大于num的大小时,num是多少拷贝多少,当源字符串的长度小于num的大小时,拷贝完源字符串后,在后面添加 ’ \0 '直到拷贝数量等于num时停止。
    在这里插入图片描述

strncat

strncat的声明和使用

char * strncat ( char * destination, const char * source, size_t num );

在这里插入图片描述

  • 在目标字符串后追加num个字符,最后增加 ’ \0 '。
  • 当源字符串长度小于num的大小时,则仅复制终止 null 字符之前的内容。
#include <stdio.h>
#include <string.h>
int main ()
{
 char str1[20];
 char str2[20];
 strcpy (str1,"To be ");
 strcpy (str2,"or not to be");
 strncat (str1, str2, 6);
 puts (str1);
 return 0;
}

strncmp

strncmp的声明和使用

int strncmp ( const char * str1, const char * str2, size_t num );

在这里插入图片描述

  • 比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。
    在这里插入图片描述
#include <stdio.h>
#include <string.h>
int main ()
{
  char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
  int n;
  puts ("Looking for R2 astromech droids...");
  for (n=0 ; n<3 ; n++)
  if (strncmp (str[n],"R2xx",2) == 0)
 {
    printf ("found %s\n",str[n]);
 }
  return 0;
}

字符串查找函数(strstr)

strstr的声明和使用

const char * strstr ( const char * str1, const char * str2 );

在这里插入图片描述

  • 返回指向 str1 中第一次出现的 str2 的指针,如果 str2 不是 str1 的一部分,则返回 null 指针。
  • 匹配过程不包括终止 null 字符,但会在此处停止。
int main()
{
	char str[] = "This is a simple string"; 
	char* pch;
	pch = strstr(str, "simple");
	strncpy(pch, "sample", 6);
	puts(str);
	return 0;
}

strstr模拟实现

//strstr模拟实现
const char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	//向后查找字符串str1
	const char* p1 = str1;
	//向后查找字符串str2
	const char* p2 = str2;
	//标记str1查找的位置
	const char* cp = str1;
	while (*cp)
	{
		p1 = cp;
		while (*p1 == *p2 && *p2)
		{
			p1++;
			p2++;
		}
		if (*p2 == '\0')
		{
			return cp;
		}
		p2 = str2;
		cp++;
	}
	return cp;
}
int main()
{
	char str[] = "abbbbcde";
	char* pch;
	pch = my_strstr(str, "bbc");
	puts(pch);
	return 0;
}

字符串分隔函数(strtok)

strtok的声明和使用

char * strtok ( char * str, const char * delimiters );
  • sep参数是个字符串,定义了用作分隔符的字符集合。
  • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
  • strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
  • strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  • strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  • 如果字符串中不存在更多的标记,则返回 NULL 指针。
int main ()
{
  char str[] ="- This, a sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
 {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
 }
  return 0;
}

最后

感谢大家的观看, 大家可以在评论区留言,你们的支持就是我最大的动力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2119418.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言深入理解指针5

1.sizeof和strlen 对比 1.1sizeof sizeof用来计算变量所占内存空间大小&#xff0c;单位是字节&#xff0c;操作数是类型的话&#xff0c;计算的是使用类型创建的变量所占空间的大小 sizeof只关注占用内存空间大小&#xff0c;不在乎内存中存放什么数据 int main() {int a …

验证码识别之点选验证码识别——绪论

基于深度学习与传统算法的点选验证码识别 绪论 随着互联网的飞速发展&#xff0c;网络安全问题日益凸显&#xff0c;验证码作为一种有效的安全防护手段&#xff0c;广泛应用于登录验证、注册验证、防止自动化攻击等多个场景。传统的验证码形式如文本验证码、图形验证码等&…

使用 Parallel 类进行多线程编码(上)

用 C# 进行多线程编程有很多方式&#xff0c;比如使用 Thread 对象开启一个新线程&#xff0c;但这已经是一种落后的写法了&#xff0c;现在推荐的写法是使用 Parallel 类&#xff0c;它可以让我们像写传统代码一样编写多线程的程序&#xff0c;Parallel 类有三个常用的方法如下…

erlang学习: Mnesia Erlang数据库

创建Mnesia数据库 mnesia:create_schema([node()]).在shell里输入该行代码即可创建一个mnesia数据库于当前文件夹下 编译器文件路径下同样也有 数据库表定义创建 之后是数据库表定义&#xff0c;打开数据库创建完成后&#xff0c;启动数据库&#xff0c;添加一些表定义&…

ccpc网络热身赛: Iris’Food

题目 做法 第一位选除0外最小的数&#xff0c;其他位按从小到大选。 #include<bits/stdc.h> #define int unsigned long long using namespace std; int t,a[20],m; const int mod1e97; int ksm(int a,int b){int ans1;while(b){if(b%2) ansans*a%mod;b/2;aa*a%mod;}r…

哪里打印便宜一点?什么地方打印便宜?

在这个快节奏的时代&#xff0c;无论是学生、上班族还是创业者&#xff0c;都有可能面临需要紧急打印文件的情况。然而&#xff0c;面对市面上琳琅满目的打印服务提供商&#xff0c;如何选择性价比高的打印服务成了许多人关心的问题。今天&#xff0c;我们就来探讨一下“哪里打…

SQL注入基础入门完整教学

SQL注入-概述 什么是sql注入漏洞&#xff1f; 攻击者利用Web应用程序对用户输入验证上的疏忽&#xff0c;在输入的数据中包含对某些数据 库系统有特殊意义的符号或命令&#xff0c;让攻击者有机会直接对后台数据库系统下达指令&#xff0c;进而 实现对后台数据库乃至整个应用…

如何进行不同数据库的集群操作?--从部署谈起,今天来看MySQL和NoSql数据库Redis的集群

篇幅较长&#xff0c;主要分为mysql和Redis两部分。找想要的部分可见目录食用。。 目录 什么是集群&#xff1f;为什么要集群&#xff1f; 1.1 数据库主要分为两大类&#xff1a;关系型数据库与 NoSQL 数据库 1.2 为什么还要用 NoSQL 数据库呢&#xff1f; ----------------…

python怎么输入中文

解决中文输入的两种应用&#xff1a; 在脚本中加语言编码声明 “-*- coding: uft-8 -*-” 应用一&#xff1a;print中出现中文 方法一&#xff1a;用unicode( , encoding utf-8 ) 或者 unicode(" ", encoding "utf-8" )。 方法二&#xff1a;用u 或者…

springboot 的共享session方案?

问&#xff1a;springboot 的共享session方案&#xff1f; 参考&#xff1a; https://juejin.cn/post/7195227930077691963分布式之session共享问题 4种解决方案及spring session的使用_分布式session共享方案-CSDN博客 什么是 Session &#xff1f; 答&#xff1a;因为Http协…

新能源动力组中预充电路及电阻选型分析

新能源动力组中预充电路及电阻选型分析 1.概述2.预充电路与预充电阻3.预充电阻参数选择4.实例分析 1.概述 最近几年&#xff0c;新能源行业在中国得到迅猛发展。由于其高效、节能、低噪声、无污染等特点&#xff0c;它已成为国内工业发展的新趋势包括汽车和飞机。虽然应用在新…

微波无源器件2 用于双极化波束形成网络的增强型双极化定向耦合器

摘要&#xff1a; 定向耦合器和混合相移器是用于实现波束形成网络的关键器件。通常一个波束形成网络用线极化和正交极化两个极化给天线馈电。双极化器件被用于降低波束形成网络的复杂性和尺寸。双极化定向耦合器由相同的作者提出。一种增强型的双极化耦合器在本文中提出。此器件…

JumpServer关闭admin mfa验证

背景 因为上一次启动了mfa验证&#xff0c;但是没有验证就关机重启&#xff0c;导致再开机输入密码后需要mfa绑定&#xff0c;但是怎么也无法绑定成功&#xff0c;导致无法登录。 故希望通过后台取消mfa的验证 from users.models import Useru User.objects.get(usernameadmin…

ThreadLocal 释放的方式有哪些

ThreadLocal基础概念&#xff1a;IT-BLOG-CN ThreadLocal是Java中用于在同一个线程中存储和隔离变量的一种机制。通常情况下&#xff0c;我们使用ThreadLocal来存储线程独有的变量&#xff0c;并在任务完成后通过remove方法清理这些变量&#xff0c;以防止内存泄漏。然而&…

前端开发的单例设计模式

一、什么是单例模式 单例模式&#xff08;Singleton Pattern&#xff09;是一种常见的设计模式&#xff0c;它确保在整个应用程序的生命周期中&#xff0c;一个类只能创建一个实例。无论你在代码的任何地方尝试创建该类的新实例&#xff0c;它都会返回已经存在的唯一实例。这在…

鸿蒙开发(API 12 Beta6版)【NFC标签读写】 网络篇

简介 近场通信(Near Field Communication&#xff0c;NFC)是一种短距高频的无线电技术&#xff0c;在13.56MHz频率运行&#xff0c;通信距离一般在10厘米距离内。电子设备可以通过NFC通信技术和NFC标签通信&#xff0c;从标签中读取数据&#xff0c;或写入数据到标签。 NFC标…

XInput手柄输入封装

功能全面地封装了XInput的输入, 1. 普通按钮按下, 按住, 弹起状态检查, 2. 摇杆4个方向的按下, 按住, 弹起检查 3. 按键状态变化检测并且记录按下触发时间, 按住保持时间, 方便用来完全自定义的输入功能 4. 多手柄输入合并 CXinputHelper.h #pragma once #include <win…

微信支付开发避坑指南

1 微信支付的坑 1.1 不能用前端传递过来的金额 订单的商品金额要从数据库获取&#xff0c;前端只传商品 id。 1.2 交易类型trade type字段不要传错 v2版API&#xff0c;不同交易类型&#xff0c;要调用的支付方式也不同。 1.3 二次签名 下单时&#xff0c;在拿到预支付交…

哈希表-数据结构

一、哈希表基本概念 哈希表&#xff08;也称为散列表&#xff09;是根据键而直接访问在内存存储位置的数据结构&#xff0c;也就是说实际上是经过哈希函数进行映射&#xff0c;映射道表中一个位置来访问记录&#xff0c;这个存放记录的数组称为散列表。 哈希函数&#xff1a;就…

计组基础知识

操作系统的特征 并发 共享 虚拟 异步 操作系统的功能 1、资源分配&#xff0c;资源回收 硬件资源 CPU、内存、硬盘、I/O设备。 2、为应⽤程序提供服务 操作系统将硬件资源的操作封装起来&#xff0c;提供相对统⼀的接⼝&#xff08;系统调⽤&#xff09;供开发者调⽤。 3、管…