网站建设市场行情分析,短视频营销推广,品牌宣传型网站建设方案,如何开通公众号前言
之前我们用两篇文章介绍了strlen、strcpy、stract、strcmp、strncpy、strncat、strncmp、strstr、strtok、streeror这些函数
第一篇文章strlen、strcpy、stract
第二篇文章strcmp、strncpy、strncat、strncmp
第三篇文章strstr、strtok、streeror
今天我们就来学习字…前言
之前我们用两篇文章介绍了strlen、strcpy、stract、strcmp、strncpy、strncat、strncmp、strstr、strtok、streeror这些函数
第一篇文章strlen、strcpy、stract
第二篇文章strcmp、strncpy、strncat、strncmp
第三篇文章strstr、strtok、streeror
今天我们就来学习字符分类函数、字符转换函数、内存访问函数
话不多说我们直接开始
字符分类函数
这些函数需要包含头文件ctype.h
例子islower
用islower函数作为例子
当字符是小写字母时返回一个非零的整数 当不是小写字母时返回0
int main()
{char ch w;int ret islower(ch);printf(%d\n, ret);return 0;
}字符转换函数 int tolower(int a) int toupper(int b) 一般使用
转换单个字符
int main()
{char ch W;char ret tolower(ch);printf(%c\n, ret);return 0;
}转换字符串
int main()
{char arr[] HELLO WORLD;int i 0;while (arr[i]){if (isupper(arr[i])){arr[i] tolower(arr[i]);}i;}printf(%s\n, arr);return 0;
}内存访问函数
我们接下来会学习memcmp、memmove、memcmp、memset函数
引入
小明提出疑问 我们之前已经学习了那么多的字符串函数strlen、strcpy、stract、strcmp、strncpy、strncat、strncmp…为什么还要学习内存函数呢
那是因为上面的那些函数操作对象都是字符串也大多需要用到’\0’ 而当我们要对整型数组或者结构体的数组这时我们在用之前的那些函数就做不到了
下面看一段代码它能达到我们预想的结果吗
int main()
{int arr1[] { 1,2,3,4,5 };int arr2[5] { 0 };strcpy(arr1, arr2);return 0;
}程序警告 “函数”: 从“int [5]”到“char *”的类型不兼容 “函数”: 从“int [5]”到“const char *”的类型不兼容 原因
上面我们学习过strcpy函数的参数是char* dest, const char* src 而下面这行代码 strcpy(arr1, arr2);就是在把一个整型元素传给一个char*指针的元素
并且我们知道strcpy在遇到’\0’就停止拷贝以及strcpy的操作单位大小是一个字节
那么如图整型数据在小端模式下存储的方式如图 当拷贝完01后遇到了00我们都知道’\0’的ASCII码值是0所以这就相当于拷贝结束所以对于非字符数组strcpy是无法使用的
这时我们就要使用上文提到的内存函数了
memcmp
内存拷贝函数可以拷贝任何类型的数据
此处联系之前学习的知识就可以知道参数的类型是void* 后面的num是需要拷贝的字节数
void * memcpy ( void * destination, const void * source, size_t num );使用示例
下面介绍两个例子拷贝整型数据、拷贝结构体类型数据
-struct Stu
{char name[20];int name;
};int main()
{int arr1[] { 1,2,3,4,5 };int arr2[5] { 0 };struct Stu arr3[] { {zhang, 20}, {wang, 15},{li, 25} };struct Stu arr4[] { 0 };memcpy(arr1, arr2, sizeof(arr1));memcpy(arr3, arr4, sizeof(arr3));return 0;
}模拟实现
问题 因为是void*类型的参数所以我们这里既不能解引用、又不能与整数运算
所以我们就从第三个参数num入手既然我不知道要拷贝的元素类型是什么那么就以字节为单位进行拷贝这样肯定就没问题了 *(char*)dest *(char*)src;//处理赋值问题 (char*)dest;//处理运算问题(char*)src;初步代码
void* my_memcpy(void* dest, const void* src, int num)
{assert(dest src);//断言好习惯void* ret dest;//存储首元素方便拷贝之后打印while (num--){*(char*)dest *(char*)src;(char*)dest;//强制类型转换的优先级比要低所以要写在前面(char*)src;}return dest;
}一些重点提示 特殊使用
在下面这个字符串中我想要将12345拷贝到34567的位置上怎么实现呢使用my_memcpy函数 int arr1[] { 1,2,3,4,5,6,7,8,9,10 };
像下面这么写可以吗
int main()
{int arr1[] { 1,2,3,4,5,6,7,8,9,10 };int i 0;my_memcpy(arr1 2, arr1, 20);for (i 0; i 10; i){printf(%d , arr1[i]);}return 0;
}运行结果 咦那这是为什么
原因
初步说明 源数据和目的地数据有关系当想将3复制到5的地址处时3已经在之前被替换成1了所以结果就不对
解决方法
那么如果我们从后向前复制是不是就可以解决了先将5复制到74复制到6以此类推
但这种方法也是有漏洞的当要拷贝的源数据在目的地数据之前时程序也会出问题
所以要根据实际情况来判断但是有另外的函数来处理这种重叠拷贝的问题 下面我们就来学习memmove函数
注意
虽然使用memcpy函数去执行上面的操作也是可以实现的 但C语言标准中规定memcpy函数只用来处理内存不重叠的拷贝 memmove函数是用来处理重叠内存的拷贝的
memmove
void * memmove ( void * destination, const void * source, size_t num );使用示例
int main()
{int arr1[] { 1,2,3,4,5,6,7,8,9,10 };int i 0;memmove(arr1 2, arr1, 20);return 0;
}运行结果
模拟实现
思路分析
分三种情况讨论
1
dest的地址小于src也就是dest指向的元素在src指向的元素的左边 就从前向后拷贝
2
dest的地址大于src也就是dest指向的元素在src指向的元素的右边 就从后向前拷贝
3
拷贝的内容无内存重叠怎么拷贝都可以
最终代码
此处只提供一种分类方式还有其他的分类方式都可以 就是需要注意在进行整数运算的时候需要进行强制类型转换
void* my_memmove(void* dest, const void* src, size_t count)
{assert(dest src);void* ret dest;if (dest src)//从前向后{while (count--){*(char*)dest *(char*)src;(char*)dest;(char*)src;}}else//从后向前{while (count--)//count改变dest和src就不用改变了{*((char*)dest count) *((char*)src count);}}return ret;
}int main()
{int arr1[] { 1,2,3,4,5,6,7,8,9,10 };int i 0;my_memmove(arr1 2, arr1, 20);for (i 0; i 10; i){printf(%d , arr1[i]);}return 0;
}memcmp
简单了解一下即可
介绍
定义如下
int memcmp ( const void * ptr1, const void * ptr2, size_t num );num是比较的字节个数
返回值
返回值与strcmp函数的返回值判定方式相同 如果字符串1小于字符串2返回值小于0 如果字符串1等于字符串2返回值为0 如果字符串1大于字符串2返回值大于0 memset
内存设置函数
介绍
作用设置缓冲区作为特殊的字符
参数
dest目的地即要修改哪块空间 c要设置的字符是什么 count要设置的字符数单位是字节
使用
int main()
{char arr[10] ;memset(arr, #, 10);return 0;
}运行过程
注意事项
观察下面这段代码运行结果是什么
int main()
{int arr[10] { 0 };memset(arr, 1, 10);printf(%d\n, arr[0]);return 0;
}输出结果
这是因为参数中count单位是字节 上面的代码是将前十个字节改成了1也就是十六进制的01 01 01 01
结语
关于函数的介绍到这里就结束了希望你有所收获 之后我们会学习自定义数据类型结构体 我们下篇文章见