C语言进阶第五课-----------字符函数和字符串函数 1

简介: C语言进阶第五课-----------字符函数和字符串函数

289a638c3a6846f2b514c038571cf891.png本章前言

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

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

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

函数介绍

在学习函数我们会见到很多陌生的函数,怎么去认识这些函数我推荐一个网站C语言函数,废话少说,开始正题

strlen

在前面中我们已经使用过这个函数,知道这个函数的作用是计算字符串的长度,计算的是‘\0’前面的长度,不包括’\0’

参数是字符串起始的地址,也就是要从哪里开始计算字符长度的地址,返回的类型是无符号整形

#include<stdio.h>
#include<string.h>
int main()
{
  char arr[] = "abcd";
  char arr1[] = { 'a','b','c','d' };//这里没有'\0';
  printf("%d\n", strlen(arr));
  printf("%d\n", strlen(arr1));
  printf("%d\n", strlen("abcd"));
  return 0;
}

其实我们还可以计算字符串常量的长度 strlen(“abcd”);传入的是a的地址

如果我们来分析一下对应的返回类型就会有另一个知识点

#include<stdio.h>
#include<string.h>
int main()
{
  if (strlen("abc") - strlen("abcdef") > 0)
  {
    printf("大于");
  }
  else
  {
    printf("小于");
  }
  return 0;
}


289a638c3a6846f2b514c038571cf891.png

如果看过前面我写过的博客就会明白,无符号数的在内存的存储 ,所有都是有效位,连符号符号位也计算进去了 ,范围是0~4,294,967,295 ,上面虽然我们通过数学方法计算得到-3,但是却是无符号数,在内存的存储是

1111 1111 1111 1111 1111 1111 1111 1101

最终计算出来的是一个很大的数.

或者我们可以把-3强转成int类型,就会是真正的-3了

如果我们要模拟实现有三种方法

方法1:递归

#include<stdio.h>
size_t my_strlen(char* arr)
{
  if (!*arr)
  {
    return 0;
  }
  return 1 + my_strlen(arr + 1);
}
int main()
{
  char arr[] = "abcdwe";
  size_t a = my_strlen(arr);
  return 0;
}

方法2:计数

#include<stdio.h>
int main()
{
  char arr[] = "aaaaaaaaa";
  int a = 0;
  char* p = arr;
  while (*p++)
  {
    a++;
  }
  return 0;
}

方法三:首元素的地址减去’\0’的地址

#include<stdio.h>
int main()
{
  char arr[] = "aaaaaaaaa";
  char* p = arr;
  while (*p++)
  {
    ;
  }
  printf("%d", p - arr - 1);
  return 0;
}

strcpy

字符串拷贝

返回类型是char* ,返回strDestination,我们可以认为这是一个初始地址, 参数有两个,一个是目的地址,一个源头地址,strSource是被拷贝的起始地址,strDestination是粘贴到的起始地址

trcpy函数将strSource(包括终止的null字符)复制到strDestination指定的位置。复制或附加字符串时不执行溢出检查。如果源字符串和目标字符串重叠,则strcpy的行为是未定义的。

会把’\0’也会拷贝过去的,

#include<stdio.h>
#include<string.h>
int main()
{
  char arr[10] = "xxxxxxxxx";
  strcpy(arr, "aaaa");
  return 0;
}

5bfb6616311847879d4483a0b11eeb78.png注意事项:

  1. 源字符串必须以 ‘\0’ 结束。
    拷贝结束是要遇到源头的结束标志,如果源头没有结束标志,就会继续拷贝直到遇到结束标志
#include<string.h>
int main()
{
  char arr[] = { 'a','b','c','d' };
  char arr1[] = "xxxxxxxx";
  strcpy(arr1, arr);
  return 0;
}

运行这段代码就会发现程序会崩溃,原因是没有遇见’\0’会一直拷贝,直到拷贝的个数超过了arr1数组的长度,越界访问,程序崩溃,

2… 会将源字符串中的 ‘\0’ 拷贝到目标空间。

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

#include<stdio.h>
#include<string.h>
int main()
{
  char arr[2] = "a";
  char arr1[5] = "asbd";
  strcpy(arr, arr1);
  return 0;
}

