当前位置: 首页 > news >正文

C语言:字符函数

在学习完成了C语言的的指针这一大难点后,我们将继续学习C语言里面的库函数,其中字符函数也是比较重要的一类。

零 . 字符函数:

下面列出了头文件 ctype.h 中定义的函数。
这些函数用于测试字符是否属于某种类型,这些函数接受 int 作为参数,它的值必须是 EOF 或表示为一个无符号字符。
如果参数 c 满足描述的条件,则这些函数返回非零(true)。如果参数 c 不满足描述的条件,则这些函数返回
在这里插入图片描述在这里插入图片描述

这些函数所需要的头文件是ctype.h,在这里我们只需要练习一个函数就ok了,其他的函数是非常类似的。借助下面的练习完成。

1.1. 练习1:将字符串中的小写字母改成大写字母,其他不变

方法一:利用ASCII码来改变

代码如下:

#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<ctype.h>
//练习1:将字符串中的小写字母改成大写字母,其他不变
int main()
{char str[] = "hElLo WOrld";char c;int i = 0;while (str[i]){char c = str[i];if (islower(c))c -= 32;putchar(c);i++;}return 0;
}

我们来看这段代码:1. 其中islower就是判断字母是小写,如果是小写,那么减去32(小写字母(ASCII 97–122)减去32 → 大写字母(ASCII 65–90),如果是大写就不进去if内部。
2. putchar输出转换后的字符(或原大写字符)到标准输出。
3. 循环条件​:str[i] 检查当前字符是否为非零(即非 '\0'),遇到结束符时终止
4. char c 声明字符变量,用于存储单个字符,将 str[i] 的值(字符)复制到变量 c 中,二者内存独立,修改 c 不影响原字符串

方法二:利用字符转换函数

代码如下:

//练习1:将字符串中的小写字母改成大写字母,其他不变
int main()
{char str[] = "hElLo WOrld";char c;int i = 0;while (str[i]){char c = str[i];c = toupper(c);putchar(c);i++;}return 0;
}

此时就不需要判断了,如果加了判断也是ok的,这样就能把字符进行大写化
toupper就是:to upper,往上-大写。
tolower就是:to lower,往下-小写。

一. 重要的字符函数:

1. strlen函数

1. 1.strlen 函数的使用:

在这里插入图片描述

strlen是库函数,本质是通过计算字符串里面的\0前面的字符的个数,他是可以用来计算字符串,但是不能用来计算字符数组的(一般字符数组里面不含\0)
同时返回值是一个无符号数,需要打印的话使用:%zd;传入字符串的首地址就ok

1.2 . strlen函数的模拟:

代码如下:

size_t my_strlen(char* c)
{int count = 0;while (*c){count++;c++;}return count;
}int main()
{char* c = "helso";int ret = my_strlen(c);printf("%zd", ret);
}

还可以做一下稍微的改进:

size_t my_strlen(char* c)
{int count = 0;while (*c++){count++;}return count;
}int main()
{char* c = "helsole";size_t ret = my_strlen(c);printf("%zd", ret);
}

先来看这个第二个代码的while循环:

  • *c++ 包含两步操作:
    • *c**​:解引用指针 c,获取当前字符的值。
    • c++​:指针后移(指向下一个字符),​副作用发生在解引用之后
      在这里插入图片描述

可以详细看这张图标来完成。我们还可以继续尝试递归的方式还有

#include<assert.h>
size_t my_strlen(const char* str)
{assert(str);if (*str == '\0')return 0;elsereturn 1 + my_strlen(str + 1);
}int main()
{char a[] = "heijos";size_t ret = my_strlen(a);printf("%zd", ret);
}

2.strcpy函数

2.1 strcpy的使用:

C 库函数 **char *strcpy(char dest, const char src)src 所指向的字符串复制到 dest
该函数返回一个指向最终的目标字符串 dest 的指针。
在这里插入图片描述

cpy顾名思义就是靠拷贝函数:将原字符串拷进目标字符串(src–>dest),需要注意的是:
需要注意的是如果目标数组 dest 不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况,同时原来的字符串也是以‘\0’结尾。(\0也会被复制)

#include<string.h>
int main()
{char* c = "copy to d";char d[10] = { 0 };strcpy(d, c);printf("%s", d);
}

网址给出的案例在这里插入图片描述

最后结果:在这里插入图片描述

strcpy代码模拟:

我们尝试模拟,代码如下:

char* my_strcpy(char* dest, const char* str)
{int tmp = dest;while (*str){*dest = *str;dest++;str++;}return dest;
}#include<string.h>
int main()
{char* c = "copy to d";char d[10] = { 0 };my_strcpy(d, c);printf("%s", d);
}

这段代码就完成了复制;我们还可以做一下改进:

char* my_strcpy(char* dest, const char* str)
{int tmp = dest;while (*dest++ = *str++);return dest;
}#include<string.h>
int main()
{char* c = "copy to d";char d[10] = { 0 };my_strcpy(d, c);printf("%s", d);
}

以下分步拆解首次循环逻辑(假设 str 初始指向字符串 "copy to d" 的首字符 'c'):

步骤操作指针状态​**dest 赋值结果**​
1. while (*str++) 检查先取 *str 的值('c',非零 → 条件为真) → ​**再执行 str++**​str 指向 'o'未执行赋值
2. 进入循环体执行 *dest = *strstr 仍指向 'o'dest[0] = 'o'
3. dest++目标指针后移dest 指向下一个位置-

关键问题​:

  • 首字符 'c' 被完全跳过​:条件判断时检查了 *str'c'),但 str++ 在进入循环体前已执行,导致循环内 *str 实际指向的是第二个字符 'o'
  • ​**dest[0] 未被覆盖​:因初始化为 0char d[10] = {0}),且未被赋值 → 首字节仍是 '\0',导致 printf 输出空字符串。
    你的问题直指C语言中
    后置自增运算符(*str++)的核心陷阱**​:它会在判断条件后立刻移动指针,导致循环内操作错位。以下是详细分析:
