绪论
书接上回,通过进阶指针你已经了解到了更多种指针类型,他们的用法及使用之处相当的关阔需要不断的积累经验来使用,这里我毛遂自荐一下我的指针练习希望对你有帮助,本章是一些关于字符串的函数介绍和自己实现,总体来说学会了这些函数可以对你在字符串类型的编程有很大的意义。
所以安全带系好,发车啦(建议电脑观看)。
附:红色,部分为重点部分;蓝颜色为需要记忆的部分(不是死记硬背哈,多敲);黑色加粗或者其余颜色为次重点;黑色为描述需要
思维导图:
要XMind思维导图的话可以私信哈
目录
1.函数介绍
1.1strlen
1.2strcpy
1.3strcat
1.4strcmp
1.5 strncpy
1.6strncat
1.7strncmp
1.8strstr
1.8strtok
1.9strerror
1.10字符分类函数
1.11memcpy
1.12memmove
1.13memcmp
1.14memset
1.函数介绍
下面将介绍到如下库函数:
求字符串长度型:
strlen
字符串函数型:
strcpy : copy :拷贝型
strcat :catch:追加型
strcmp :compare:比较型
strncpy : 拷贝型 加num确定了拷贝的个数
strncat:同上确定了追加的个数
strncmp:同理
字符串查找型:
strstr :在str(前)字符串中查是否有str(后)
strtok:在str中找分隔符(token)
返回错误型:
strerror
内存函数型(与字符串功能类似):
memcpy
memmove
memset
memcmp
1.1strlen
知识点:
size_t strlen (const char * string)
这个函数是求字符串长度的,从所传递进来的地址开始以char * 的步长往后找 '\0'
最终返回无符号的\0前的共有的元素个数
细节(注意点):
因为strlen以'\0'为结束标志,所以在其算的字符串中必须得有'\0',否则将会算出一个随机值
练习:
char arr[] = "abce";
int ret = strlen(arr);
printf("%d\n",ret);//4
模拟实现strlen
1.2strcpy
知识点:
char * strcpy(char * destination , const char * source )
将source处的字符串拷贝到destination处的空间内
返回des的起始地址
细节:
- source内必须有\0来结束拷贝
- destination的空间必须要大于等于source拷贝过来所需的大小
- 在拷贝时source内的\0也会被拷贝过来
- destination处的空间必须是可修改的
练习:
char arr1[] = "xxxxxxxxxxxxxxxx";
char arr2[] = "abcdef";
printf("%s",strcpy(arr1,arr2));//strcpy返回的是arr1首元素的地址,所以最终将打印abcdef
//当如下时
char arr2[] = "ab\0cdef";
printf("%s",strcpy(arr1,arr2));//strcpy返回的是arr1首元素的地址,所以最终将打印ab \0看不到
模拟实现strcpy
1.3strcat
知识点:
char * strcat(char * destination , const char * source )
其用法和strcpy有点类似,是将source内的数据追加到destination后面去
返回des的起始地址
细节:
- source内必须有\0停止
- destination必须有足够的空间放
- destination内也必须有\0否则无法进行拷贝
- destination必须可以被修改
- 不能自己给自己追加(因为是从\0开始追加所以\0会别取代,这样就无法停止)
练习:
char arr1[] = "hello ";
char arr2[] = "world";
//char *arr2 = "world";
printf("%s",strcat(arr1,arr2));//最终打印hello world
//从\0处开始,如果arr1 he\0llo -> heworld
strcat的模拟实现
1.4strcmp
知识点:
int strcmp(const char * str1 , const char * str 2)
比较两个字符串的大小
返回值:
str1 > str2 返回大于0的数
1 < 2 返回小于0的数
1 = 2 返回0vs环境下1 > 2 返回 1 1 < 2 返回 -1 1=2 返回0
细节:
字符串的比较时是对应的一个个字符比较,并且比较的是对应的ASCII码值
练习:
strcmp的模拟实现
char arr1[] = "abcdef";
char arr2[] = "abq";
printf("%d",strcmp(arr1,arr2));//次处1 和 2 的前两个字符a b 的ASCII码相但是比到c 与 q 时
//c 的ASCII码值小于 q的... 所以最终 1 < 2 返回负数
对于以上的函数没有对字符的限制(只到\0才停止),所以和scanf一样并不太安全所以需要
#define _CRT_SECURE_NO_WARNINGS 1 来防止报错
以下是一些有字符个数限制的字符函数
1.5 strncpy
知识点:
char* strncpy(char * destination ,char * source,size_t num);
其用法和strcpy几乎一致只是要对拷贝的字符个数有明确限制
同样返回des的起始地址
细节:
将指定的source的字符个数拷贝到destination处,当所需拷贝的字符超过source时后面用\0替代继续拷贝
练习:
模拟实现strncpy
char * my_strncpy(char * des ,const char * sour ,size_t count)
{
assert(des && sour);
char * tmp = des;
while(count--)
{
if(*sour == '\0')
{
*des++ = '\0';
continue;
}
else
{
*des++ = *sour++;
}
}
}
//反之
char* my_strncpy(char* strDest, const char* strSource, size_t count)
{
assert(strDest && strSource);
char *ret = strDest;
while(count--)
{
*strDest = *strSource ;
if(*strSource != '\0')
{
strDest++;
strSource++;
}
}
return ret;
}
例子:
1.6strncat
知识点:
char * strncat(char * des , const char * sour ,size_t count)
同样用法相同,加上了限制的个数
同样返回des的起始地址
细节:
追加完后在最后补上一个\0
练习:
模拟实现strncat
char* my_strncat(char* des, const char* sour, size_t count)
{
assert(des && sour);
char* tmp = des;
while (*des)
{
des++;
}
while (count--)
{
if (*sour == '\0')
*des = '\0';
*des++ = *sour++;
}
return tmp;
}
例子:
1.7strncmp
知识点:
int strncmp(const char * str1 ,const char * str2 ,size_t count);
用法相同,限制了比较个数
返回值还是相同:
str1 > str2 返回大于0的数
1 < 2 返回小于0的数
1 = 2 返回0vs环境下1 > 2 返回 1 1 < 2 返回 -1 1=2 返回0
练习:
模拟实现
int my_strncmp(const char* string1, const char* string2,size_t count)
{
assert(string1 && string2);
while (*string1 == *string2 && *string1 != '\0')//找到不相等的字符
{
if (!--count)//后置--时无法会继续往下走而导致string1 2 指向改变
{
break;
}
string1++;
string2++;
}
if ((*string1 - *string2) == 0)
{
return 0;
}
else
{
return (*string1 - *string2) > 0 ? 1 : -1;
}
//vs环境下1大于2返回1 , 1<2 返回-1 1 = 2 返回 0
}
1.8strstr
知识点:
char *strstr( const char *string, const char *strCharSet );
在string字符串内寻找strcharset
返回strcharset首次出现的位置
细节:
寻找时:
1.如果存在:返回找到strcharset的第一个元素的地址
2.如果不存在:返回NULL
3.如果strcharset 为空则则直接返回string的地址
练习:
模拟实现strstr
1.8strtok
知识点:
用来分割字符串的函数,char *strtok( char *strToken, const char *strDelimit );
strToken给定的一个字符串,strDelimit 传进的分隔符组
在strToken内找strDelimit 来进行分隔
返回本次分隔好后的字符串的首元素的地址
细节:
如何使用strtok:
代码展示:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<string.h> int main() { char arr1[] = "ZhaoYKun@qq.com"; char arr2[]= "@."; //char arr2[] = {'@','.','\0'};//效果相同 printf("%s\n", strtok(arr1, arr2));//返回第一次分隔好的字符的首元素地址 printf("%s\n", strtok(NULL, arr2));//当用NULL时表示从分隔好了,继续从下一个开始 printf("%s\n", strtok(NULL, arr2));//同理 printf("%s\n", strtok(NULL, arr2));//当后面没有后返回NULL return 0; }
结果:
总结来说就是:
- 首先传进要分隔的字符串,和分隔符组进行第一次分隔
- 其次要再次进行分隔(第一次分隔将返回首元素地址,和记录分隔后剩的字符地址),当传进NULL和分隔符组时表示继续分隔
- 最后若没有字符了就会返回NULL
1.9strerror
知识点:
char * strerror(int error)
strerror是返回错误码所对应的错误消息的首元素地址
错误码是:1、2、3、4、5组成无法直接看出错误所以需要strerror来翻译翻译成错误消息
当返回了错误码所对应的错误信息的首元素地址后直接打印出错误信息字符串
细节:
C语言中会将错误码放在一个变量中,这个变量是:errno
而若你要使用errno这个变量就需要引头文件 #include<errno.h>
练习:
使用方法:
没有创建test.txt文件
所以最后报错为:原因:当fopen没有找到该文件就会将对应的错误码存在errno变量中
当有开文件(test.c)后就不会报错,
附:
strerror这个函数他会返回一个地址再通过这个地址来打印错误信息,稍微有点麻烦了,所以库函数里还有个可以自行打印错误信息的函数 (perror)
可以适当在perror内加上一些修饰词来修饰错误信息的如perror("error from");(即在对应错误信息前会打印你所自定义的信息 : )头文件:stdio.h
最终打印 error from : .....
==
1.10字符分类函数
知识点:
函数 int functio(int ) | 如果他的参数符合一下条件就返回真,否则返回0(假) |
iscntrl | 符合控制字符 |
isspace | 空白字符:空格' ' 、换页'\f'、换行'\n'、回车'\r'、制标符'\t'或者崔志垂直制表符'\v' |
isdigit | 十进制数字 |
isxdigit | 十六进制数字其中包括大小写字母a~f |
islower | 小写字母 |
isupper | 大写字母 |
isalpha | 大小写字母· |
isalnum | 数字和大小写字母 |
ispunct | 标点符号;任何不属于数字或字母的图形字符 |
isgraph | 任何图形字符 |
isprint | 任何可打印字符、包括图形字符和空白字符 |
知识点:
细节:
练习
;
练习:
附:
- 空白字符:' '空格符、 '\t'水平制表符、'\n' 换行符、'\v' 垂直制表符、'\f'换页符、'\r' 回车符
- 在ASCII码中0~31和127为33个 控制字符
- 图形字符:所有字符除了‘ ’空格
- 可打印字符:不包括控制字符的所有字符
- 控制字符:在ASCII码中0~31和127的共33个控制字符
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<ctype.h>
int main()
{
int i = 0;
char a[] = "abcde\nfg\nef";
//以下都是ture
//int iscntrl(int c);//传进字符的ASCII码值
while (!iscntrl(a[i]))//如果是控制字符返回非零的数,再!为假跳出循环
{
printf("%c", a[i++]);
}
printf("\n"); i++;
while (!isspace(a[i]))//从f开始//遇到空白字符就会返回非0的数,再同理...
{
printf("%c", a[i++]);
}
printf("\n");
if(isdigit('6')) //检查是不是字符数字0~9
printf("isdigit");
printf("\n");
if(isxdigit('f'))//十六进制0~f
printf("isxdigit");
printf("\n");
if (islower('z'))//为小写字母,返回非0的数
printf("islower");
printf("\n");
if (isupper('A'))//大写字母
printf("isupper");
printf("\n");
if (isalpha('A')&& isalpha('a'))//大小写都行
printf("isalpha");
printf("\n");
if (isalnum('3' ) && isalnum('a'))//数字和大小写字母
printf("isalnum");
printf("\n");
if (ispunct('@'))//除数字,字母的标点符号的图形字符
printf("ispunct");
printf("\n");
if (isgraph('@'))//除了空格的可打印出的字符
{
printf("isgraph");
}
printf("\n");
if (isprint('!'))//判断是不是可打印字符
{
printf("isgraph");
}
printf("\n");
return 0;
}
字符转换函数:
toupper
tolower
isuppuer
islower
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<ctype.h>
int main()
{
if(isupper('A'))
printf("A\n");
if (islower('a'))
printf("a\n");
printf("%c\n", toupper('a'));
printf("%c\n", tolower ('A'));
return 0;
}
在字符字符串中找字符
const char *strchr(const char * str, int character)
const char *strrchr(const char * str, int character)
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<string.h> int main() { char arr[] = "abcdeafg"; //printf("%s", strchr(arr, 'a'));//abcdeafg //找字符第一次的出现若存在返回第一次出现的地址,反之返回NULL printf("%s", strrchr(arr, 'a'));//afg //找字符最后一次出现若存在返回第出现的地址,反之返回NULL return 0; }
以上是一些针对字符串的函数,而对于其他类型的函数就需要另外的函数来其作用
以下是一些处理内存相关的函数
1.11memcpy
知识点:
void *memcpy(void *des , const void * sour size_t num )
其用法和strncpy是一样的中num表示byte所以若是拷贝一个整形那就需要4byte,其余同理、
返回des的地址
细节:
- 其中num的byte是自己定义的所以在使用的使用也要把握好所要拷贝类型所占的大小
- 在拷贝的过程中你必须保证有足够的空间来放
练习:
使用
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
int arr1[10] = { 0 };
memcpy(arr1, arr, 20);//拷贝5个int 4 * 5 = 20 byte
for(int i = 0; i<10 ; i++)
printf("%d ", arr1[i]);//0123400000
return 0;
}
模拟实现memcpy
1.12memmove
总体来说和memcpy几乎一样的用法但有些许不同:memcpy和memmove的区别
1.13memcmp
知识点:
int memcmp(const void * ptr1,const void * ptr2 , size_t num);
比较内存中的内容大小(步长char)
其返回比较其内存内容后的比较结果
若ptr1小于ptr2返回小于0的数(vs是-1)
1 > 2返回大于0的数(vs是1)
若相等返回0
细节:
具体使用如下:
int arr1[] = {1,4,7};
int arr2[]= {1,4,2};
int ret = memcmp(arr1,arr2,sizeof(arr1));
此时在内存arr1、arr2内容如下
arr1:01 00 00 00 04 00 00 00 07 00 00 00
arr2:01 00 00 00 04 00 00 00 02 00 00 00;
memcmp会根据你给的num(单位byte来比较逐字节的比较 01 和 01 比较 当比较到不同时就会返回一个值)
使用最终因为07 > 02 所以会返回一个大于0的数
练习:
练习使用
int main()
{
int arr1[] = { 1,4,7 };
int arr2[] = { 1,4,2 };
int ret = memcmp(arr1, arr2,sizeof(arr1));
printf("%d", ret);
return 0;
}
模拟实现memcmp
1.14memset
知识点:
//void *memset( void *dest, int c, size_t count );
//count的大小是byte,会一个个字节的改变内存中的内容
细节:
对于整形数组时要注意,count是以一个个byte来进行改变的
当我们要将整形数组内容全部改成1时,不能写成memset(arr,1,20);
练习:
使用举例:将hello world 改成 xxxxx yyyyy
int main()
{
char arr[] = "hello world";
//void *memset( void *dest, int c, size_t count );
memset(arr, 'x', 5);//count的大小是byte,会一个个字节的改变
printf("%s\n", arr);
memset(arr + 6, 'y', 5);
printf("%s\n", arr);
return 0;
}
模拟实现memset
本章完。预知后事如何,暂听下回分说。
持续更新大量C语言细致内容,三连关注哈