字符函数和字符串函数
1.函数介绍
1.1 strlen
size_t strlen ( const char * str );
- strlen函数是用来求字符串的长度的,我们在学习一个函数的时候,可以参考官网和cplusplus上面的介绍进行学习。
- 例如上面这个strlen函数的例子,我们可以看到它的参数是一个字符型的指针,返回类型是一个无符号的整形。
- 下面我们重点对strlen说几个点:
1.字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
2.参数指向的字符串必须要以 ‘\0’ 结束。
3.注意函数的返回值为size_t,是无符号的( 易错 )
4.学会strlen函数的模拟实现
- 上面可以看出arr数组是有’\0’的,但是长度并没有计入。
- strlen的模拟实现
size_t my_strlen(const char* str) {
const char* start = str; //字符串的起始位置就是str
const char* end = str;
while (*end != '\0') { //用来找到字符串的末尾处
end++;
}
return end - start; //最后指针减指针,巧妙地得到了字符串的长度
}
- 利用指针-指针的概念可以得到之间元素个数的原理,构造了上述函数。
1.2 strcpy
char strcpy(char * destination, const char * source );*
- strcpy是一个可以将一个字符串复制到另一个字符串的函数,它的参数是两个char*的指针,返回的类型也是一个字符型的指针,第一个参数是复制到的地址,第二个参数是复制的地址。
- strcpy注意一下几点:
1.源字符串必须以 ‘\0’ 结束。
2.会将源字符串中的 ‘\0’ 拷贝到目标空间。
3.目标空间必须足够大,以确保能存放源字符串。
4.目标空间必须可变。
5.学会模拟实现
- 在这里我们要注意为什么一定要以’\0’去结束,因为没有结束的标志将导致这个函数一直复制下去,因为在函数内部的设计当中,函数的停止标志是’\0’,因此要多加注意。
- strcpy的模拟实现
char* my_strcpy(const char* des, const char* sou)
{
char* ret = des; //记录des的起始位置
while (des++ == sou++)
{
;
}
return ret;
}
1.3 strcat
char * strcat ( char * destination, const char * source );
- strcat是一个字符串追加函数,它可以在一个字符串后面追加一个字符串,返回追加后的字符串的地址。
- strcat需要注意的几点:
1.源字符串必须以 ‘\0’ 结束。
2.目标空间必须有足够的大,能容纳下源字符串的内容。
3.目标空间必须可修改。
4.字符串自己给自己追加,如何?
- 原字符串是必须要有斜杆零的,因为这个函数要找到源字符串’\0’的位置进行追加,如果没有这个标志,将无法追加。
- 其次,字符串是不可以自己给自己追加的,因为当自己给自己追加的时候,自身的地址没有改变,而且自身一直在改变,导致自己追加自己一直结束不了,可以通过下面的图来理解。
- strcat的模拟实现:
char* my_strcat(const char* des, const char* sou)
{
char* ret = des;
while (des)
{
des++; //找到’\0’的位置
}
while (des++ == sou++)
{
; //进行追加
}
return ret;
}
1.4 strcmp
int strcmp ( const char * str1, const char * str2 );
- strcmp是一个字符串比较函数,可以对字符串进行比较,当时是对应字符的比较,比较的是每个字符的ASCLL值。
- 如果str1>str2,则返回一个大于0的输,小于返回小于0的输,等于返回0。
- strcmp需要注意几点:
1.第一个字符串大于第二个字符串,则返回大于0的数字
2.第一个字符串等于第二个字符串,则返回0
3.第一个字符串小于第二个字符串,则返回小于0的数字
- strcmp的模拟实现:
int my_strcmp(const char* src, const char* dst)
{
int ret = 0;
assert(src != NULL);
assert(dst != NULL);
while (src++ == dst++)
{
; //找到不相等的时候
}
return ((char*)src) - ((char*)dst);
}
1.5 strncpy
char * strncpy ( char * destination, const char * source, size_t num );
- strncpy是对应strcpy的一种限制,只复制前n个字符串,其他参数和类型与strcpy是类似的。
- 拷贝num个字符从源字符串到目标空间。
- 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
1.6 strncat
char * strncat ( char * destination, const char * source, size_t num );
- strncat也是对strcat的一种限制,只追加前n个字符,其他参数和strcat是相似的。
/* strncat example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[20];
char str2[20];
strcpy (str1,"To be ");
strcpy (str2,"or not to be");
strncat (str1, str2, 6);
puts (str1);
return 0;
}
1.7 strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
- strncmp和前面是类型的,只比较前n个字符,其他参数和strcmp类似的。
- 比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。
1.8 strstr
*char * strstr ( const char str1, const char * str2);
- strstr是一个找字串的函数,它的用法是在str1中找有没有str2,如果有则返回找到的字串的地址。
/* strstr example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="This is a simple string";
char * pch;
pch = strstr (str,"simple");//找到simple的首元素的地址
strncpy (pch,"sample",6);
puts (str);
return 0;
}
1.9 strtok
char * strtok ( char * str, const char * sep );
- strtok是字符串分隔函数,可以将一个字符串分隔为多个字符串,返回一个char*的指针
- sep参数是个字符串,定义了用作分隔符的字符集合
- 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
- strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
- strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
- strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
- 如果字符串中不存在更多的标记,则返回 NULL 指针
/* strtok example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="- This, a sample string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str," ,.-");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, " ,.-");
}
return 0;
}
1.10 strerror
- 返回错误码,所对应的错误信息。
- 头文件
include<errno.h>
int main ()
{
FILE * pFile;
pFile = fopen ("unexist.ent","r");
if (pFile == NULL)
printf ("Error opening file unexist.ent: %s\n",strerror(errno));
//errno: Last error number
return 0;
}
- 这里建议使用perror函数。
1.11 memcpy
void * memcpy ( void * destination, const void * source, size_t num );
- num大小为字节,很重要!
- 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
- 这个函数在遇到 ‘\0’ 的时候并不会停下来。
- 如果source和destination有任何的重叠,复制的结果都是未定义的。
- 注意:这里是建议在内存重叠的时候不建议使用mencpy,但是其实是可以正常运行的,这个点以后会重点讲。
/* memcpy example */
#include <stdio.h>
#include <string.h>
struct {
char name[40];
int age;
} person, person_copy;
int main ()
{
char myname[] = "Pierre de Fermat";
/* using memcpy to copy string: */
memcpy ( person.name, myname, strlen(myname)+1 ); //把'\0'考虑进去
person.age = 46;
/* using memcpy to copy structure: */
memcpy ( &person_copy, &person, sizeof(person) );
printf ("person_copy: %s, %d \n", person_copy.name, person_copy.age );
return 0;
}
1.12 memmove
void * memmove ( void * destination, const void * source, size_t num );
- num是字节
- 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
/* memmove example */
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "memmove can be very useful......";
memmove(str + 20, str + 15, 11);
puts(str);
return 0;
}
1.13 memcmp
int memcmp ( const void * ptr1,const void * ptr2,size_t num );
- num是字节
- 比较从ptr1和ptr2指针开始的num个字节
- 返回值如下:
- 与strcmp是一致的
/* memcmp example */
#include <stdio.h>
#include <string.h>
int main ()
{
char buffer1[] = "DWgaOtP12df0";
char buffer2[] = "DWGAOTP12DF0";//大写的ascll码小于小写的 因此buffer2小,buffer1大
int n;
n=memcmp ( buffer1, buffer2, sizeof(buffer1) );
if (n>0) printf ("'%s' is greater than '%s'.\n",buffer1,buffer2);
else if (n<0) printf ("'%s' is less than '%s'.\n",buffer1,buffer2);
else printf ("'%s' is the same as '%s'.\n",buffer1,buffer2);
return 0;
}
2.总结
- 在库函数和内存函数中还有一些重点,细节没有讲完,我将在之后的内容中进行细讲,以便大家更好的学习,谢谢大家。