🔍 ​问题核心:while (*str++) 的执行顺序

以下分步拆解第二段代码的首次循环逻辑(假设 str 初始指向字符串 "copy to d" 的首字符 'c'

步骤操作指针状态​**dest 赋值结果**​
1. while (*str++) 检查先取 *str 的值('c',非零 → 条件为真) → ​**再执行 str++**​str 指向 'o'未执行赋值
2. 进入循环体执行 *dest = *strstr 仍指向 'o'dest[0] = 'o'
3. dest++目标指针后移dest 指向下一个位置-

关键问题​:

  • 首字符 'c' 被完全跳过​:条件判断时检查了 *str'c'),但 str++ 在进入循环体前已执行,导致循环内 *str 实际指向的是第二个字符 'o'
  • ​**dest[0] 未被覆盖**​:因初始化为 0char d[10] = {0}),且未被赋值 → 首字节仍是 '\0',导致 printf 输出空字符串。
⚠️ ​对比:三种自增写法的差异

以下对比你提供的三版代码中 while 条件的行为:

代码版本​**while 条件**​行为是否复制首字符
第一段while (*str)检查当前字符非 '\0',​不自增指针​ → 循环内复制当前字符✅ 是
第二段while (*str++)检查后立刻自增​ → 循环内复制的是下一个字符❌ 否(跳过首字符)
第三段while (*dest++ = *str++)先复制当前字符(包括 '\0'),​再自增​ → 完整复制✅ 是

💡 ​核心区别​:​后置自增(i++)在表达式中“先返回值,再自增”​,导致条件判断和循环内操作使用的指针位置不同步

3.strcat函数

3.1 strcat函数的使用:

C 库函数 **char *strcat(char dest, const char src)src 所指向的字符串追加到 dest 所指向的字符串的结尾
在这里插入图片描述

该函数返回一个指向最终的目标字符串 dest 的指针。
两个字符串要求以\0结尾。
正确代码如下

int main()
{char c[22] = "i like";char* b = " you";strcat(c, b);printf("%s", c);
}

避免出现目标空间不够,会出先错误。

3.2 strcat的模拟实现

通过观察我们做出以下代码

char* my_strcat(char* dest, char* str)
{char *tmp = dest;while (*dest++);dest--;while ((*dest++ = *str++));return tmp;
}int main()
{char c[22] = "i like";char* b = " you";my_strcat(c, b);printf("%s", c);
}
为什么有dest–

在 C 语言的字符串操作中,while (*dest++) 这种循环是定位目标字符串末尾的常见写法,但它的执行逻辑会导致 dest 指针最终指向 '\0'之后的位置,而非 '\0' 本身。以下是详细分析:

