提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
前言
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在 常量字符串 中或者 字符数组 中。 字符串常量 适用于那些对它不做修改的字符串函数.
一、求字符串长度
使用字符串必须引用头文件<string.h>
1.strlen
size_t strlen ( const char * str );
返回类型为size_t,通常强制类型转化为int类型
Length(长度),strlen字符长度;
代码如下(示例):
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abcdef";
int len = strlen(arr);
printf("%d\n",len);//输出6,
return 0;
}
字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包 含 '\0' )。
参数指向的字符串必须要以 '\0' 结束。
注意函数的返回值为size_t,是无符号的( 易错 ) 学会strlen函数的模拟实现
原理:
字符串存储末尾是有'\0'结束符的;
strlen函数需要接受一个地址,然后指针指向传出过来的地址,通过指针的移动找'\0',移动次数为字符长度的。
模拟实现strlen的功能:
int my_strlen(const char* str)//模拟实现strlen
{
int count = 0;//计数
while (*str!='\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[20] = "abcdef";
int i = strlen(arr);//做差时需要强制类型转换返回类型为size_t
printf("%d\n", i);//5
int len=my_strlen(arr);//模拟实现strlen
printf("%d\n", len);
return 0;
}
二、长度不受限制的字符串函数
1、strcpy 拷贝字符串
接受参数为char* strcpy(char * destination, const char * source );
copy拷贝,strcpy拷贝字符串
源字符串必须以 '\0' 结束。
会将源字符串中的 '\0' 拷贝到目标空间。
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。
int main()
{
char arr1[] = { "xxxxx" };//必须有\0
char arr2[] = { "hello,woled" };
char arr3[20] ;//创建空间足够大
strcpy(arr3, arr1);
printf("%s\n", arr3);
return 0;
}
strcpy是将arr1的字符串复制到arr3中;
运行步骤:
1.将arr3和arr1的地址传给函数,函数定义两个指针接受传过来的地址;
2.让指向arr3的指针,等于指向arr2的指针;
3.返回arr3;
模拟实现
#include<assert.h>
char* my_strcpy(char* dest,const char* src)
{
char* ret = dest;
assert(dest != NULL);
assert(src != NULL);
while (*dest=*src)//当*src指向\0时整个等式为\0为假结束循环
{
dest++;//可将这两个指针的++放到循环条件中 如 : while(*dest++=*src++)
src++;
;
}
*dest = *src;//\0
return ret;
}
int main()
{
char arr1[20] = { "xxxxx" };//创建空间足够大
char arr2[] = { "hello,woled" };
char arr3[] = { 'a','b','c','\0' };//必须有\0
strcpy(arr1, arr3);
printf("%s\n", arr1);
strcpy(arr1, arr2);//将arr2拷贝到arr1
printf("%s\n", arr1);
my_strcpy(arr1, arr3);//模拟实现
printf("%s\n", arr1);
return 0;
}
2.strcat字符串连接
char * strcat ( char * destination, const char * source );
返回类型为char*;
功能为实现两个字符串的追加,将一个字符串复制到另一个字符串后面;
源字符串必须以 '\0' 结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。
代码如下(示例):
int main()//strcat字符串衔接
{
char arr1[20] = "hello";
char arr2[30] = "world";
strcat(arr1, arr2);
printf("%s\n", arr1);
//my_strcat(arr2, arr1);
//printf("%s\n", arr2);
return 0;
}
strcat是将一个字符串接在另一个字符串后面;
衔接步骤
1.strcat接受两个数组的地址,指针指向两个数组,
2.指针找arr1的'\0',
3.然后将arr2从arr1的'\0'开始衔接;
模拟实现
char* my_strcat(char* dest, const char* src)//模拟strcat字符串衔接
{
assert(dest != NULL);
assert(src != NULL);
char* ret = dest;
while (*dest)
{
dest++;
}//找dest为\0的位置
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()//strcat字符串衔接
{
char arr1[20] = "hello ";
char arr2[30] = "world";
strcat(arr1, arr2);
printf("%s\n", arr1);
//my_strcat(arr2, arr1);
//printf("%s\n", arr2);
return 0;
}
3.strcmp字符串的比较
int strcmp ( const char * str1, const char * str2 );
返回类型为int ;功能比较两个字符串大小,
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
代码如下(示例):
int main()//strcmp字符串大小比较
{
char arr1[20] = "abcd";
char arr2[30] = "abcb";
int rte =strcmp(arr2, arr1);//如果第一个字符串大于第二个字符串返回大于0的数反之小于0;相等等于零
//int rte2 = my_strcmp(arr1, arr2);
//printf("%d %d", rte,rte2);
return 0;
}
比较步骤
1.strcmp接受两个需要比较的地址,
2.定义指针分别指向两个数组;
3.通过指针指向的元素比较;
模拟实现
int my_strcmp(char* dest, const char* src)//模拟strcmp字符串大小比较
{
while (*dest == *src)
{
dest++;
src++;
}if (*dest == *src)
return 0;
else if (*dest > *src)
return 1;
else
return -1;
}
int main()//strcmp字符串大小比较
{
char arr1[20] = "abcd";
char arr2[30] = "abcb";
int rte =strcmp(arr2, arr1);//如果第一个字符串大于第二个字符串返回大于0的数反之小于0;相等等于零
int rte2 = my_strcmp(arr1, arr2);
printf("%d %d", rte,rte2);
return 0;
}
二、长度受限制的字符串函数介绍
1.strncpy拷贝N个字符到目标字符串中
char * strncpy ( char * destination, const char * source, size_t num );
拷贝num个字符从源字符串到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
实现和strcpy一样;
代码如下(示例):
int main()
{
char str[20] = "aabbcc";
char pch[4] = { "eeff" };
/
strncpy(str, pch, 6);//复制函数,将pch复制到str后面6个字符
puts(str);
return 0;
}
2.strncat连接N个字符到目标字符串中
char * strncat ( char * destination, const char * source, size_t num );
代码如下(示例):
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[20];
char str2[20];
strcpy (str1,"To be ");//给str1赋值为To be
strcpy (str2,"or not to be");//给str2赋值为or not to be
strncat (str1, str2, 6);
puts (str1);
return 0;
}
将arr1的6个字符复制到arr2的前6个字符
3.strncmp比较N个字符
int strncmp ( const char * str1, const char * str2, size_t num );
比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。
代码如下(示例):
int main()
{
char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
int n;
puts("Looking for R2 astromech droids...");
for (n = 0; n < 3; n++)
if (strncmp(str[n], "R2xx", 2) == 0)
{
printf("found %s\n", str[n]);
}
return 0;
}
该处使用的url网络请求的数据。
二、字符串查找
1.strstr
代码如下(示例):
char* my_strstr(char* str1, char* str2)//模拟找相同字符串
{
if (str2 == '\0')
return str1;
char* cp = str1;
char* s1 = cp;
char* s2 = str2;
while (cp)
{
s1 = cp;
s2 = str2;
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
return cp;
cp++;
}
return NULL;
}
int main()
{
char ch1[] = "abbbcef";
char ch2[] = "bbc";
char* ret = my_strstr(ch1, ch2);
printf("%s", ret);
return 0;
}
逻辑和实现方法
在ch1中找ch2的字符串,定义三个指针,两个指向ch1,一个指向ch2;即分别为*cp,*s1,*s2
指向ch1的两个指针*cp和s1,cp指向ch1;s1指向cp指针;
先让s1和s2比较,若相同,两个指针同时向后移动;若不相同,cp向后;
s1始终指向cp;直到找到相同字符串或者找不到;
当s1不和s2相等,cp+1;当s2和s1相等时,cp不动让s1+1,s2+1,再判断是否相等,若不相等,再让cp+1;
2.strtok
去除切割符
int main()
{
char ch[] = "mafeifei@qq.com";//
char copy[50] = { 0 };//拷贝数组得足够大
strcpy(copy, ch);
char sep[] = "@.";
char* ret=NULL;
for (ret = strtok(copy, sep); ret != NULL; ret = strtok(NULL, sep))
{
printf("%s ", ret);
}
return 0;
}
sep参数是个字符串,定义了用作分隔符的字符集合 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标 记。
strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容 并且可修改。)
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串 中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标 记。 如果字符串中不存在更多的标记,则返回 NULL 指针。
二、错误信息报告
1.strerror
char * strerror ( int errnum );
返回错误码,所对应的错误信息
代码如下(示例):
int main()
{
for (int i = 0; i < 43; i++)
{
printf("%d %s\n", i, strerror(i));//错误码的翻译
}
return 0;
}
二、字符操作
运用需要包含<ctype.h>头文件
1.函数名及解释
iscntrl ————任何控制字符
isspace———— 空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v' isdigit ————十进制数字 0~9
isxdigit ————十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F
islower ————小写字母a~z;返回的是整形,是小写返回0;否则返回非零的数
int tolower ( int c )————将大写字母转换为小写字母
isupper ————大写字母A~Z;返回的是整形,是大写返回0;否则返回非零的数
int toupper (int c);将小写字母转换为大写字母
isalpha ————字母a~z或A~Z
isalnum ————字母或者数字,a~z,A~Z,0~9
ispunct ————标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph———— 任何图形字符
isprint————— 任何可打印字符,包括图形字符和空白字符
#include<ctype.h>
#include<stdio.h>
int main()
{
char ch[] ="FaFeiFei is S KDj";
//gets(ch);
printf("%s\n", ch);
char* c = ch;
while(*c)
{
printf("%c", tolower(*c));//大写转换为小写
c++;
}
return 0;
}
二、内存操作函数
1.memcpy
void * memcpy ( void * destination, const void * source, size_t num );
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到 '\0' 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。
destination是目的地地址,source是要拷贝的地址,num是要拷贝的长度,以字节为单位
memcpy是内存的拷贝,可以拷贝任何类型;
代码如下(示例):
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
int arr3[10] = { 10,9,8,7,6,5,4,3,2,1 };
my_memcpy(arr2 , arr1, 20);//将arr1的20个字节拷贝到arr2中arr2==1 2 3 4 5 0 0 0 0 0
memcpy(arr3, arr2, 9);//arr2的10个字节拷贝arr3 ==1 2 3 7 6 5 4 3 2 1
for (int i = 0; i < 10; i++)//拷贝9个字节,一个数是4个字节,拷贝了第三个元素一个字节,若是3则是大端存储
{
printf("%d ", arr3[i]);
}
return 0;
}
memcpy可以判断大端存储还是小段
memcpy接受任何类型的地址,在函数内部将其转换为char* 类型,因为char* 类型一次指向一个字节
在函数内部循环num次,一次拷贝一个字节
模拟实现
void* my_memcpy(void* dest, void* src, size_t num)
{
void* ret = dest;
assert(src && dest);
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
2.memmove
void * memmove ( void* destination, const void * source, size_t num );
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
代码如下(示例):
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr1 + 2, arr1, 20);//将arr1的首元素向后的(20/4)个元素拷贝到arr1的第二个元素后面//1 2 1 2 3 4 5 8 9 10
for (int i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
函数内部先判断从前向后拷贝还是从后向前拷贝;
我们想要的得到我们想要的效果第一步就要判断是从前向后还是从后向前拷贝
模拟实现
拷贝逻辑和memcpy相同,一个字节,一个字节拷贝
void* my_memmove(void* dest, void* src, size_t num)
{
if (dest < src)
{
//前向后
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//后向前
while (num--)//19 +1为第二个元素,+19为第二十个元素
{
*((char*)dest + num) = *((char*)src+num);
}
}
}
3.memcmp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
ptr1>ptr2返回大于0
ptr1=ptr2返回0
ptr1<ptr2返回小于0
代码如下(示例):
int main()
{
int arr1[] = { 1,2,1,3,4,5,6 };
int arr2[] = { 1,2,257 };
int crt1=memcmp(arr1, arr2, 9);//比较以字节为单位
//arr1
//01 00 00 00
//02 00 00 00
//01 00 00 00
//03 00 00 00
//以此类推
//arr2
//01 00 00 00
//02 00 00 00
//01 01 00 00//257的16进制为101
printf("%d\n", crt1);//等于0
int crt2 = memcmp(arr1, arr2, 10);//小于0
printf("%d\n", crt2);
return 0;
}
4.memset
void * memset ( void * ptr, int value, size_t num );
ptr Pointer to the block of memory to fill.
value Value to be set. The value is passed as an int, but the function fills the block of memory using the unsigned char conversion of this value.
num Number of bytes to be set to the value.
size_t is an unsigned integral type.
代码如下(示例):
int main()
{
int arr1[] = { 0,1,2,3 };
memset(arr1, 0, 16);//一次将arr1中的一个字节换成0;修改16次就是16个字节,4个int类型的数字
for (int i = 0; i < 4; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
此库函数可做数组的初始化。
总结
1 strlen计算字符串长的,传递一个字符串参数即可;
2strcpy 拷贝字符串,需要传两个字符串参数
3.strcat 连接字符串
4.strcmp字符串比较
5.strncpy 限制长度的字符串拷贝
6.strncmp限制长度的字符串比较
7.strncat连接n个字符发到目标字符串
8.strstr查找字符串
9.strtok取出分割符
10.strerror错误信息报告
11.memcmp任意类型的比较
12memmove任意类型的移动
13.memcpy任意类型的拷贝
14memset任意类型的限制长度字符拷贝。