C语言:字符函数 & 字符串函数 & 内存函数

简介: C语言:字符函数 & 字符串函数 & 内存函数

字符函数

顾名思义,字符函数就是作用于字符的函数,而字符函数主要分为字符分类函数以及字符转换函数

字符分类函数

字符分类函数,用于判断一个字符是否属于某一个类


函数 参数符合条件
isntrl 任何字符
isspace 空白字符,空格'',换页符'\f',换行符'\n',回车符'\r',制表符'\t',垂直制表符'\v'
isdigit 十进制数字0 - 9
isxdigit 十六进制数字,包括0 - 9a - fA - F
islower 小写字母a - z
isupper 大写字母A - Z
isalpha 字母a - zA - Z
isalnum 字母或数字,a - zA - Z0 - 9
ispunct 标点符号,任何不属于字母或数字的可打印字符
isgraph 任何图形字符
isprint 任何可打印字符

对于以上函数,只要传入的字符符合要求,返回非0数字;否则返回0;


字符转换函数

tolower

将传入的大写字母变成小写字母

toupper

将传入的小写字母变成大写字母


字符串函数

strlen

strlen函数用于求出字符串的长度,其判定结束的标志为\0

大部分情况下,\0出现在字符串的结尾,但是如果\0出现在字符串的中间,那么我们就无法得到字符串的正确长度。


strcpy

strcpy函数用于拷贝字符串,其参数如下:

destination:拷贝后字符串存放的空间

source:字符串的来源

返回值为char*,指向拷贝后的destination,方便链式访问

  • 对于source来说,其结束的标志依然为'\0',其默认带有的'\0'也会被拷贝到指定字符串的末尾。
  • destination必须指向可以修改的空间,并且足以放置source的字符个数。

strncpy是一个与strcpy功能一致的函数,但是其可以限制拷贝字符的个数

对于strcpy,其拷贝字符的个数就是source'\0'之前字符个数。strncpy可以传入第三个参数,用于规定拷贝字符的个数。

示例:

char arr[100] = { 0 };
strncpy(arr, "hello", 3);

以上代码把"hello"的前三个字符”hel“拷贝进了arr中。

另外,如果字符串的长度不足n,那么少的位置会用\0补充


strcat

strcat函数用于对字符串进行追加,其会把source追加到destination的末尾。所以destinationsource都必须由\0结尾

示例:

char arr[100] = "hello";
strcat(arr, "world");

追加后,arr内部存储的就是helloworld了。

注意事项:

  • C语言标准没有要求此函数可以自追加,这取决于编译器的实现
  • destination必须是可以修改的

同样的,这个函数也有限制长度的版本strncat。第三个参数用于限定追加字符串的长度:当字符串长度超过n,则只追加n个字符;当字符串长度小于n,那么追加完这个字符串就不再追加


strcmp

此函数用于比较两个字符串的大小

  • str1大于str2,返回大于0的值
  • str1等于str2,返回0
  • str1小于str2,返回小于0的值

比较的是两个字符串的字典序,而非长度。

同样的,该函数存在一个限制长度的版本strncmp,比较两个字符串的前n个字符。

strstr

此函数用于进行字符串查找,即在str1中查找str2

如果找到了,返回str1中指向str2的指针

如果没找到,返回NULL


strtok

strtok函数用于对字符串进行分割,其有两个参数:

str:被分割的字符串

delimiters:分隔符组成的字符串

比如delimiters如果是“@#!”,那么这个字符串遇到#@!时就会将字符串进行分隔。

当在字符串中找到了对应的分隔符:

  1. 将这个分隔符改为\0
  2. 返回指向这个字符的指针

如果没找到字符,或者遇到末尾,此时返回NULL

另外地,strtok如果对str传入了NULL,下一次会从上一次更改的地方开始查找

示例:

char arr[100] = "hello!world?cs@dn";
const char* p = "!?@";

for (char* r = strtok(arr, p); r != NULL; r = strtok(NULL, p))
{
  printf("%s\n", r);
}


以上代码中,第一次调用strtok传入了arr,后续都传入NULL,从而完成整个字符串的分隔:

输出结果:

hello
world
cs
dn


内存函数

C语言中的内存函数用于对内存进行操控,主要包括内存的拷贝,初始化,以及内存数据的比较。

memcpy

函数用于对内存进行拷贝,此函数包含三个参数:

destination:目的地,即拷贝后的数据存入的地方

source:源,即被拷贝的内存

num:字节数

示例:

int arr1[] = { 1,2,3,4,5 };
int arr2[5] = { 0 };

memcpy(arr2, arr1, sizeof(int) * 5);

以上代码,完成了两个数组之间的内存拷贝,拷贝方向为:从arr1拷贝到arr2,共拷贝了sizeof(int) * 5 = 20个字节。

现在我们模拟实现一个memecpy