这里的情况和上面的情况是一样的,会越界访问,程序崩溃,这里是主要是拷贝的长度太长

  1. 目标空间必须可变。
  2. 学会模拟实现。
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcpy(char* arr, const char* arr1)
{
  assert(arr && arr1);
  char* p = arr;
  char* p1 = arr1;
  while (*p++ = *p1++)
  {
    ;
  }
  return arr;
}
int main()
{
  char arr[] = "abcdhghgfg";
  char arr1[] = "xxx";
  my_strcpy(arr, arr1);
  return 0;
}

strcat

字符串追加

这里的参数和strcpy的参数是一样的,有目标地址和源头地址

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

简单的理解就是源字符串的第一个字符会覆盖目标字符串的’\0’,然后往后添加字符,这里也会把源字符串的’\0’追加过来

#include<stdio.h>
#include<string.h>
int main()
{
  char arr[] = "asfd";
  char arr1[20] = "abcde";
  strcat(arr1, arr);
  return 0;
}

db71ca2f76b7415c8b259d76aaa10608.png

可以看到arr1的e后面原来是有结束标志的,因为字符串追加,会覆盖,

所以会有一些注意事项:

1.目标空间要足够大.可修改

#include<stdio.h>
#include<string.h>
#include<assert.h>
int main()
{
  char arr[] = "asfd";
  char arr1[20] = "abcde";
  strcat(arr, arr1);
  return 0;
}

b13e0daa073c46da9fbba8a4a8f61c15.png

当我们运行出来就会发现当追加的字符串长度大于目标空间,就会追加就会发生越界访问,程序会崩溃

2. 目标字符串必须要有’\0’,源字符串也必须有’\0’

因为strcat追加是从目标字符串的’\0’开始追加的,如果没有就会无法追加,

如果源字符串没有’\0’就会一直追加

#include<stdio.h>
#include<string.h>
#include<assert.h>
int main()
{
  char arr[] = { 'a','b' };
  char arr1[10] = "qqq";
  strcat(arr1, arr);
  return 0;
}

b250080f2ae24c8088e8f0dc260cfa16.png这里还是会发生越界访问,程序会崩溃

模拟实现

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcat(char* arr1, const char* arr)
{
  assert(arr1 && arr);
  char *p = arr;
  char* p1 = arr1;
  int sz = strlen(arr1);
  //找到目标的结束标志
  p1 = p1 + sz;
  //数据追加
  while (*p1 = *p)
  {
    p1++;
    p++; 
  }
  return arr1;
}
int main()
{
  char arr[] = "abc";
  char arr1[10] = "xx\0x111";
  my_strcat(arr1, arr);
  return 0;
}

需要注意的是如果目标字符串的’\0’后面还有字符,会直接覆盖上去的,不会扩大字符长度,

到这里可能有些小可爱会像让字符串自己给自己追加,结果发现我们模拟出来的函数程序崩溃了

下面为例:

这里是长度位20的数组,数组里面有四个元素,我们追加是通过访问内存来获取对应的值,然后覆盖上去,当我们把‘\0’覆盖了,当源字符地址找到对应的内存,但是却不是\0’而是字符a, 下一个字符是b,如此往下,没有结束标记,一直追加,最终会发生越界访问,程序崩了

但是使用库函数strcat却可以,但是我们是不建议的,