🔍 ​**while (*dest++) 的执行机制**​

假设目标字符串 dest"i like"(存储在数组 c[22] 中),其内存布局如下('\0' 在索引 6 处):

索引01234567
字符ilike\0?

循环的执行步骤如下:

  1. ​**检查条件 *dest**​:
    • *dest'\0',条件为真,进入循环体(但此循环无显式循环体,仅执行指针自增)。
  2. ​**执行自增 dest++**​:
    • 后置自增​:先返回 dest 的当前值,再将 dest 指向下一位置。
  3. ​**重复直到遇到 '\0'**​:
    • dest 指向 c[6]'\0')时:
      • 条件 *dest0(假),​但自增仍会执行​ → dest 移动到 c[7]
        因此dest–是必须要有的。

4.strcmp函数

4.1strcmp的使用

顾名思义就是比较两个字符串的大小:
在这里插入图片描述

我们先说以下cmp的比叫方式:
字符串通过标准库函数 strcmp() 实现比较,核心逻辑为:

  • 逐字符ASCII值对比​:从首字符开始,逐个比较字符的ASCII值
  • 终止条件​:
    • 遇到不相同的字符 → 返回两字符ASCII差值(正数/负数)。
    • 遇到 \0 结束符 → 若长度不同,短字符串较小;否则相等(返回0)
      ![[Pasted image 20250613170755.png]]
      使用说明,代码如下:
int main()
{char c[22] = "i like";char* b = " you";int ret = strcpmy(c, b);if (ret = 0)printf("一样大");if (ret < 0)printf("c < b");else {printf("c > b");}
}

4.2.strcmp的模拟实现:

第一次尝试而写的错误代码,没有考虑到\0,就是str的结束

int my_strcmp(const char *str1,const char * str2 )
{while (*str1 - *str2 == 0){str1++;str2++;}return *str1 - *str2;
}int main()
{char c[22] = "i like";char* b = " you";int ret = my_strcmp(c, b);if (ret == 0)printf("一样大");if (ret < 0)printf("c < b");else {printf("c > b");}
}

改进过后的代码就有:

int my_strcmp(const char *str1,const char * str2 )
{while (*str1 != 0 && *str1 - *str2 == 0){//只有未到达/0时才继续str1++;str2++;}return *str1 - *str2;//当到达0时一定比没到到达的小,这样比较出来了
}int main()
{char c[22] = "i like";char* b = " you";int ret = my_strcmp(b,c);if (ret == 0)printf("一样大");if (ret < 0)printf("c < b");else {printf("c > b");}
}

在这里插入图片描述

相关文章:

  • 基于ssm的教学质量评估系统
  • SQL Server判断中文的高效方法
  • 使用docker compose部署netmaker打通内网
  • 基于Springboot的动态刷新定时任务
  • 工业数据互联新基建:三格电子 PLC 数据采集网关破解跨协议通信难题
  • 高精度算法详解:从原理到加减乘除的完整实现
  • Jmeter本身耗资源导致压测不上去解决方案
  • .NET Core 数据库连接字符串加密与解密
  • JDBC基础关键_002_JDBC 增删改
  • 平压印刷机设计原理与关键技术研究
  • 图像匹配 像素跟踪roma
  • 【Dify精讲】第9章:插件系统与扩展机制【知识卡片】
  • 【深入剖析】攻克 Java 并发的基石:Java 内存模型 (JMM) 原理与实践指南
  • 阳台光伏CT电表防逆流,ADL200N-CT/D16-WF相序诊断、快速响应,易安装
  • 趣解TensorFlow之入门篇
  • 在 WinForms 中制作无边框窗体通过鼠标拖动移动和调整大小,难点是我窗体上被标题栏和状态栏dock之后很难选中
  • 【Qt】工具介绍和信号与槽机制
  • 深度学习驱动的验证码识别实战:从原理到高并发工业部署
  • docker compose部署kafka
  • 如何为加壳保护后的程序提供调试支持
  • 快速提升网站权重/深圳seo优化排名
  • 省级住房城乡建设主管部门网站/比较好的友链平台
  • 做公司网站有什么需要注意的/广州现在有什么病毒感染
  • 国内大的做网站的公司/网络seo培训
  • 四川省工程建设信息官方网站/引流推广多少钱一个
  • 越秀区营销型网站建设/谷歌seo技巧