void* my_memcpy(void* destination, void* source, size_t num)
{
  void* ret = destination;
  assert(destination && source);

  while (num--)
  {
    *(char*)destination = *(char*)source;
    destination = (char*)destination + 1;
    source = (char*)source + 1;
  }

  return ret;
}

可以看到,memcpy的拷贝是以字节为单位,将传入的void*指针转为char*指针,然后一个一个字节进行拷贝。这样这个函数就可以处理任何类型的内存拷贝。

但是这个函数存在一个问题,无法拷贝内存发生重叠的函数。

看到以下过程:

int arr[6] = { 1,2,3,4 };

memcpy(arr + 2, arr, sizeof(int) * 4 ;

此代码希望把arr的前四个元素拷贝到后四位去,即:

1 2 1 2 3 4

实际输出结果:

1 2 1 2 1 2

为什么会这样?

看到以下过程:

我们要把蓝色区域的数值拷贝到红色区域,从左往右拷贝,第一次进行拷贝,由于内存重叠,1 2会把3 4覆盖,导致后续拷贝3 4时拷贝到的还是1 2

C语言标准库没有要求memcpy对重叠的内存进行处理,但是有的编译器可以处理这种情况,有的不可以。

为处理这个情况,C语言有专门的函数memmove用于处理重叠内存的情况。


memmove

memmove函数也用于进行内存拷贝,与memcpy不同的是,C标准规定其可以处理内存的重叠。

示例:

int arr[6] = { 1,2,3,4 };

memmove(arr + 2, arr, sizeof(int) * 4 ;

同样的代码,输出结果为:

1 2 1 2 3 4

这是如何做到的?

其实就是一个简单的拷贝方向的问题:

当我们把以上的重叠拷贝,从右向左拷贝:

可以看到,虽然发生了内存的重叠,但是我们先把会被覆盖的数据拷贝好,然后再覆盖重叠区域的数据,此时我们的拷贝就正常运行了。

所以memmove的实现中,我们要根据内存的重叠情况,来控制内存的拷贝方向,以保证重叠的数据先被拷贝。

代码如下:

void* my_memmove(void* destination, void* source, size_t num)
{
  void* ret = destination;
  assert(destination && source);

  if (destination < source)
  {
    while (num--)
    {
      *(char*)destination = *(char*)source;
      destination = (char*)destination + 1;
      source = (char*)source + 1;
    }
  }
  else
  {
    while (num--)
    {
      *((char*)destination + num) = *((char*)source + num);
    }
  }

  return ret;
}

destination指针小于source,我们就从低地址向高地址拷贝

destination指针大于source,我们就从高地址向低地址拷贝


memset

memset函数用于对内存进行初始化,其包含三个参数:

ptr:指向待初始化内存的指针

value:希望内存被初始化的值

num:想要初始化内存的字节数

此函数只能按照字节初始化内存,比如以下代码:

int arr[5] = { 0 };
memset(arr, 1, sizeof(int) * 5);

以上代码并不是把数组中的五个int元素初始化为1,而是把每个字节都初始化为00000001


memcmp

此函数用于比较内存中的数据,ptr1ptr2是被比较的内存。

其按照字节进行比较,从前往后,一个一个字节比较ASCII码值,当某一对字节的ASCII码值不同,此时该字节ASCII码值大的内存,就是比较大的。

相关文章
|
11天前
|
存储 编译器 程序员
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
在C语言中,内存布局是程序运行时非常重要的概念。内存布局直接影响程序的性能、稳定性和安全性。理解C程序的内存布局,有助于编写更高效和可靠的代码。本文将详细介绍C程序的内存布局,包括代码段、数据段、堆、栈等部分,并提供相关的示例和应用。
25 5
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
|
11天前
|
存储 算法 C语言
【C语言】字符常量详解
字符常量是C语言中处理字符数据的重要工具。通过单引号括起一个字符,我们可以方便地使用字符常量进行字符判断、字符运算和字符串处理等操作。理解字符常量的表示方法、使用场景和ASCII码对应关系,对于编写高效的C语言程序至关重要。
60 11
|
11天前
|
存储 C语言 开发者
【C语言】格式化输出占位符及其标志字符详解(基于ISO/IEC 9899:2024)
在C语言中,格式化输出通过 `printf` 函数等格式化输出函数来实现。格式说明符(占位符)定义了数据的输出方式,标准ISO/IEC 9899:2024(C23)对这些格式说明符进行了详细规定。本文将详细讲解格式说明符的组成部分,包括标志字符、宽度、精度、长度修饰符和类型字符,并适当增加表格说明。
30 6
|
11天前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
39 6
|
15天前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
36 6
|
13天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
37 1
|
15天前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
15天前
|
大数据 C语言
C 语言动态内存分配 —— 灵活掌控内存资源
C语言动态内存分配使程序在运行时灵活管理内存资源,通过malloc、calloc、realloc和free等函数实现内存的申请与释放,提高内存使用效率,适应不同应用场景需求。
|
19天前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
159 1
|
8天前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。