相关文章
|
12天前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
51 23
|
12天前
|
算法 C语言
【C语言程序设计——函数】利用函数求解最大公约数和最小公倍数(头歌实践教学平台习题)【合集】
本文档介绍了如何编写两个子函数,分别求任意两个整数的最大公约数和最小公倍数。内容涵盖循环控制与跳转语句的使用、最大公约数的求法(包括辗转相除法和更相减损术),以及基于最大公约数求最小公倍数的方法。通过示例代码和测试说明,帮助读者理解和实现相关算法。最终提供了完整的通关代码及测试结果,确保编程任务的成功完成。
43 15
|
12天前
|
C语言
【C语言程序设计——函数】亲密数判定(头歌实践教学平台习题)【合集】
本文介绍了通过编程实现打印3000以内的全部亲密数的任务。主要内容包括: 1. **任务描述**:实现函数打印3000以内的全部亲密数。 2. **相关知识**: - 循环控制和跳转语句(for、while循环,break、continue语句)的使用。 - 亲密数的概念及历史背景。 - 判断亲密数的方法:计算数A的因子和存于B,再计算B的因子和存于sum,最后比较sum与A是否相等。 3. **编程要求**:根据提示在指定区域内补充代码。 4. **测试说明**:平台对代码进行测试,预期输出如220和284是一组亲密数。 5. **通关代码**:提供了完整的C语言代码实现
52 24
|
8天前
|
存储 C语言
【C语言程序设计——函数】递归求斐波那契数列的前n项(头歌实践教学平台习题)【合集】
本关任务是编写递归函数求斐波那契数列的前n项。主要内容包括: 1. **递归的概念**:递归是一种函数直接或间接调用自身的编程技巧,通过“俄罗斯套娃”的方式解决问题。 2. **边界条件的确定**:边界条件是递归停止的条件,确保递归不会无限进行。例如,计算阶乘时,当n为0或1时返回1。 3. **循环控制与跳转语句**:介绍`for`、`while`循环及`break`、`continue`语句的使用方法。 编程要求是在右侧编辑器Begin--End之间补充代码,测试输入分别为3和5,预期输出为斐波那契数列的前几项。通关代码已给出,需确保正确实现递归逻辑并处理好边界条件,以避免栈溢出或结果
46 16
|
7天前
|
存储 编译器 C语言
【C语言程序设计——函数】分数数列求和2(头歌实践教学平台习题)【合集】
函数首部:按照 C 语言语法,函数的定义首部表明这是一个自定义函数,函数名为fun,它接收一个整型参数n,用于指定要求阶乘的那个数,并且函数的返回值类型为float(在实际中如果阶乘结果数值较大,用float可能会有精度损失,也可以考虑使用double等更合适的数据类型,这里以float为例)。例如:// 函数体代码将放在这里函数体内部变量定义:在函数体中,首先需要定义一些变量来辅助完成阶乘的计算。比如需要定义一个变量(通常为float或double类型,这里假设用float。
19 3
|
7天前
|
存储 算法 安全
【C语言程序设计——函数】分数数列求和1(头歌实践教学平台习题)【合集】
if 语句是最基础的形式,当条件为真时执行其内部的语句块;switch 语句则适用于针对一个表达式的多个固定值进行判断,根据表达式的值与各个 case 后的常量值匹配情况,执行相应 case 分支下的语句,直到遇到 break 语句跳出 switch 结构,若没有匹配值则执行 default 分支(可选)。例如,在判断一个数是否大于 10 的场景中,条件表达式为 “num> 10”,这里的 “num” 是程序中的变量,通过比较其值与 10 的大小关系来确定条件的真假。常量的值必须是唯一的,且在同一个。
11 2
|
11天前
|
存储 编译器 C语言
【C语言程序设计——函数】回文数判定(头歌实践教学平台习题)【合集】
算术运算于 C 语言仿若精密 “齿轮组”,驱动着数值处理流程。编写函数求区间[100,500]中所有的回文数,要求每行打印10个数。根据提示在右侧编辑器Begin--End之间的区域内补充必要的代码。如果操作数是浮点数,在 C 语言中是不允许直接进行。的结果是 -1,因为 -7 除以 3 商为 -2,余数为 -1;注意:每一个数据输出格式为 printf("%4d", i);的结果是 1,因为 7 除以 -3 商为 -2,余数为 1。取余运算要求两个操作数必须是整数类型,包括。开始你的任务吧,祝你成功!
41 1
|
1月前
|
存储 C语言 开发者
【C语言】字符串操作函数详解
这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
79 10
|
1月前
|
存储 程序员 C语言
【C语言】文件操作函数详解
C语言提供了一组标准库函数来处理文件操作,这些函数定义在 `<stdio.h>` 头文件中。文件操作包括文件的打开、读写、关闭以及文件属性的查询等。以下是常用文件操作函数的详细讲解,包括函数原型、参数说明、返回值说明、示例代码和表格汇总。
62 9
|
1月前
|
C语言 开发者
【C语言】数学函数详解
在C语言中,数学函数是由标准库 `math.h` 提供的。使用这些函数时,需要包含 `#include <math.h>` 头文件。以下是一些常用的数学函数的详细讲解,包括函数原型、参数说明、返回值说明以及示例代码和表格汇总。
57 6

热门文章

最新文章