1.strlen
size_t strlen ( const char * str );
参数:
str -- 要计算长度的字符串。
返回值:
该函数返回字符串的长度。
注意函数的返回值为size_t,是无符号的( 易错 )
可以写成int 各有利弊
写成size_t时 不会出现负数情况
写成int 当相减时 可以为负数
但size_t就一直为正数 会出现一些错误
if((strlen("abc")-strlen("abcdef"))>0)//小心返回类型
{
printf("hehe\n");
}
else//写int不会出现这种错误 size_t可以保证结果不为负数 各有利弊
{
printf("haha\n");
}
strlen库函数的使用
#include<stdio.h>
#include<string.h>
int main()
{
char arr[]="abcdef";
int len=strlen(arr);
printf("len=%d\n",len);
return 0;
}
6
strlen自定义函数的实现
#include<stdio.h>
#include<assert.h>
#include<string.h>
int my_strlen(const char* str)//库里面返回类型是size_t 其实也就是unsigned int无符号整型
{
int count=0;
assert(str!=NULL);
while(*str!='\0')
{
count++;
str++;
}
return count;
}
int main()
{
int len=my_strlen("abcdef");
printf("%d\n",len);
return 0;
}
6
2.strcpy
char* strcpy(char * destination, const char * source );
参数:
dest -- 指向用于存储复制内容的目标数组。
src -- 要复制的字符串。
返回值:
该函数返回一个指向最终的目标字符串 dest 的指针。
源字符串必须以 '\0' 结束。
会将源字符串中的 '\0' 拷贝到目标空间。
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。
strcpy库函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
int main()
{
char arr1[]="abcdef";
char arr2[]="bit";
strcpy(arr1,arr2);
printf("%s\n",arr1);
return 0;
}
bit
strcpy自定义函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
char* my_strcpy(char* dest,const char* src)
{
assert(dest!=NULL);
assert(src!=NULL);
char* ret=dest;
//拷贝src指向的字符串到dest指向的空间 包含'\0'
//while(*src!='\0')
//{
// *dest=*src;//b放到a上
// dest++;
// src++;
//}
//*dest=*src//'\0'
//简化
while(*dest++=*src++)
{
;
}
//赋值的同时往后走 当\0赋值的时候 \0的ascii码值为0 表达式为假 跳出循环
return ret;
//返回目的空间的起始地址
}
int main()
{
char arr1[]="abcdef";//arr1元素个数大于arr2
//char arr1[]="abcdefghi"//这是常量字符串 改变不了 错误
char arr2[]="bit";
//char arr2[]={'b','i','t'}错误 无\0
my_strcpy(arr1,arr2);
//第一个参数目的地地址 第二个参数是源头
//为了copy后只打印bit 要把\0放到d的位置
printf("%s\n",arr1);
return 0;
}
bit
3.strcat
char * strcat ( char * destination, const char * source );
参数:
dest -- 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串。
src -- 指向要追加的字符串,该字符串不会覆盖目标字符串。
返回值:
该函数返回一个指向最终的目标字符串 dest 的指针。
源字符串必须以 '\0' 结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。
strcat库函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
int main()
{
//char arr1[30]="hello\0xxxxxxx";//有x变为\0 说明是追加过去的\0
char arr1[30]="hello";
char arr2[]="world";//arr2里面也要有\0 因为arr2的\0可以追加过去
strcat(arr1,arr2);//不具体规定元素个数的追加 空间过小不行 arr1元素个数变成30
printf("%s\n",arr1);
return 0;
}
helloworld
strcat自定义函数
char* my_strcat(char* dest,const char* src)
{
char* ret=dest;
assert(dest!=NULL);
assert(src);
//1.找到目的字符串的'\0'
while(*dest!='\0')
{
dest++;
}
//2.追加
while(*dest++=*src++)
{
;
}
return ret;
}
int main()
{
char arr1[30]="hello";
char arr2[]="world";
my_strcat(arr1,arr2);
printf("%s\n",arr1);
return 0;
}
helloworld
4.strcmp
int strcmp ( const char * str1, const char * str2 );
参数:
str1 -- 要进行比较的第一个字符串。
str2 -- 要进行比较的第二个字符串。
返回值:
如果返回值小于 0,则表示 str1 小于 str2。
如果返回值大于 0,则表示 str1 大于 str2。
如果返回值等于 0,则表示 str1 等于 str2。
strcmp库函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
int main()
{
char* p1="abcdef";
char* p2="sqwer";
int ret=strcmp(p1,p2);
//比较的是字符的ASCII码值 相同接着往下比较
printf("%d\n",ret);//编译器不同 得到的结果不同 因此写判断条件的时候写>0 <0 =0
if(ret>0)
{
printf("p1>p2\n");
}
else if(ret<0)
{
printf("p1<p2\n");
}
else
{
printf("p1=p2\n");
}
}
p1<p2
strcmp自定义函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
int my_strcmp(const char* str1,const char* str2)//比较 不希望改变
{
assert(str1&&str2);
//比较
while(*str1&&(*str1==*str2))//相等且str1不为\0继续比较 如果没有*str1两边都为\0时无法跳出循环
{
str1++;
str2++;
}
//if(*str1>*str2)
// return 1;
//else
// return -1;
return (*str1-*str2);
}
int main()
{
char* p1="abcdef";
char* p2="abqwe";
int ret=my_strcmp(p1,p2);
printf("ret=%d\n",ret);
if(ret>0)
{
printf("p1>p2\n");
}
else if(ret<0)
{
printf("p1<p2\n");
}
else
{
printf("p1=p2\n");
}
return 0;
}
p1<p2
5.strncpy
char * strncpy ( char * destination, const char * source, size_t num );
参数:
dest -- 指向用于存储复制内容的目标数组。
src -- 要复制的字符串。
n -- 要从源中复制的字符数。
返回值:
该函数返回最终复制的字符串。
拷贝num个字符从源字符串到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
strncpy库函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
int main()
{
char arr1[10]="abcdef";
char arr2[]="hello bit";
strncpy(arr1,arr2,4);//增加个数 相对安全 只copy4个
//char arr1[10]="abcdef";
//char arr2[]="bit";
//strncpy(arr1,arr2,6);//长度过长 不够 剩下用\0填充
printf("%s\n",arr1);
return 0;
}
字节数够打印hellef
字节数不够会补充\0 打印bit
strncpy自定义函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
char *my_strncpy(char *dest, const char *src, size_t count)//copy字节数
{
char *ret = dest;//起始地址不变 给一个中间指针变量
while (count--)
{
if ((*dest= *src) != 0)//赋值的同时保证不是\0
src++;//向后挪动一个字符
dest++;//也向后挪动一个字符
}
return ret;//返回起始地址
}
int main()
{
char arr1[10]="abcdef";
char arr2[]="bit";
my_strncpy(arr1,arr2,2);
//my_strcnpy(arr1,arr2,4);
printf("%s\n",arr1);
return 0;
}
字节数够的时候(2) bicef
字节数不够的时候(4) bit 后面会补\0
6.strncat
char * strncat ( char * destination, const char * source, size_t num );
参数:
dest -- 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串,包括额外的空字符。
src -- 要追加的字符串。
n -- 要追加的最大字符数。
返回值:
该函数返回一个指向最终的目标字符串 dest 的指针。
strncat库函数
#include<Stdio.h>
#include<string.h>
#include<assert.h>
int main()
{
char arr1[30]="hello\0xxxxxxxx";//追加完之后会主动放\0
char arr2[]="world";
strncat(arr1,arr2,3);//追加个数过多 加完后再补一个\0就不管了
printf("%s\n",arr1);
return 0;
}
hellowor
strncat自定义函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
char* my_strncat(char * dest, const char *src, size_t n)
{
assert(dest);
assert(src);
char *ret=dest;//保留起始地址
//找到\0
while(*dest)
{
dest++;
}
//开始追加
while(n--)
{
*dest++=*src++;
}
//追加完后补上\0
*dest = '\0';
return ret;
}
int main()
{
char arr1[30]="hello";//追加完之后会主动放\0
char arr2[]="world";
my_strncat(arr1,arr2,3);//追加个数过多 加完后再补一个\0就不管了
printf("%s\n",arr1);
return 0;
}
hellowor
7.strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
参数:
str1 -- 要进行比较的第一个字符串。
str2 -- 要进行比较的第二个字符串。
n -- 要比较的最大字符数。
返回值:
如果返回值 < 0,则表示 str1 小于 str2。
如果返回值 > 0,则表示 str1 大于 str2。
如果返回值 = 0,则表示 str1 等于 str2。
strncmp库函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
int main()
{
const char* p1="abcdef";
const char* p2="abcqwer";
int ret=strncmp(p1,p2,3);//比较字节数 比较前3个 返回0 比较前4个 返回负数
printf("%d\n",ret);
if(ret>0)
{
printf("p1>p2\n");
}
else if(ret<0)
{
printf("p1<p2\n");
}
else
{
printf("p1=p2\n");
}
return 0;
}
p1=p2
strncmp自定义函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
int my_strncmp(const char* str1,const char* str2,size_t num)
{
assert(str1&&str2);
//--num比较字节数减少 减到0后跳出循环 比较完
//*str1==*str2 如果不等 就直接跳出循环 比较对应字符的ASCII 也包括str2先到\0 这种情况
while(--num&&*str1&&(*str1==*str2))//*str1不为\0 如果继续自加比较 如果不加这个条件 当两边同时是\0时不能跳出循环
{
str1++;
str2++;
}
//返回 看差值
return (*str1-*str2);
}
int main()
{
const char* p1="abcdef";
const char* p2="abcqwer";
int ret=strncmp(p1,p2,3);//比较前3个 返回0 比较前4个 返回负数
printf("%d\n",ret);
if(ret>0)
{
printf("p1>p2\n");
}
else if(ret<0)
{
printf("p1<p2\n");
}
else
{
printf("p1=p2\n");
}
return 0;
}
p1=p2
8.strstr
char * strstr ( const char *str1, const char * str2);
参数:
str1 -- 要被检索的 C 字符串。
str2 -- 在 str1 字符串内要搜索的小字符串。(子字符串)
返回值:
该函数返回在str1 中第一次出现 str2字符串的位置,如果未找到则返回 null。
strstr库函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
int main()
{
char *p1="abcdefghi";
char *p2="def";
char *ret=strstr(p1,p2);
//出现两次的话会返回第一次出现的首字符地址
//返回的是子串首字符地址
if(ret==NULL)
{
printf("子串不存在");
}
else
{
printf("%s\n",ret);//打印defghi
}
return 0;
}
defghi
strstr自定义函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
char* my_strstr(const char* p1,const char* p2)
{
assert(p1!=NULL);
assert(p2!=NULL);
char *s1=p1;
char *s2=p2;
char *cur=p1;//如果用p1和p2走的话 不能记住原始地址 返回地址 而且会遇到特殊情况
if(*p2=='\0')//特殊情况:abbbcdef bbc 这样的话 无法找出来 所以创建第三第四个指针 进行遍历
{
return (char*)p1;
}
while(*cur)
{
s1=cur;//s1需要回来 再次进行遍历
s2=(char*)p2;
while(*s1&&*s2&&(*s1==*s2))//*s1 *s2!='\0'
{
s1++;
s2++;
}
if(*s2=='\0')
{
return cur;//找到子串
}
if(*s1=='\0')
{
return NULL;//当s1字符数量<s2字符数量 提前终止
}
cur++;
}
return NULL;//找不到子串
}
int main()
{
char *p1="abbbcdef";
char *p2="bbc";
char *ret=my_strstr(p1,p2);
if(ret==NULL)
{
printf("子串不存在");
}
else
{
printf("%s\n",ret);//打印bbcdef
}
return 0;
}
bbcdef
9.strtok
char * strtok ( char * str, const char * sep );
参数:
str -- 要被分解成一组小字符串的字符串。
sep -- 包含分隔符的 C 字符串。
返回值:
该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。
sep参数是个字符串,定义了用作分隔符的字符集合
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标 记。
strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容 并且可修改。)
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串 中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标 记。
如果字符串中不存在更多的标记,则返回 NULL 指针。
strtok库函数
int main()
{
//192.168.31.121
//192.168.31.121-strtok
//zpw@bitedu.tech
//zpw bitedu tech
char arr[]="zpw@bitedu.tech";
char*p="@.";
//会把@和.改成\0 然后从起始字符开始打印
char buf[1024]={0};
strcpy(buf,arr);
char* ret=NULL;
for(ret=strtok(arr,p);ret!=NULL;ret=strtok(NULL,p))//以后总传空指针
{
printf("%s\n",ret);
}
//会记住上次改成\0的位置 下次从后面开始 类似于static
//切割buf中的字符串 切割不了会返回空指针
return 0;
}
zpw
bitedu
tech
10.strerror
char * strerror ( int errnum );
参数:
errnum -- 错误号,通常是 errno
返回值:
该函数返回一个指向错误字符串的指针,该错误字符串描述了错误 errnum。
#include <errno.h>//必须包含的头文件\
sterror库函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<errno.h>
int main()
{
//错误码-错误信息
//0 -No error
//1 -Operation not permitted
//2 -No such file or directory
//3 4 5等也有
//errno是一个全局的错误码的变量
//当C语言的库函数在执行过程中 发生了错误 就会把对应的错误码 赋值到errno中
//char*str=strerror(errno);//把错误码翻译成错误信息
//printf("%s\n",str);
//打开文件
FILE* pf=fopen("test.txt","r");
if(pf==NULL)
{
printf("%s\n",strerror(errno));
}
else
{
printf("open file success\n");
}
return 0;
}
No such file or directory
11.字符分类函数
#include<ctype.h>头文件
#include<stdio.h>
#include<ctype.h>
int main()
{
//char ch='w';
//int ret=islower(ch);//判断是不是小写 小写就返回非0 大写就返回0
//printf("%d\n",ret);
//char ch=tolower('Q');//大写变小写 如果小写的话就不变
//char ch=toupper('q');//小写变大写
//putchar(ch);
//大写全部变小写
char arr[]="I Am A Student";
int i=0;
while(arr[i])
{
if(isupper(arr[i]))
{
arr[i]=tolower(arr[i]);
}
i++;
}
printf("%s\n",arr);
return 0;
}
i am a student
12.memcpy
void * memcpy ( void * destination, const void * source, size_t num );
参数:
str1 -- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
str2 -- 指向要复制的数据源,类型强制转换为 void* 指针。
num -- 要被复制的字节数。
返回值:
该函数返回一个指向目标存储区 str1 的指针。
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到 '\0' 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。(某些编译器下可以解决重叠问题)
memcpy库函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
struct S
{
char namr[20];
int age;
};
int main()
{
int arr1[]={1,2,3,4,5};
int arr2[5]={0};
struct S arr3[]={{"张三",20},{"李四",30}};
struct S arr4[3]={0};
memcpy(arr2,arr1,sizeof(arr1));//整型数组的copy
memcpy(arr4,arr3,sizeof(arr3));//结构体的copy
int i=0;
for(i=0;i<5;i++)
printf("%d ",arr2[i]);
for(i=0;i<3;i++)
printf("\n%s",arr4[i]);
}
1 2 3 4 5
张三
李四
memcpy自定义函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
struct S
{
char namr[20];
int age;
};
void* my_memcpy(void* dest,const void* src,size_t num)
{
void* ret=dest;
assert(dest!=NULL);
assert(src!=NULL);
while(num--)
{
*(char*)dest=*(char*)src;
(char*)dest++;//强转之后再加加 前置加加会报错 可能是编译器原因
(char*)src++;//++优先级低于*
}
return ret;//返回起始地址
}
int main()
{
int arr1[]={1,2,3,4,5};
int arr2[5]={0};
struct S arr3[]={{"张三",20},{"李四",30}};
struct S arr4[3]={0};
my_memcpy(arr4,arr3,sizeof(arr3));
my_memcpy(arr2,arr1,sizeof(arr1));
int i=0;
for(i=0;i<5;i++)
printf("%d ",arr2[i]);
for(i=0;i<3;i++)
printf("\n%s",arr4[i]);
return 0;
}
1 2 3 4 5
张三
李四
C语言标准要求:
memcpy 只要处理不重叠的内容copy就可以(库里的memcpy可解决重叠问题 自定义没有实现)
memmove 处理重叠内存的copy 遇到重叠情况可用memmove
13.memmove
void * memmove ( void * destination, const void * source, size_t num );
参数:
str1 -- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
str2 -- 指向要复制的数据源,类型强制转换为 void* 指针。
num -- 要被复制的字节数。
返回值:
该函数返回一个指向目标存储区 str1 的指针。
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
memmove库函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
int main()
{
//1 2 3 4 5拷贝到3 4 5 6 7
int arr[]={1,2,3,4,5,6,7,8,9,10};
//my_memcpy(arr+2,arr,20);//源头和目的地在同一空间 会重叠 copy不成功
//memcpy(arr+2,arr,20);//库里面可以实现 库里面memcpy和memmove是一样的效果
memmove(arr+2,arr,20);//处理重叠状态
int i=0;
for(i=0;i<10;i++)
{
printf("%d ",arr[i]);
}
return 0;
}
1 2 1 2 3 4 5 8 9 10
memmove自定义函数
#include<stdio.h>
#include<assert.h>
#include<string.h>
void* my_memmove(void* dest,void* src,size_t count)
{
void* ret=dest;
assert(dest!=NULL);
assert(src!=NULL);
if(dest<src)
{
//前->后
while(count--)
{
*(char*)dest=*(char*)src;
(char*)dest++;
(char*)src++;
}
}
else
{
//后->前
while(count--)
{
*((char*)dest+count)=*((char*)src+count);
}
return ret;
}
//或者
/*if(dest<src||dest>(char*)src+count)
{
//前-后
}
else
{
//后-前
} */
}
//头文件string.h
int main()
{
//1 2 3 4 5拷贝到3 4 5 6 7
int arr[]={1,2,3,4,5,6,7,8,9,10};
//my_memcpy(arr+2,arr,20);//源头和目的地在同一空间 会重叠 copy不成功
//memcpy(arr+2,arr,20);//库里面可以实现 库里面memcpy和memmove是一样的效果
//memmove(arr+2,arr,20);//处理重叠状态
my_memmove(arr+2,arr,20);
int i=0;
for(i=0;i<10;i++)
{
printf("%d ",arr[i]);
}
return 0;
}
1 2 1 2 3 4 5 8 9 10
14.memcmp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
参数:
str1 -- 指向内存块的指针。
str2 -- 指向内存块的指针。
num-- 要被比较的字节数。
返回值:
如果返回值 < 0,则表示 str1 小于 str2。
如果返回值 > 0,则表示 str1 大于 str2。
如果返回值 = 0,则表示 str1 等于 str2。
memcmp库函数
#include<stdio.h>
#include<string.h>
int main()
{
int arr1[]={1,2,3,4,5};
int arr2[]={1,2,5,4,3};
int ret=memcmp(arr1,arr2,9);
printf("%d\n",ret);
if(ret>0)
{
printf("arr1>arr2\n");
}
else if(ret<0)
{
printf("arr1<arr2\n");
}
else
{
printf("arr1=arr2\n");
}
return 0;
}
arr1<arr2
15.memset
void* memset(void *str,int c,size_t n)
参数:
str -- 指向要填充的内存块。
c -- 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
n -- 要被设置为该值的字符数。
返回值:
该值返回一个指向存储区 str 的指针。
memset库函数
int main()
{
char str[50];
strcpy(str,"This is string.h library function");
puts(str);
memset(str,'$',7);
puts(str)
//int arr[10]={0};
//最后一个参数是10个字节的意思
//改成01 01 01 01 01 01 01 01 01 01 00 00 00 00
//相当于结果是01 01 01 01十六进制变为十进制
//错误写法
return 0;
}
This is string.h library function
$$$$$$$ string.h library function
#10库函数#完