江西专业的网站建设制作wordpress添加< iframe>
在学习完成了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 = *str | str 仍指向 'o' | dest[0] = 'o' | 
3. dest++ | 目标指针后移 | dest 指向下一个位置 | - | 
关键问题:
- 首字符 
'c'被完全跳过:条件判断时检查了*str('c'),但str++在进入循环体前已执行,导致循环内*str实际指向的是第二个字符'o'。 - **
dest[0]未被覆盖:因初始化为0(char 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 = *str | str 仍指向 'o' | dest[0] = 'o' | 
3. dest++ | 目标指针后移 | dest 指向下一个位置 | - | 
关键问题:
- 首字符 
'c'被完全跳过:条件判断时检查了*str('c'),但str++在进入循环体前已执行,导致循环内*str实际指向的是第二个字符'o'。 - **
dest[0]未被覆盖**:因初始化为0(char 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 处):
| 索引 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | … | 
|---|---|---|---|---|---|---|---|---|---|
| 字符 | i | l | i | k | e | \0 | ? | … | 
循环的执行步骤如下:
- **检查条件 
*dest**:- 若 
*dest非'\0',条件为真,进入循环体(但此循环无显式循环体,仅执行指针自增)。 
 - 若 
 - **执行自增 
dest++**:- 后置自增:先返回 
dest的当前值,再将dest指向下一位置。 
 - 后置自增:先返回 
 - **重复直到遇到 
'\0'**:- 当 
dest指向c[6]('\0')时:- 条件 
*dest为0(假),但自增仍会执行 →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");}
}
 

