目录
一、局限性(特指用到字符串的函数)
1.strlen()函数
- //strlen()函数的使用
- //字符串中以'\0'为结束标志,其返回值数字个数不包括'\0'
- //参数指向的字符串必须要有'\0'作为结束
- //注意函数的返回值为size_t,是无符号(易错)
- //my_strlen()实现 请回看计算字符串不同方式
#include <stdio.h>
#include <string.h>
//判断以下输出?
//答:你没看错,就是输出为hehe
//应为strlen的返回值是 size_t == unsigned int
//即 3 - 6 = 3
//为正数即打印 hehe,而不是haha
int main()
{
if((strlen("abc") - strlen("abcdef"))>0)
{
printf("hehe");
}
else
{
printf("haha");
}
}
2.strcpy()函数
- 必须保证数组中含有'\0'
- char arr2[] = {'b','c'};错误,里边必须要以'\0'结束
- char*arr = "abcdef";错误,这是一个常量字符串,会发生出错
- 目标空间必须要足够大,保证能存放源字符串
- my_strcpy()函数实现,如下
char* my_strcpy(char *arr, char *arr1)
{
assert(arr && arr1);
char* ret = arr;
// 1.找到arr的'\0'位置
while(*arr != '\0')
{
arr++;
}
// 2.在后边插入arr1的值
while(*arr1 != '\0')
{
*arr = *arr1;
arr++;
arr1++;
}
*arr = *arr1;
// 2.第二种写法while(*arr++ = *arr1++);
// 第一步 *arr = *arr1 将解引用,将arr1的值赋值给arr,如果即把' '替换'\0'为真
// 第二步 arr++,arr1++,即arr又指向'\0'的位置,然后arr1指向'w'位置,循环 第一二两步
// 最后,将arr1中的'\0'赋值给arr中,为'\0'的ASCII码值为0,循环结束
// 3.返回值
return ret;
}
3.strcat()函数
- 源字符串必须以'\0'结束
- 目标空间必须有足够的大,能容纳下源字符串的内容
- 目标空间必须可修改
- 实现my_strcat
#include <stdio.h>
#include <assert.h>
#include <string.h>
char* my_strcat(char *arr, char *arr1);
int main()
{
char arr[] = "hello";
char arr1[] = " world";
printf("%s",my_strcat(arr,arr1));
return 0;
}
char* my_strcat(char *arr, char *arr1)
{
assert(arr && arr1);
char* ret = arr;
// 1.找到arr的'\0'位置
while(*arr != '\0')
{
arr++;
}
// 2.在后边插入arr1的值
while(*arr1 != '\0')
{
*arr = *arr1;
arr++;
arr1++;
}
*arr = *arr1;
// 2.第二种写法while(*arr++ = *arr1++);
// 第一步 *arr = *arr1 将解引用,将arr1的值赋值给arr,如果即把' '替换'\0'为真
// 第二步 arr++,arr1++,即arr又指向'\0'的位置,然后arr1指向'w'位置,循环 第一二两步
// 最后,将arr1中的'\0'赋值给arr中,为'\0'的ASCII码值为0,循环结束
// 3.返回值
return ret;
}
4.strcmp()函数
- strcmp(string1,string2),比较两个字符串的中的元素一一对比
- 比如 abc 与 fcd a<f 返回<0的数字...
- 比如 abc 与 acd a<a 返回=0的数字...
- 比如 fbc 与 acd f>a 返回>0的数字...
- my_strcmp()函数实现
#include <stdio.h>
#include <assert.h>
int my_strcmp(const char *arr1,const char *arr2);
int main()
{
char arr1[10] = {0};
char arr2[10] = {0};
scanf("%s",arr1);
scanf("%s",arr2);
int ret = my_strcmp(arr1,arr2);
if(ret == 0)
{
printf("equal\n");
}
else if(ret == 1)
{
printf("arr1>arr2\n");
}else{
printf("arr2>arr1\n");
}
}
int my_strcmp(const char *arr1,const char *arr2) {
assert(arr1 && arr2);
// 1.判断对应字符是否相同,一一比对
while(*arr1 == *arr2)
{
// 1.1避免越界访问,设置条件
if(*arr1 == '\0')
{
return 0;
}
arr1++;
arr2++;
}
// 2.当比对的 一元素 与 零一元素 不同时,看ASCII码表
if(*arr1 > *arr2)
{
return 1;
} else{
return -1;
}
}
5.strncpy()函数
//strncpy()函数 //strncp(*destination,*src,size_t); //当src的元素个数,没有size_t大时,补个'\0' int main() { char arr1[5] = "abc"; char arr2[] = "ge"; strncpy(arr1,arr2,4); printf("%s",arr1); }
6.strncat()函数
#include <stdio.h> #include <string.h> //strncat()函数 //strnat(*destination,*src,size_t); //当size_t > *src 长度时,将*src放入到*destination后补一个'\0' //当size_t < *src 长度时,将*src制定个数size_t个元素放入到*destination后补一个'\0' int main() { char arr[30] = "hello\0xxxxxxxxxxx"; char arr2[] = " world"; strncat(arr,arr2,8); printf("%s",arr); return 0; }
7.strncmp()函数
//strncmp()函数 //int strncmp(const char* string1,const char* string2,size_t count); int main() { // 常量字符串不能被修改,用const进行修饰 const char* p1 = "abcdef"; char* p2 = "abceff"; int ret = strcmp(p1,p2); printf("%d\n",ret);//输出小于0的数,不一定是-1 printf("%d",strncmp(p1,p2,3));//输出为 0 ,比较三个字符 return 0; }
8.my_strstr()函数实现
#include <stdio.h> #include <string.h> #include <assert.h> //strstr查找字符串 char* my_strstr(const char* des,const char* src) { assert(des && src); char* s1 = des; char* s2 = src; //记录每次匹配的起始位置 char* cur = des; //判断子串是否为空,为空直接返回主串地址 if(*src == '\0') { return des; } //进行注意匹配,匹配条件:*cur!=NULL while(*cur) { // 1.当匹配失败时,将cur的位置进行更新 s1 = cur; //赋初值,字串要回到起始位置 s2 = src; // 2.进行循环查找,比对主子串,相同主子两串+1,向下匹配 while((*s1 != '\0') && (*s2 != '\0') && (*s1 == *s2)) { s1++; s2++; } // 3.当匹配到子串为'\0',即找到了子串的全部,返回主串的起始地址cur if(*s2 == '\0') { return cur; } // 4.没有遇到子串的字符时,主串的起始位置,向下查找 cur++; } // 5.没有找到与字串相符合的主串,返回空 return NULL; } int main() { char* p1 = "abcdefghij"; char* p2 = "def"; //库函数 char* ret = strstr(p1,p2); //实现自己的my_strstr char* ret1 = my_strstr(p1,p2); printf("%s\n",ret); printf("%s",ret1); return 0; }
9.strtok()函数
#include <stdio.h> #include <string.h> //strtok()函数 // char* strtok(char* str,const char* sep); // sep代表标记(特殊符号) // 1.第一个参数制定一个字符串,包含0或多个由sep字符串中一个或者多个分隔符的标记 // 比如:110@cn.com 字符串为110@cn.com sep为 '@' '.' // 2.strtok函数找到str中的下一个标记,并将其用'\0'结尾,返回一个指向这个标记的指针 // [注]:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时变量的内容并且可修改 // 比如:110@cn.com 找到'@'后,将字符串变为110\0cn.com,返回1的地址。再调用时,从cn.com开始查找下一个sep // 3.当strtok函数第一个参数不为NULL,函数找到str中的第一个标记,strtok函数将保存在他字符串中的位置 // 比如:110@cn.com 从110'\0'找到后,将'\0'替换为NULL // 4.当strtok函数第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记,循环1,2,3步 // 5.如果字符串中不存在更多的标记,返回NULL,即将主串全部找完 //作用:比如:192.168.1.1 -> 返回 192 168 1 1 int main() { //1.定义字符数数组 //目标串 char arr[] = "193.268.3.4"; //切分 char* p = "."; //2.将建临时数组,存储源字符串 //由于strtok()函数会切分源字符串,所以要用重新定义一个临时字符数组接收源字符串的赋值 char buf[1024] ={0}; //做拼接 strcpy(buf,arr); //3.切分buf中的字符串 char* ret = NULL; // 初始化 第1,2,3步 第四步 for (ret = strtok(buf,p);ret != NULL;ret = strtok(NULL,p)) { printf("%s ",ret); } return 0; }
10.strerror()函数
//char* strerror (int errnum) //作用:返回错误码,所对应的错误信息 int main() { FILE *pf = fopen("test.txt","r"); if(pf == NULL) { printf("%s",strerror(errno)); } else { printf("open file success"); } return 0; }
11.总结上述
strcpy、strcat、strcmp、strncpy、strncat、strncmp
操作对象是:字符串,'\0',不能拷贝整型数组、浮点型数组、结构体数组
二、解决局限性
1.memcpy()函数
//memcpy()函数 //memcpy(void*des,void*src,size_t num) 目的地,复制源,操作字节个数(sizeof计算) 【注意】C语言规定必须是两个不同数组 //可以拷贝整型数组、浮点型数组、结构体数组、字符串 //模拟实现 #include <stdio.h> #include <string.h> #include <assert.h> struct Stu{ char name[20]; int age; }; void* my_memcpy(void* des,const void * src,size_t num) { //断言,检测数据是否合法 assert(des && src); // 4.返回首地址 void *ret; // 3.当指定元素个数遍历完 while (num--) { // 1.将src中元素放入des中 //注意类型转换 *(char *) des = *(char *) src; // 2.两个指针向后移 des = (char*)des + 1; src = (char*)src + 1; } return ret; } int main() { int arr1[] = {1,2,3,4,5}; int arr2[5] = {0}; int i = 0; // 1.memcpy(void* des,void* src,size_t num) 目的地,复制源,操作字节个数 memcpy(arr2,arr1, sizeof(arr1)); // 打印 for (i = 0 ;i < sizeof(arr2)/ sizeof(arr2[0]);i++) { printf("%d ",arr2[i]); } // 2.模拟实现my_memcpy(),实现数组 struct Stu stu1[] ={{"huang",15},{"lan",10}}; struct Stu stu2[sizeof(stu1)/ sizeof(stu1[0])] ={0}; my_memcpy(stu2,stu1, sizeof(stu2)); // 打印 for (i = 0 ;i < sizeof(stu2)/ sizeof(stu2[0]);i++) { printf("\n%s %d ",stu2[i].name,stu2[i].age); } }
2.memmove()函数
// memmove()函数 // memcmp(void* des,const void* src,size_t num) 目的地,复制源,操作字节个数(sizeof计算) 【注意】可以是同一个数组,重叠内存拷贝 // 模拟实现my_memmove #include <stdio.h> #include <string.h> #include <assert.h> void* my_mommove(void *des, const void *src, size_t count); int main() { int arr[] = {1,2,3,4,5,6,7,8,9,10}; int arr2[] = {10,20,30,40,50,60,70,80,90,100}; // 1.简单应用 memmove(arr+2,arr,20); int i = 0; // 打印 for (i = 0 ;i < sizeof(arr)/ sizeof(arr[0]);i++) { printf("%d ",arr[i]); } printf("\n=================\n"); // 2.模拟实现 //分析:先写逻辑,重叠时,des<src从前往后拷贝;反之,从后向前拷贝。不重叠时,都可。 my_mommove(arr2+2,arr2,20); //打印 for (i = 0 ;i < sizeof(arr2)/ sizeof(arr2[0]);i++) { printf("%d ",arr2[i]); } } void* my_mommove(void *des, const void* src, size_t count) { assert(des && src); // 3.我们要从头打印串,所以要将des的首地址返回,用临时变量存储首地址,确保能全部打印 void* ret = des; // 1.从前往后拷贝 即des < src 画图可知 if(des < src) { //循环条件用替换字节的个数 while (count--) { *(char *) des = *(char *) src; des = (char *) des + 1; src = (char *) src + 1; } } // 2.从后往前拷贝 即des >= src包含不重叠情况 else { while(count--) { //将两个串从尾部开始拷贝,'+count'代表尾部 //表示将从src后部对应des后部向前拷贝 *((char*)des + count) = *((char*)src + count); } } return ret; }
3.memcmp()函数
//memcmp()函数 #include <stdio.h> #include <memory.h> //memcmp(数组一,数组二,比较字节个数) //相同返回0 //数组一 < 数组二 返回小于0的数值 //数组一 > 数组二 返回大于0的数值 int main() { int arr1[] = {1,2,3,4,5}; int arr2[] = {1,2,5,4,3}; int ret = memcmp(arr1,arr2,9); printf("%d",ret);//结果为-1 return 0; }
4.memset()函数
//memset()函数 - 内存设置 #include <stdio.h> #include <memory.h> //memset(空间地址,字符,字节个数) int main() { char arr[5] = ""; int arr1[5] = {0}; int i = 0; // 1.放入字符 memset(arr,'#',5); for (i = 0;i < 5;i++) { printf("%c ",arr[i]); } printf("\n=====\n"); // 2.放入数字 memset(arr1,1,20); for (i = 0;i < 5;i++) { printf("%d ",arr1[i]); } //输出 16843009 16843009 16843009 16843009 16843009 // 原因:内存中存储格式为 【 01 01 01 01 】【 01 01 01 01 】【 01 01 01 01 】【 01 01 01 01 】【 01 01 01 01 】 // 转为十进制 即为 16843009 16843009 16843009 16843009 16843009 return 0; }
三.好用的库函数
// 好用的函数 函数 符合参条件返回为真(是真就返回比0的数,不是就返回0) //iscntrl 任何控制字符 //isdigit 十进制数字0-9 //isxdigit 十六进制数字,包括所有十进制数字,小写字母a-f,大写字符A-F //islower 小写字母a-z //isupper 大写字母A-Z //isalpha 字母a-z或A-Z //isalnum 字母或者数字,a-z,A-Z,0-9 //ispunct 标点符号,热河不属于数字或者字母的图形字符(可打印) //isprint 任何可打印字符包括图形字符和空白字符 //tolower 大写转小写 //toupper 小写转大写 #include <stdio.h> #include <ctype.h> //运用一下库函数 int main() { char arr[] ="I am A Student"; int i = 0; while (arr[i]) { if(isupper(arr[i])) arr[i] = tolower(arr[i]); i++; } printf("%s",arr); }