字符串函数
1.strlen函数
strlen库函数
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abc";
char arr1[] = { 'a','b','c' };
int len = strlen(arr);
int len1 = strlen(arr1);//没有'\0'就无法停止
printf("%d\n",len);
printf("%d\n",len1);//就会出现随机值
return 0;
}
strlen函数是计算字符串长度的
字符串已经\0'作为结束标志,strlen函数返回的是在字符串中\0'前面出现的字符个数(不包含'\0')。 参数指向的字符串必须要以'\0'结束
主函数的返回值为size_t,是无符号的(易错) 学会strlen函数的模拟实现
自定义strlen函数
方法一:计数器版本
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strlen(const char* str)
{
int count = 0;
assert(str != NULL);
while(*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[] = { 'a','b','c' };
int len = my_strlen(arr);
printf("%d\n",len);
return 0;
}//计数器版本
方法二:递归版本
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strlen(const char* str)
{
assert(str != NULL);
if(*str != '\0')
return 1 + my_strlen(str + 1);
}
int main()
{
char arr[] = { 'a','b','c' };
int len = my_strlen(arr);
printf("%d\n",len);
return 0;
}//递归版本
方法三:指针-指针
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strlen(const char* str)
{
assert(str != NULL);
char* ret = (char*)str;
while(*str != '\0')
{
str++;
}
return str - ret;
}
int main()
{
char arr[] = { 'a','b','c' };
int len = my_strlen(arr);
printf("%d\n",len);
return 0;
}//指针-指针版本
易错点:无符号
#include<stdio.h>
#include<string.h>
int main()
{
if(strlen("abc") - strlen("abcdef") < 0)
{
printf("<\n");
}
else
{
printf(">=\n");
}
}
strlen("abc") - strlen("abcdef")本来解读为-3,但是被无符号整数调整以后-3变成(逆循环)一个极大的数字
如果想要一个正常的大小关系,就调用自定义的strlen函数
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strlen(const char* str)
{
assert(str != NULL);
char* ret = (char*)str;
while(*str != '\0')
{
str++;
}
return str - ret;
}
int main()
{
if(my_strlen("abc") - my_strlen("abcdef") < 0)
{
printf("<\n");
}
else
{
printf(">=\n");
}
return 0;
}
2.strcpy函数
strcpy库函数
strcpy()函数是用来拷贝字符串的
char* strcpy(char* destination,char* source)
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = { 0 };
char arr2[] = "hello bit";
strcpy(arr1,arr2);
printf("%s",arr1);
return 0;
}
考虑一下如果没有'\0'是否可以实现拷贝
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = { 0 };
char arr2[] = {'h','e','l','l','o',' ','b','i','t'};
strcpy(arr1,arr2);
printf("%s",arr1);
return 0;
}//事实证明这样写是不行的,必须有'\0'阻止
总结:1.拷贝字符串里面必须有'\0' 2.原字符串空间必须足够大
源字符串必须以'\0'结束。 会将源字符串中的'\0'拷贝到目标空间。 目标空间必须足够大,以确保能存放源字符串。 目标空间必须可变。 学会模拟实现。
3.strncpy函数
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "hello ";
strncat(arr1,arr1,10);//字符串自身追加(连接)
printf("%s",arr1);
return 0;
}
hello hello hell
要拷贝自身,如果第三个参数很大,那么也会相应循环补好
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "hello ";
char arr2[] = "bit.";
strncpy(arr1,arr2,2);
printf("%s",arr1);
return 0;
}
billo
如果第三个参数很大,那么也会相应的补好'\0'。
4.strcat函数
strcat库函数
写法一:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "hello ";
char arr2[] = "bit";
strcat(arr1,arr2);//字符串追加(连接)
printf("%s",arr1);
return 0;
}
写法二
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "hello ";
strcat(arr1,"world");//字符串追加(连接)
printf("%s",arr1);
return 0;
}
源字符串必须以'\0'结束。 目标空间必须有足够的大,能容纳下源字符串的内容。 目标空间必须可修改。
自定义strcat函数
#include<stdio.h>
#include<string.h>
#include<assert.h>
void my_strcat(char* dest, const char* src)
{
assert(dest && src);
//1.找到目标字符串中的\0
while(*dest)
{
dest++;
}
//2.源数据追加过去,包含\0
while(*src)
{
*dest = *src;
dest++;
src++;
}
}
int main()
{
char arr1[] = "hello ";
char arr2[] = "world";
my_strcat(arr1,arr2);
printf("%s",arr1);
return 0;
}
while(*src)
{
*dest = *src;
dest++;
src++;
}
//直接改成
while(*dest++ = *src++)
{
;//更简洁
}
易错点:追加目标代码本身
直接 strcat(arr1,arr1);相当于是不停地将arr1中的部分往后堆叠,arr不停地增加,追加arr1就不会完结,从而导致代码死循环。
这时候就要用strncat函数来表示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "hello ";
strncat(arr1,arr1,5);//字符串自身追加(连接)
printf("%s",arr1);
return 0;
}
hello hello
5.strncat函数
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "hello ";
strncat(arr1,arr1,5);//字符串自身追加(连接)
printf("%s",arr1);
return 0;
}
hello hello
strncat()主要功能是在字符串的结尾追加n个字符。
6.strcmp函数
字符串比较函数
strcmp库函数
#include<stdio.h>
#include<string.h>
int main()
{
char ch1[] = "obc";
char ch2[] = "abcdef";
int ret = strcmp(ch1,ch2);//字符串比较
printf("%d",ret);
return 0;
}
1
明显的该库函数不能体现出判断那个字符串长或短的功能
判断字符串的代码:
#include<stdio.h>
#include<string.h>
int main()
{
char ch1[] = "obc";
char ch2[] = "abcdef";
int ret = strcmp(ch1,ch2);//字符串比较
if(ret == 0)
{
printf("相等");
}
else printf("不相等");
return 0;
}
自定义strcmp函数
判断字符串大小:
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char* s1,const char* s2)
{
assert(s1 && s2);
while(*s1++ == *s2++)
{
if(*s1 == '\0')
{
return 0;
}
}
if(*s1 > *s2)
{
return 1;
}
else
{
return -1;
}
}
int main()
{
char* p = "obc";
char* q = "abcdef";
int ret = my_strcmp(p,q);//字符串比较
if(ret > 0)
{
printf("p>q\n");
}
else if(ret < 0)
{
printf("p<q\n");
}
else printf("p=q");
return 0;
}
7.strncmp函数
#include<stdio.h>
#include<string.h>
int main()
{
char* p = "obc";
char* q = "abcdef";
int ret = strncmp( p, q, 3);//只比较前三个字符是否相等
printf("%d\n", ret);
return 0;
}
strncmp函数为字符串比较函数,字符串大小的比较是以ASCII 码表上的顺序来决定,此顺序亦为字符的值。其函数声明为int strncmp( const char * str1, const char * str2, size_t n );功能是把 str1 和 str2 进行比较,最多比较前 n 个字节。
strcpy strcat strcmp ——————长度不受限制的字符串函数 strncpy strncat strncmp ——————长度受限制的字符串函数
8.strstr函数
strstr库函数
strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回 str1字符串从 str2第一次出现的位置开始到 str1结尾的字符串;否则,返回NULL。
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcdefghijk";
char arr2[] = "bcd";
//在arr1中查找是否包含arr2数组
char* str = strstr(arr1,arr2);
if(str != NULL)
{
printf("Yes");
}
else printf("No");
return 0;
}
自定义strstr函数
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strstr(const char* str1,const char* str2)
{
assert(str1 && str2);
const char* s1 = NULL;
const char* s2 = NULL;
const char* cp = str1;
if(*str2 == '\0')
{
return (char*)str1;
}
while(*cp)
{
s1 = cp;
s2 = str2;
while(*s1 && *s2 && (*s1 == *s2))
{
s1++;
s2++;
}
if(*s2 == '\0')
{
return (char*)cp;
}
cp++;
}
return NULL;
}
int main()
{
char arr1[] = "abcdefghijk";
char arr2[] = "bcd";
//在arr1中查找是否包含arr2数组
char* str = my_strstr(arr1,arr2);
if(str != NULL)
{
printf("找到了:%s\n",str);
}
else printf("没找到\n");
return 0;
}
abcdef cde
abbbcdef bbc //会发现第一个b匹配不上,这时候就要回退,再试试看,把str1比较的字符往后移
9.strtok函数
strtok库函数
用于切割字符串
举例
3090378834@.qq.com//@和.都是切割符
3090378834
com
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "3090378834@.qq.com";
char* p = "@.";
char tmp[20] = { 0 };
strcpy(tmp, arr);
char* str = strtok(tmp, p);
printf("%s\n",str);
str = strtok(NULL, p);//明确看出有三段所以调用三次
printf("%s\n",str);
str = strtok(NULL, p);
printf("%s\n",str);
return 0;
}
3090378834
qq
com
char* strtok(char* str,const char* sep);
sep参数是个字符串,定义了用作分隔符的字符集合
·第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记 ·strtok函数找到str中的下一个标记,并将其用'\0'结尾,返回一个指向这个标记的指针。(注:strtok函函会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。) ·strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置 ·strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记 ·如果字符串中不存在更多的标记,则返回NULL指针
优化版本:
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "3090378834@.qq.com";
char* p = "@.";
char tmp[20] = { 0 };
strcpy(tmp, arr);
char* ret = NULL;
for(ret = strtok(tmp,p);ret != NULL; ret = strtok(NULL, p))
{
printf("%s\n",ret);
}
return 0;
}
10.strerror函数
返回错误码,所对应的错误信息
char* strerror(int errnum);
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
printf("%s\n",strerror(0));
printf("%s\n",strerror(1));
printf("%s\n",strerror(2));
printf("%s\n",strerror(3));
printf("%s\n",strerror(4));
printf("%s\n",strerror(5));
printf("%s\n",strerror(6));
return 0;
}
No error
Operation not permitted
No such file or directory
No such process
Interrupted function call
Input/output error
No such device or address
调用失败查看原因,把错误码转换成错误信息
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("test.txt","r");
if(pf == NULL)
{
printf("%s\n",strerror(errno));
return 1;
}
//读文件
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
No such file or directory
11.perror函数
直接打印错误信息,用法更加简单
#include<stdio.h>
int main()
{
FILE* pf = fopen("test.txt","r");
if(pf == NULL)
{
perror("fopen");
return 1;
}
//读文件
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
fopen: No such file or directory//fopen自定义打印
1.首先把错误码转化为错误信息 2.打印错误信息(包含了自定义的信息)
字符分类函数
字符函数
函数 | 如果它的参数符合下列条件就返回真 |
---|---|
iscntrl | 任何控制字符 |
isspace | 空白字符:空格' ',换页'\f',换行'\n',回车'\r',制表符'\t'或者垂直制表符'\v' |
isdigit | 十进制数字0-9 |
islower | 小写字母a-z |
isupper | 大写字母A-Z |
isalpha | 字母a-z或A-Z |
isalnum | 字母或者数字,a-z,A-Z,0-9 |
ispunct | 标点符号,任何不属于数字或者字母的图形字符(可打印) |
isgraph | 任何图形字符 |
isprint | 任何可打印字符,包括图形字符和空白字符 |
举例1:
#include<stdio.h>
#include<ctype.h>
int main()
{
int ch = '2';
//isdigit 如果数字字符返回非0的值,如果不是数字字符,返回0
int ret = isdigit(ch);
printf("%d",ret);
return 0;
}
1
举例2:
#include<stdio.h>
#include<ctype.h>
int main()
{
int ch = 'a';
//islower 如果小写字母字符返回非0的值,如果不是小写字母字符,返回0
int ret = islower(ch);
printf("%d",ret);
return 0;
}
2
字符转换
int tolower( int c ); //大写转小写
int toupper( int c ); //小写转大写
举例1:
#include<stdio.h>
#include<ctype.h>
int main()
{
char arr[20] = { 0 };
scanf("%s",arr);
int i = 0;
while(arr[i] != '\0')
{
if(isupper(arr[i]))
{
arr[i] = tolower(arr[i]);
}
printf("%c ",arr[i]);
i++;
}
return 0;
}
内存函数
内存函数:
-
memcpy
-
memmove
-
memmcmp
-
memset
memcpy函数
内存拷贝
memcpy指的是C和C++使用的内存拷贝函数,函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝n个字节到目标destin中。
void *memcpy(void *destin, void *source, unsigned n);
memcpy库函数
#include<stdio.h>
#include <cstring>
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
//strcpy拷贝的是字符串
memcpy(arr2,arr1,20);
printf("%s\n",arr2);
return 0;
}
自定义memcpy函数
#include<stdio.h>
#include <cstring>
#include<assert.h>
void* my_memcpy(void* dest,const void* src,size_t num)
{
assert(dest && src);
void* ret = dest;
//void* 类型的指针是不能直接++或者--或者解引用的
//所以直接强制转换为char类型,然后每个地址依次打印
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
//*(char*) dest++ = *(char*) src++;这是有问题的
}
return ret;
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
my_memcpy(arr2,arr1,20);
return 0;
}
arr1内的数据拷贝到arr2中去
接下来考虑如何将arr1中的1,2,3,4,5放置于3,4,5,6,7中去
1,2,3,4,5,6,7,8,9,10
1,2,1,2,3,4,5,8,9,10
memcpy应该拷贝不重叠的内存
memmove可以处理内存重叠的内存
memmove函数
memmove库函数
void* memmove( void* dest, const void* src, size_t num)
可以通过这个函数来实现内存重叠部分的功能
#include<stdio.h>
#include <cstring>
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
memmove(arr1+2, arr1, 20);
return 0;
}
自定义memmove函数
#include<stdio.h>
#include<cstring>
#include<assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
void* ret = dest;
assert(dest && src);
if(dest < src)
{
//从前向后拷贝
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//从后向前拷贝
while(num--)//20 19
{
*((char*)dest + num) == *((char*)src + num);
}
}
return ret;
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
my_memmove(arr1+2, arr1, 20);
return 0;
}
可以把源数据从前向后拷贝,也可以从后向前拷贝
但是经过vs调试可以发现就用memcpy库函数实际上也可以完成上述的自己拷贝自己的作用,并且效果与自定义memmove函数一致。
memcpy - 只要实现了不重叠拷贝就行了,而vs中的实现既可以拷贝不重叠,也可以拷贝重叠内存。
memcmp函数
内存比较函数
memcmp函数的原型为 int memcmp(const void *str1, const void *str2, size_t n);其功能是把存储区 str1 和存储区 str2 的前 n 个字节进行比较。该函数是按字节比较的,位于string.h。
int memcmp( const void * ptr1, const void * ptr2, size_t num)
#include<stdio.h>
#include <string.h>
int main()
{
float arr1[] = { 1.0,2.0,3.0,4.0 };
float arr2[] = { 1.0,3.0 };
int ret = memcmp(arr1, arr2, 4);
printf("%d\n",ret);
return 0;
}
1
memset函数
内存设置函数
memset是计算机中C/C++语言初始化函数。作用是将某一块内存中的内容全部设置为指定的值, 这个函数通常为新申请的内存做初始化工作。
void* memset( void * ptr, int value, size_t num)
#include<stdio.h>
#include <string.h>
int main()
{
int arr[10] = { 0 };
memset(arr, 1, 20);//以字节为单位设置内存
return 0;
}