一、字符串操作函数
1.strlen函数
(1)'\0'不算进字符串长度
(2)字符串必须有'\0’结尾
(3)函数返回类型是size_t,无符号类型
int main()
{
//char arr[] = "abc";
char arr[] = { 'a','b','c' };
int len = strlen(arr);//随机值
printf("%d\n", len);
return 0;
}
1.计数器版本
int my_strlen1(const char* str)
{
assert(str);
int count = 0;
while (*str)
{
count++;
str++;
}
return count;
}
2.递归版本
int my_strlen2(const char* str)
{
if (*str)
{
return 1 + my_strlen2(str + 1);
}
return 0;
}
3.指针-指针版本
int my_strlen3(const char* str)
{
const char* find = str;
while (*find)
find++;
return find - str;
}
int main()
{
char arr[] = "abcdef";
printf("%d\n", my_strlen1(arr));
printf("%d\n", my_strlen2(arr));
printf("%d\n", my_strlen3(arr));
}
int main()
{
//无符号数 - 无符号数 = 无符号数
//unsigned int 3 - unsigned int 6 = (unsigned int)-3
//10000000000000000000000000000011(原)
//11111111111111111111111111111100(反)
//11111111111111111111111111111101(补)
//4294967293(很大的正数,一定 > 0)
if (strlen("abc") - strlen("abcdef") > 0)
{
printf(">\n");
}
else
{
printf("<=\n");
}
return 0;
}
2.strcpy函数
(1)拷贝时直接将源字符串的'\0'也拷贝进了目标空间
(2)确保源字符串添加了'\0'结束
(3)确保目标空间有足够的空间存储源字符串
(4)目标空间必须可变
int main()
{
char arr[10] = { 0 };
arr = "hello"; //err! arr是首元素地址,应把hello放进arr所指向的空间而不是arr这个编号本身
strcpy(arr, "hello"); //实际传参的是"hello"的首元素h地址
char arr2[] = { 'a','b','c' }; //err! '\0'是拷贝结束的标志
strcpy(arr, arr2);
char arr[5] = { 0 };
const char* p = "abcdef";
strcpy(arr, p); //err,超过了dest的个数,越界访问
char *str = "############"; //目标空间不可变
char* p = "abcdef";
strcpy(str, p);
return 0;
}
void my_strcpy(char* str1, const char* str2)
{
while (*str2)
{
*str1++ = *str2++;
}
*str1 = *str2;
}
int main()
{
char arr[20] = { 0 };
const char* arr2 = "abcdef";
my_strcpy(arr, arr2);
puts(arr);
}
3.strcat函数 - 字符串追加(连接)
(1)源字符串必须以\0结束
(2)目标空间必须足够大,能容纳下源字符串的内容
(3)目标空间必须可修改
int main()
{
char arr[20] = "hello \0############";
//strcat(arr, "world");
//my_strcat(arr, "world");
//hello \0############\0
// world\0
//hello world\0#######\0
//printf("%s\n", arr);
printf("%s\n", my_strcat(arr, "world"));
//没有打印#,说明字符串里\0也被追加到了第一个\0后面
return 0;
}
int main()
{
char arr[20] = "abcd";
strcat(arr, arr); //err!
//abc\0
//abca
//abcab
//abcabcabc.....找不到\0
printf("%s\n", arr);
return 0;
}
char* my_strcat(char* dest, const char* src)
{
assert(dest && src);
char* cp_dest = dest;
//1.找到目标字符串中的\0
while (*cp_dest)
{
cp_dest++;
}
//2.追加源字符串,包括'\0'
while (*cp_dest++ = *src++)
{
;
}
return dest; //返回目标空间的起始地址
}
4.strcmp函数
int main()
{
//char p[] = "abcccc";
char q[] = "abcdef";
//if (p > q) //0x00AFF834 0x00AFF824
// printf(">\n");
//else
// printf("<\n");
int ret = strcmp(q, "aaa");
printf("%d\n", ret);
return 0;
}
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2 && *str1)
{
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
const char* p = "abcdef";
const char* q = "abcccc";
//int ret = strcmp(p, q);
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\n");
}
strcpy - strncpy
strcat - strncat
strcmp - strncmp
长度不受限制的字符串函数 长度受限制的字符串函数
strncpy函数 - 长度受限制
char* my_strncpy(char* str1, const char* str2, size_t count)
{
char* start = str1;
while ((*str1 = *str2) && count)
{
str1++;
str2++;
count--;
}
if (count)
while(count--)
{
*str1++ = '\0';
}
return start;
}
int main()
{
char arr1[20] = "abcdefghi";
char arr2[] = "qwer";
//strncpy(arr1, arr2, 2);
//printf("%s\n", arr1); //qwcdefghi
//strncpy(arr1, arr2, 6); //如果拷贝的个数超过了arr2的长度,则补'\0'
my_strncpy(arr1, arr2, 6);
printf("%s\n", arr1); //qwcdefghi
return 0;
}
strncat - 长度受限制
char* my_strncat(char* str1, char* str2, size_t count)
{
char* start = str1;
while (*str1++)
;
str1--;
while (count && (*str1 = *str2))
{
str1++;
str2++;
count--;
}
if (count)
{
while (count--)
if ((*str1++ = *str2++) == '\0')
return start;
}
*str1 = '\0';
return start;
}
int main()
{
char arr1[30] = "hello \0####################";
// world\0 (追加5个)
// hello world\0###############
char arr2[] = "worldlife";
//strncat(arr1, arr2, 15); //连接arr2的k个字符到arr1之后,在arr1添加\0
my_strncat(arr1, arr2, 15);
printf("%s\n", arr1);
}
strncmp - 限制长度
int my_strncmp(const char* str1,const char* str2, size_t count)
{
while (*str1 == *str2 && *str1 && --count)
{
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
const char* p = "abcdef";
const char* q = "abcqwert";
//int ret = strcmp(p, q);
//int ret = strncmp(p, q, 3);
int ret = my_strncmp(p, q, 3);
printf("%d\n", ret);
}
5.strstr函数 - 在一个字符串中找另一个字符串出现的位置
int main()
{
char arr1[] = "abcdefabcdef";
char arr2[] = "bcd";
//在arr1中查找是否包含arr2字符串,如果arr2是arr1子串则返回arr2第一次出现的位置,如果找不到则返回空指针
char* ret = strstr(arr1, arr2);
if (ret)
{
printf("找到了:%s\n",ret);
}
else
{
printf("没找到\n");
}
return 0;
}
char* my_strstr(char* str1, const char* str2)
{
assert(str1 && str2);
char* cp_str1 = NULL;
const char* cp_str2 = NULL;
while (*str1)
{
cp_str1 = str1;
cp_str2 = str2;
while (*cp_str1 == *cp_str2 && !*cp_str2)
{
cp_str1++;
cp_str2++;
}
if (*cp_str2)
return str1;
str1++;
}
//int len = strlen(str2);
//while (*str1)
//{
// if (*str1 == *str2)
// {
// if (strncmp(str1, str2, len)==0)
// {
// return str1;
// }
// }
// str1++;
//}
//return NULL;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abc";
//在arr1中查找是否包含arr2字符串,如果arr2是arr1子串则返回arr2第一次出现的位置,如果找不到则返回空指针
char* ret = my_strstr(arr1, arr2);
if (ret)
{
printf("找到了:%s\n", ret);
}
else
{
printf("没找到\n");
}
return 0;
}
6.strtok函数 - 字符串切割
zpw@biteedu.cn
分隔符:@.
zpw
bitedu
tech
192.168.3.122
192
168
3
122
char* strtok(char* str , const char* sep)
sep参数是个字符串,用作分隔符的字符集合
第一个参数指定一个字符串,它包含了0个或者多个sep字符串中的一个或多个分隔符分割的标记
1. strtok找到str中的下一个标记,并将其用'\0'结尾,返回一个指向这个标记的指针(返回的是查找的初始元素(第一个分隔符的下一个元素)的地址)
(strtok函数会改变被操作的字符串,所以在调用的时候最好传tmp数组做拷贝)
2. strtok的第一个参数不为NULL,函数将找到str中的第一个标记,strtok函数将保存它在字符串中的位置
strtok的第一个参数为NULL,函数将在同一个字符串被保存的位置开始,查找下一个标记
找不到则返回NULL
int main()
{
char arr[] = "Lucid Winter@163.com";
//拷贝str做切割
char tmp[30] = { 0 };
strcpy(tmp, arr);
const char* p = "@. ";
char* ret = NULL;
for (ret = strtok(tmp, p); ret ; ret = strtok(NULL,p))
{
printf("%s\n", ret);
}
return 0;
}
7.strerror函数 - 把错误码转换成错误信息,需要的时候自己%s形式打印
调用库函数失败的时候,都会设置错误码
strerror将错误码翻译成错误信息,以char*字符串形式的字符串打印出来
errno是全局的错误码,头文件<errno.h>
char* strerror(int errno);
#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));
FILE* pf = fopen("test.txt", "r");
if (pf == NULL) //如果调用(打开文件)失败,返回空指针,自动就把错误码放到全局变量errno里面
{
printf("%s", strerror(errno));
return 1;
}
//...
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
8.perror函数 - 直接打印错误信息 - print error
void perror(const char* str)
1.首先把错误码转换成错误信息
2.打印错误信息(包含自定义信息)
int main()
{
FILE* pf = fopen("testing.txt", "r");
if (pf == NULL)
{
perror("fopen is error"); //fopen:No such file or directory
//把你编写的自定义信息打印之后打印':',再打印错误信息
return 1;
}
return 0;
}
二、字符操作函数
1.字符分类函数
如果符合条件返回非0的值,如果不符合条件则返回0
iscntrl - 任何控制字符
isspace - 空白字符:空格'',换页'\f',换行'\n',回车'\r',制表符'\t'或者垂直制表符'\v'
isdigit - 十进制数字0-9
isxdigit - 十六进制数字,包括0-9,a-f,A-F
islower - 小写字母a-z
isupper - 大写字母A-Z
isalpha - 字母a-z或A-Z
isalnum - 字母或者数字,a-z,A-Z,0-9
ispunct - 标点符号,任何不属于数字或者字母的图形字符
isgragh - 任何图形字符
isprint - 任何可打印字符,包含图形字符和空白字符
int main()
{
//char ch = '2';
//int ret = isdigit(ch); //如果是数字字符返回非0的值,如果不是数字字符,则返回0
char ch = 'A';
int ret = islower(ch);
printf("%d\n",ret);
return 0;
}
2.字符转换函数
int main()
{
char arr[20] = { 0 };
fgets(arr, 20, stdin);
char* p = arr;
while (*p)
{
if (isupper(*p))
{
*p = tolower(*p);
}
putchar(*p++);
}
return 0;
}
三、内存函数
1.memcpy() - 内存拷贝
void* memcpy(void* destination , const void* source, size_t num);
num是要拷贝的字节数
memcpy - 只要实现了不重叠拷贝就行了,而VS中的实现既可以拷贝不重叠,也可以拷贝重叠内存
void* my_memcpy(void* dest, const void* src, size_t num)
{
assert(dest && src);
char* cp_dest = (char*)dest;
char* cp_src = (char*)src;
while (num--)
{
*cp_dest++ = *cp_src++;
//*(char*)dest++ = *(char*)src++; //错误!char*强制类型转换是一个状态,后置++已经没有了强制类型转换这个状态
}
return dest;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
//char* strcpy(char* dest,const char* src); //数组类型不同而且\0的值是整型0会导致拷贝错误,无法拷贝整型!
//memcpy(arr2, arr1, sizeof(int) * 5);
int n = 0;
scanf("%d", &n);
//my_memcpy(arr2, arr1, sizeof(int) * n);
//my_memcpy(arr1+2, arr1, sizeof(int) * n); - 12121218910,错误
int i = 0;
for (i = 0; i < sizeof(arr1)/sizeof(arr1[0]); i++)
{
printf("%-2d ", arr1[i]);
}
printf("\n");
for (i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
{
printf("%-2d ", arr2[i]);
}
return 0;
}
2.memmove() - 处理内存重叠的情况
void* memmove(void* dest, const void* src, size_t num);
void* my_memmove(void* dest, const void* src, size_t num)
{
size_t cp_num = num;
char* cp_src = (char*)src;
char* cp_dest = (char*)dest;
char* p = (char*)malloc(sizeof(char) * cp_num);
char* rec = p;
char* free_p = p;
while (cp_num--)
{
*p++ = *cp_src++;
}
while (num--)
{
*cp_dest++ = *rec++;
}
free(free_p);
return dest;
}
void* my_memmove(void* dest, const void* src, size_t num)
{
char* cp_dest_last = (char*)dest + num;
char* cp_src_last = (char*)src + num;
char* cp_dest_first = (char*)dest;
char* cp_src_first = (char*)src;
while (num-- && dest<(char*)src+num-1)
{
*(cp_dest_last--) = *(cp_src_last--);
}
while (num--)
{
*(cp_dest_first++) = *(cp_src_first++);
}
return dest;
}
void* my_memmove(void* dest, const void* src, size_t num)
{
assert(dest&&src);
char* cp_dest_first = (char*)dest;
char* cp_src_first = (char*)src;
//dest落在src的整个范围左侧时,从前向后
//dest落在src的整个范围内时,从后向前
//dest落在src的整个范围右侧时,无所谓,假设从后向前
//综上,dest<src,从前向后 ; dest>=src,从后向前
if (dest < src)
{
//前->后
while (num--)
{
*cp_dest_first++ = *cp_src_first++;
}
}
else
{
//后->前
while (num--)
{
*(cp_dest_first+num) = *(cp_src_first+num);
}
}
return dest;
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
//my_memmove(arr1, arr1+2, sizeof(int) * 5);
memcpy(arr1+2, arr1, sizeof(int) * 5);
return 0;
}
3.memcmp - 内存比较
int memcmp(const void* ptr1, void* ptr2, size_t num)
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
while(*(char*)ptr1==*(char*)ptr2 && num--)
{
;
}
return *(char*)ptr1 - *(char*)ptr2;
}
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);
}
4.memset - 内存设置
void* memset(void* ptr, int value, size_t num);
void* my_memset(void* ptr, int value, size_t num)
{
char* cp_ptr = (char*)ptr;
while (num--)
{
*cp_ptr++ = value;
}
return ptr;
}
int main()
{
int arr[10] = { 0 };
memset(arr, 1, 20); //以字节为单位设置内存,因此监视不方便看(一个int为4个字节)
//如果要以元素为单位进行memset,只能对字符数组进行
char ch[10] = { 0 };
memset(ch, 'a', 9);
return 0;
}