字符函数和字符串函数

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

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


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


相关文章
|
5月前
|
C语言
字符函数和字符串函数
字符函数和字符串函数
67 0
|
C语言 Python
字符函数和字符串函数(下)
字符函数和字符串函数(下)
53 0
字符函数和字符串函数(下)
|
10月前
|
C语言
字符函数和字符串函数(下)
字符函数和字符串函数(下)
|
10月前
|
C语言
字符函数和字符串函数(上)
字符函数和字符串函数
|
10月前
详解字符函数和字符串函数-1
详解字符函数和字符串函数
40 0
|
10月前
|
C语言
详解字符函数和字符串函数-2
详解字符函数和字符串函数
46 0
|
编译器 C语言 Python
字符函数和字符串函数(上)
字符函数和字符串函数(上)
44 0
|
存储 安全
常用的字符函数和字符串函数
常用的字符函数和字符串函数
88 0