文章目录
长度不受限的字符串函数(strcpy、strcat、strcmp)
strcpy——字符串拷贝
1.功能介绍
strcpy即字符串拷贝函数,即通过该函数将一个字符串中的内容拷贝到另一个字符串中去,该函数的参数为两个指针,其中一个为目标的起始地址(即要拷贝到的目的地),另一个为被拷贝字符串空间的起始地址,因为该函数的返回值为目标空间的起始地址,所以函数的返回类型为 char* 型。
对于函数的参数:
因为是将源字符串拷贝到目标字符串,所以目标字符串的内容会发生变化,而源字符串不会发生变化,所以源字符串传入指针参数前要用 const 修饰,防止变化。
举个栗子:
将函数 arr2 中的 “ABCD” 拷贝到 arr1 中
可以看到,拷贝结束后,原先arr1中的内容将会被覆盖,arr1中只有“ABCD”。
对于该函数,有以下几点注意:
1.源字符串必须以 ‘\0’ 结束
2.会将源字符串中的 ‘\0’ 拷贝到目标空间
3.目标空间必须足够大,以确保能存放源字符串
4.目标空间必须可变(不能为常量字符串、不能用 const 修饰)
2.模拟实现
#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
assert(dest != NULL);//断言,即当dest为空指针时就会报错
assert(src != NULL);//同上
char* ret = dest;//保存目标空间起始位置地址
while (*dest++ = *src++)
{
;
}
return ret;//返回起始地址
}
int main()
{
char arr1[10] = "abcdefg";
char arr2[] = "xyzopq";
char* p = my_strcpy(arr1, arr2);
printf("%s\n", p);
return 0;
}
提示:在模拟实现函数时,当传入的参数为指针时,为了防止传入的参数为空指针,一定要进行断言(assert)处理。
strcat——字符串追加
1.功能介绍
strcat为字符串追加函数,用于在目标字符串后再追加一个字符串,同 strcpy 函数一样,有两个参数,其中一个为目标空间的起始地址,另一个为被追加字符串的首地址,返回值为目标空间首元素的地址。而对于参数,也如 strcpy 一样,目标空间会变化,源字符串不会变化,所以源字符串会用 const 修饰。
栗子:
将 arr2 中的字符串追加到 arr1 后
注意以下几点:
1.源字符串必须以 ‘\0’ 结束
2.目标空间必须有足够的大,能容纳下源字符串的内容
3.目标空间必须可修改
2.模拟实现
char* my_strcat(char* dest, const char* src)
{
assert(dest!= NULL && src != NULL);//断言
char* ret = dest;//保存目标空间首地址
while (*dest != '\0')//找到目标空间中的‘\0’的位置
{
dest++;
}
while (*dest++ = *src++)//从目标空间中‘\0’的位置开始追加
{
;
}
return ret;//返回起始地址
}
strcmp——字符串比较
1.功能介绍
strcmp用于比较两个字符串,参数为两个待比较字符串的首地址,因为只是比较,并不是改变,所以两个参数都用 const 修饰,返回值为int型。
比较方式:逐个字符进行比较(实质比较的为字符的ASCII码值),即两字符串分别从首元素开始将第一个字符,第二个字符 …进行比较,若字符相同,则继续下一个比较,若第一次比较的字符不同,则比较就结束,返回规定的值。
对于返回值,有以下说明:
即当 str1 > str2 时,返回值 > 0 ; str1 = str2 时,返回值 = 0 ;当 str1 < str2 时,返回值 < 0 。
栗子:
2.模拟实现
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 != NULL);//断言,str1为空指针时报错
assert(str2 != NULL);//断言,str2为空指针时报错
while (*str1 == *str2)
{
if (*str1 == '\0')//字符串全部比较完毕
{
return 0;//比较完毕后返回0说明两字符串相等
}
str1++;
str2++;
}
return *str1 - *str2;//相减后的结果与返回值标准一致
}
长度受限的字符串函数(strncpy、strncat、strncmp)
strncpy——部分拷贝
功能:
我们知道,通过strcpy函数可以拷贝整个字符串,而这里的strncpy函数区别则在于可通过该函数拷贝字符串的部分内容,该函数的参数相较于strcpy函数多了一个参数: size_t num 即多了一个无符号整型的参数(必须保证此参数为正数,size_t即为无符号整型),这个参数的意义即为决定字符串中被拷贝字符的个数,即操作数。
对于操作数,注意:
1.当操作数小于等于源字符串中的字符个数时,操作数的大小决定被拷贝的字符个数。
2.当操作数大于源字符串中字符的个数时,strncpy函数将源字符串中的字符拷贝到目标空间后不够的将用’\0’填充。(因为字符串的结束标志为‘\0’,所以此种情况结果就为源字符串)
举个栗子:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "************";
char arr2[20] = "************";
char arr[] = "abcdfg";
strncpy(arr1, arr, 3);
strncpy(arr2, arr, 10);
printf("%s\n", arr1);
printf("%s\n", arr2);
return 0;
}
观察在内存中情况为:
strncat——部分追加
功能:
同strcat相比strncat也多出一个参数:size_t num,该操作数决定了目标字符串中追加的字符个数。
对于操作数,同样需注意:
1.当操作数小于源字符串中的字符个数时,操作数的大小决定被追加的字符个数,并在追加完后再追加一个’\0’。
2.当操作数大于等于源字符串中的字符个数时,将源字符串内容全部追加到目标空间便结束追加。
举个栗子:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "******";
char arr2[20] = "******";
char arr[] = "abcdfg";
strncat(arr1, arr, 3);
strncat(arr2, arr, 8);
printf("%s\n", arr1);
printf("%s\n", arr2);
return 0;
}
strncmp——部分比较
功能:
同 strcmp 相比 strncmp 多出一个参数:size_t num,该操作数决定了目标字符串中待比较的字符个数。比较方法和返回值的规定同 strcmp 一样。
栗子:
strlen——求字符串长度
1.函数功能
strlen函数是一个用于求字符串长度的库函数,它的参数是被求长度的字符串的起始地址,返回值是一个无符号整型(因为长度都为正数)。
注意以下几点:
1.字符串是将 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’)。
2.参数指向的字符串必须要以 ‘\0’ 结束。
3.注意函数的返回值为size_t,是无符号的( 易错 )
举个栗子:
可以看出,strlen函数的返回类型为无符号整型数(size_t),所以才会出现如上结果。
2.模拟实现(三种方法)
计数器方法
即定义一个变量为count,如果传入的指针指向的内容不是’\0’,那么count++,同时指针后移一位,循环往复,直到找到’\0’时返回count即可。
#include<stdio.h>
#include<string.h>
#include<assert.h>
size_t my_strlen(const char* str)
{
assert(str != NULL);//断言
int count = 0;
while (*str)
{
str++;
count++;
}
return count;
}
int main()
{
char arr[] = "abcdefg";
int ret=my_strlen(arr);
printf("%d\n", ret);
return 0;
}
递归法
即参数一进入函数体就判断传入指针指向的内容是否为’\0’,如果是就返回0,不是就返回1+my_strlen(str+1),如此进行下去,直到递归到内层时找到’\0’,这时再一步步将值返回回来即可。
size_t my_strlen(const char* str)
{
assert(str != NULL);
if (*str=='\0')
{
return 0;
}
return 1 + my_strlen(str + 1);
}
指针-指针法
运用 指针 - 指针 = 两个指针之间的元素个数 的方法,先保存字符串的首地址,然后将首地址向后移动,直至移动到地址指向字符串中 ‘ \0 ’ ,两地址相减后就得到字符串中元素的个数。
int my_strlen(const char* str)
{
assert(str != NULL);
char* start = str;//保存首地址
while (*str != '\0')//当指针指向‘\0’时停止循环
{
str++;
}
return str - start;//返回长度
}
strstr——字符串查找
1.函数功能
该函数为字符串查找函数,即给出一个已知的字符串 str2 ,在另一个字符串 str1 中查找是否含有字符串str2,若存在,则返回 str1 中首次出现字符串 str2 的起始地址,若 str1 中没有 str2 ,则返回空指针(NULL),所以函数的返回类型为 char* 型;该函数有两个参数,第一个参数为字符串 str1 的首地址,第二个参数为字符串 str2 的首地址;因为该函数只是对字符串进行查找,而不进行改变,所以两个参数都用 const 修饰。
注意:
若字符串 str2 为空字符串,则返回的就为 str1 的首地址。
举个栗子:
在字符串 arr1 中查找是否含有字符串 arr2
我们可以看到,字符串arr1中含有arr2,所以返回的就为arr1中首次出现字符串arr2部分的首地址,所以打印出来就为以上结果。
2.模拟实现
为了模拟实现strstr函数,我们首先要清楚查找字符串时可能出现的情况。
情况1:
即在字符串arr1中查找arr2时每个字符都只出现一次,查找起来比较简单;
情况2:
当要查找的字符串中有字符重复时,查找方式就相对复杂,如在 arr1 中查找 arr2 ,图解如下:
第一步:定义指针 cp 指向 arr1 的首元素,指针 s1 、s2 为空指针。
第二步:将 cp 赋给 s1 ,定义指针 s2 指向 arr2 的首元素,当指针 cp 指向的内容不为‘\0’时,判断 s1 与 s2 指向是内容是否相同(且不为‘\0’)。
第三步:当 s1 与 s2 指向的内容相同时,指针 s1 与 指针 s2 同时向后移动,当 s1 与 s2 出现指向的内容不同的情况时,指针cp 向前移动一步。
第四步:重复第二步与第三步,直至 s2 指向的内容为 ‘\0’ 。在此期间,若 cp 指向的内容为 ‘\0’ ,则说明字符串 arr1 已经查找完,且在 arr1 中找不到 arr2 。
模拟实现代码:
char* my_strstr(const char* dest, const char* src)
{
assert(dest && src);//断言
const char* s1 = NULL;
const char* s2 = NULL;
const char* cp = dest;
if (*src == '\0')
{
return (char*)dest;//规定当源字符串为‘\0’时,返回目标字符串首地址
}
while (*cp)
{
s1 = cp;
s2 = src;
while (*s1 && *s2 && (*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return (char*)cp;
}
cp++;
}
return NULL;
}
int main()
{
char arr1[] = "abbbcdefgh";
char arr2[] = "bcdef";
char* ret = my_strstr(arr1, arr2);
if (ret == NULL)
{
printf("未找到\n");
}
else
{
printf("找到了:%s\n", ret);
}
return 0;
}
strtok——字符串分割
功能:
strtok函数能通过给定的一系列字符将一个字符串分割成许多子字符串的函数。
注意以下几点:
1.strDelimit 参数是个字符串,定义了用作分隔符的字符集合。
2.第一个参数指定一个字符串,它包含了0个或者多个由strDelimit字符串中一个或者多个分隔符分割的标记。
3.strtok函数找到strToken中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改)
4.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
5.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
6.如果字符串中不存在更多的标记,则返回 NULL 指针。
看如下示例:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcd@efg*hijkl.xyz";
char arr2[20] = { 0 };
strcpy(arr2, arr1);//将字符串arr1临时拷贝到arr2中
char* p = "@*.";//分割标记字符串
char* ret = NULL;
for (ret = strtok(arr2, p); ret != NULL; ret=strtok(NULL, p))
{
printf("%s\n", ret);
}
return 0;
}
运用for循环,首先根据标记字符串来分割arr1中的第一个字符串,然后判断字符串被分割后这个标记的指针是否为NULL,若不为NULL,则打印出第一个字符串,接着再运用strtok函数并将第一个参数赋为NULL ,依据标记字符串再来进行分割,直至返回的这个标记的指针为 NULL 时停止打印。
strerror、perror——错误报告函数
strerror
strerror函数为一个错误报告函数,其参数为一个整数,即错误码,该函数能将错误码转换为错误信息(但不能自己打印)。
一个简单的栗子:
如上strerror函数中的0、1、2、3、4 都为错误码,其相对应的错误信息打印出来就如上图所示。
perror
该函数也用于程序中错误信息的报告,但与strerror函数不同的是该函数可直接直接打印出错误信息。
实质该函数的功能分两步:
1.首先把错误码转换为错误信息
2.打印错误信息(包含自定义的信息)
函数运用实例:
说明:fopen函数的功能是打开一个文件,当其执行成功时会返回打开文件的首地址,执行失败时会返回一个空指针(NULL)。
#include<stdio.h>
#include<string.h>
#include<errno.h>//库函数使用时的错误信息都会存放在errno这个全局变量中,
//因此在用这个变量前需先引用此头文件
int main()
{
FILE* pf = fopen("test.txt", "r");//打开test.txt文件阅读
if (pf == NULL)
{
printf("%s\n", strerror(errno));//errno用来存放错误码
perror("fopen");
}
return 0;
}