1.字符函数
1.1字符分类函数
C语⾔中有⼀系列的函数是专⻔做字符分类的,也就是⼀个字符是属于什么类型的字符的。
这些函数的使⽤都需要包含⼀个头⽂件是 ctype.h
https://legacy.cplusplus.com/reference/cctype/
字符分类函数的使用非常相似,我们举其中一例讲解:
int islower ( int c );
该字符函数是用来判断c是否是小写字母,如果是⼩写字⺟就返回⾮0的整数,如果不是⼩写字⺟,则返回 0。
写⼀个代码,将⼩写字⺟转⼤写
#include <stdio.h>
#include <ctype.h>
int main()
{
char a = 0;
scanf("%c", &a);
if (islower(a))
{
printf("%c\n", a - 32);
}
else
{
printf("%c\n", a);
}
return 0;
}
写⼀个代码,将字符串中的⼩写字⺟转⼤写,其他字符不变。
#include <stdio.h>
#include <ctype.h>
int main()
{
int i = 0;
char a[] = "Test String";
char c = 0;
while (a[i])
{
c = a[i];
if (islower(c))
{
printf("%c", c - 32);
i++;
}
else
{
printf("%c", c);
i++;
}
}
return 0;
}
1.2字符转换函数
C语言中提供了两个字符转换函数:
int tolower ( int c ); //将参数传进去的⼤写字⺟转⼩写
int toupper ( int c ); //将参数传进去的⼩写字⺟转⼤写
上⾯的代码,我们将⼩写转⼤写,是通过将其对应的ASCII码-32完成的效果,有了转换函数,就可以直接使⽤ tolower 函 数。
#include <stdio.h>
#include <ctype.h>
int main()
{
int i = 0;
char str[] = "Test String.\n";
char c;
while (str[i])
{
c = str[i];
if (islower(c))
c = toupper(c);
putchar(c);
i++;
}
return 0;
}
2.字符串函数
2.1表示字符串和字符串I/O
2.1.1如何定义字符串
如果字符串常量之间没有间隔,或者用空白字符分隔,C默认将其是为串连起来的字符串常量
//两行代码等价
char str[] = "we, are"" are" " the""best!";
char str[] = "we,are the best!"
如果想在内部使用双引号,则在双引号前面加一个反斜杠\
char str[] = "\"we are the best!\"Jack says"
字符串常量属于静态存储类型,这说明如果在函数中使用字符串常量,该字符串只会被存储一次,在整个程序的生命周期内存在,即使函数被调用多次。用双引号括起来的内容被视为指向该字符串的指针。类似于数组名作为指向该数组位置的指针。
int main()
{
printf("%s, %p, %c\n", "we", "are", *"the best");
return 0;
}
2.1.2字符串数组和初始化
char str[10] = {'t','h','e',' ','b','e','s','t','\0'};
注意:最后的空字符('\0'),如果没有这个空字符,这就不是一个字符串,而是一个字符数组。
在指定数组大小时,要确定数组的元素个数至少比字符串长度多1(目的是为了容纳空字符)。对于未被使用的元素都会被自动初始化为0(char形式的空字符)
2.1.3数组和指针
通常,字符串都作为可执行文件的一部分存储在数据段中,当把程序载入内存时也载入程序中的字符串,字符串存储在静态内存区,但是程序在运行时才会为该数组分配内存。此时才将字符串拷贝到数组中。
此时,字符串有两个副本。一个是在静态内存中的字符串常量,另一个是存储在数组中的字符串。
在数组形式中,数组名是地址常量,这意味着不能更改,不能进行++arr之类的操作但可以进行整体+1的操作
而对于指针形式(*ptr),在程序执行时就会为指针变量留出一个存储位置,并把字符串的地址存储在指针变量中,该变量最初指向该字符串的首字符,但值可以改变,并且可以使用递增运算符,(++ptr)则表示指向第二个字符
总结:初始化数组把静态存储区的字符串拷贝给一个数组中,而初始化指针只把字符串的地址拷贝给指针
int main()
{
char a[] = "abc";
const char* p = "abc";
printf("abc的地址:%p\n", "abc");
printf("数组名a的地址:%p\n", a);
printf("指针p的地址:%p\n", p);
printf("abc的地址:%p\n", "abc");
return 0;
}
该程序说明了:
1.数组名a的地址和指针p的地址不同,这验证了以上总结的内容
2.多次使用printf()函数打印字符串常量地址均一样,但是编译器只使用了一个存储位置,而且与指针p的地址一样,因为它们都表示字符串地址。编译器可以把多次使用的相同字面量存储在一处或多处,这取决于编译器
3.静态数据使用(字符串abc)的内存 与 a数组动态数据使用的内存不同
2.1.4数组和指针的区别
两者的主要区别:数组名是常量,指针名是变量
当我们打算修改字符串时,要用数组的形式来修改,尽量不要用指针
如若用指针要使用const限定符,const修饰指针变量应如何使用:https://blog.youkuaiyun.com/weixin_61196535/article/details/135091722?spm=1001.2014.3001.5501
#include <stdio.h>
#include <string.h>
int main() {
// 创建一个字符数组,用于存储字符串
char str[100] = "Hello, World!";
// 输出原始字符串
printf("原始字符串: %s\n", str);
// 修改字符串中的某个字符
// 在这个例子中,我们将 'o' 修改为 'X'
for (int i = 0; i < strlen(str); i++) {
if (str[i] == 'o') {
str[i] = 'X';
}
}
// 输出修改后的字符串
printf("修改后的字符串: %s\n", str);
return 0;
}
2.2字符串函数
2.2.1strlen函数的使用和模拟实现
strlenhttps://legacy.cplusplus.com/reference/cstring/strlen/?kw=strlen
size_t strlen ( const char * str );
•字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前⾯出现的字符个数(不包含 '\0' )。
• 参数指向的字符串必须要以 '\0' 结束。
• 注意函数的返回值为size_t,是⽆符号的( 易错 )
• strlen的使⽤需要包含头⽂件
模拟实现:
方式一:通过计数器的方式实现,使用循环将字符挨个传递,用count计数并返回
//计数器⽅式
int my_strlen(const char* str)
{
int count = 0;
assert(str);
while (*str)
{
count++;
str++;
}
return count;
}
方式二: 字符串首指针-尾指针,指针相减得到的是元素个数
//指针-指针的⽅式
int my_strlen(char* s)
{
assert(str);
char* p = s;
while (*p != ‘\0’)
p++;
return p - s;
}
方式三:递归,要求不能创建了临时变量
int my_strlen(const char* str)
{
assert(str);
if (*str == '\0')
return 0;
else
return 1 + my_strlen(str + 1);
}
2.2.2strcpy的使⽤和模拟实现
strcpy是字符串复制函数。
strcpyhttps://legacy.cplusplus.com/reference/cstring/strcpy/?kw=strcpy
char* strcpy(char * destination, const char * source );
空字符串也拷贝
• 源字符串必须以 '\0' 结束。
• 会将源字符串中的 '\0' 拷⻉到⽬标空间。
• ⽬标空间必须⾜够⼤,以确保能存放源字符串。
• ⽬标空间必须可修改。
使用:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[10] = { "home" };
char arr2[5] = { "ouse" };
strcpy(arr1+1, arr2);
printf("%s", arr1);
return 0;
}
模拟:
char* my_strcpy(char* dest, const char* src)
{
char* ret = dest;
assert(dest != NULL);
assert(src != NULL);
while ((*dest++ = *src++))
{
;
}
return ret;
}
更加巧妙的写法:
2.2.3strcmp的使⽤和模拟实现
strcmphttps://legacy.cplusplus.com/reference/cstring/strcmp/?kw=strcmp
标准规定:
◦ 第⼀个字符串⼤于第⼆个字符串,则返回⼤于0的数字
◦ 第⼀个字符串等于第⼆个字符串,则返回0
◦ 第⼀个字符串⼩于第⼆个字符串,则返回⼩于0的数字
◦ 那么如何判断两个字符串? ⽐较两个字符串中对应位置上字符ASCII码值的⼤⼩。
int my_strcmp(const char* str1, const char* str2)
{
int ret = 0;
assert(src != NULL);
assert(dest != NULL);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
return *str1 - *str2;
}
2.2.4strncmp函数的使⽤
char * strncpy ( char * destination, const char * source, size_t num );
//(目标空间,源字符串,复制个数)
拷贝num个字符串到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
2.2.5strcat函数的使⽤
//strcat是字符串追加函数
char * strcat ( char * destination, const char * source );(目标空间,源字符串)
源字符串必须以'\0'结束。
目标空间必须足够大能够存放源字符串。
目标必须可变。
strcat不能自己给自己追加。(会将自己的'\0'覆盖)
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = { "hello " };
char arr2[10] = { "world" };
strcat(arr1, arr2);
printf("%s", arr1);
strcat(arr2,arr2)//错误
return 0;
}
2.2.6strncat函数的使用
char * strncat ( char * destination, const char * source, size_t num );(目标空间,源字符串,追加个数)
追加num个字符串到目标空间,外加一个'\0'。
如果中 C 字符串的长度小于 num,则仅复制'\0'之前的内容。
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[10] = { "ha" };
char arr2[5] = { "hahe" };
strncat(arr1, arr2, 2);
printf("%s", arr1);
return 0;
}