#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
//strtok(字符串分割函数)
//char* strtok(char* str, const char* sep)
//str是一个字符指针,指向的是一个包含若干个分隔符的字符串;sep指向的是由str指向的字符串中出现的所有形式的分隔符构成的一个集合,本质还是一个字符串
//str指向的字符串被sep指向的字符串中的分隔符分割成一个个的标记。例:
//现有字符串:"[email protected]",则该字符串被两个分隔符"@ ."分割成三个标记,第一个标记为abcd、第二个标记为1234、第三个标记为com
//strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。如:
// "[email protected]"中的第一个标记:abcd,strtok函数会用\0将abcd结尾,strtok函数的返回值是指向abcd首元素的字符指针
// (注:strtok函数会改变备操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改)
//strtok函数在寻找str中的第一个标记时,strtok的第一个参数不为NULL,除第一个标记外strtok在寻找其它标记时,strtok的第一个参数都为NULL,因为strtok函数具有记忆功能:
//strtok函数在寻找完一个标记之后会保存它现在所在的位置,在寻找下一个标记时候直接用空指针NULL来接收它当前所在的位置,从该位置开始继续往后找即可。如:
//strtok函数在寻找完"[email protected]"中的第一个标记abcd之后,它当前所在的位置在[email protected]中的分隔符@位置处,在寻找下一个标记时候将@的位置传给strtok,从@开始往后找,直到再次遇到分隔符停止寻找,这两个分隔符之间的所有内容就是前面说的‘下一个标记’
//如果字符串中的所有标记都被找完,再执行strtok函数会返回空指针NULL
int main()
{
char arr[] = "[email protected]";
char buf[30] = { 0 };
strcpy(buf, arr);
const char* p = "@.";
char* str = strtok(buf, p);
printf("%s\n", str); //lbj
str = strtok(NULL, p);
printf("%s\n", str); //123
str = strtok(NULL, p);
printf("%s\n", str); //emil
str = strtok(NULL, p);
printf("%s\n", str); //NULL
//字符串"[email protected]"中的一共只有三个标记,只需要执行三次strtok就可以找完所有标记,这是第四次执行strtok函数,所以会返回空指针NULL
return 0;
}
//代码优化
int main()
{
char arr[] = "[email protected]";
char buf[30] = { 0 };
strcpy(buf, arr);
const char* p = "@.";
char* str = NULL;
for (str = strtok(buf, p); str != NULL; str = strtok(NULL, p)) //和for(i=0;i<10;i++)是一个道理
{ //str = strtok(buf, p):寻找第一个标记,并将strtok返回的第一个标记的首字符地址赋值给str
//str != NULL:判断条件,当strtok返回空指针NULL时终止循环
//str = strtok(NULL, p):用于寻找第一个标记以外的其他标记
printf("%s\n", str);
}
return 0;
}
//strerror
//char* strerror(int errnum) errnum是错误码,strerror的返回值是错误码所对应的错误信息的首字符地址
// 其实:c语言的库函数在调用失败的时候会将一个错误码存放在一个叫做error的变量中,当我们想知道调用库函数时发生了什么错误信息,就可以将error中的错误码翻译成错误信息
// 有一个库函数perror(),它的作用等价于strerror()+printf(),感兴趣可以了解一下
//功能演示
int main()
{
char* p = strerror(0);
printf("%s\n", p); //No error 当错误码是0时,代表没错误信息
p = strerror(1);
printf("%s\n", p); //Operation not permitted
p = strerror(2);
printf("%s\n", p); //No such file or directory
p = strerror(3);
printf("%s\n", p); //No such process
return 0;
}
//memcpy
//void* memcpy(void* destination, const void* source, size_t num);
//void*可以接收任意类型的指针,运算或者解引用时必须先进行强制类型转换;destination是目标空间起始位置;source是源空间的起始位置;num的单位是字节
//memcpy的返回值是目标空间的起始位置,即destination
//即memcpy是将源空间的前num个字节拷贝到目标空间
// memcpy是内存拷贝函数,内存不是字面意思,它指的是内存中存储的任意类型的数据
// strcpy只能拷贝字符串,而memcpy可以拷贝任何类型的数据
//(函数需要包含头文件<string.h>)
//memcpy不适用于destination和source有内存重叠的情形,该情形专门由下一个讲到的mememove函数来处理
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[] = { 2,4,6,8,10 };
memcpy(arr1, arr2, 20); //20的单位是字节
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]); //2 4 6 8 10 6 7 8 9 10
}
return 0;
}
//模拟实现memcpy(不考虑目标空间和源空间的内存重叠)
void* my_memcpy(void* arr1, const void* arr2, size_t num)
{
void* ret = arr1;
while (num--)
{
*(char*)arr1 = *(char*)arr2;//强制类型转换只是在该语句中,该语句执行完又会恢复到原来的类型,即强制类型转换都是临时性的
((char*)arr1)++;
((char*)arr2)++;
}
return ret;
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[] = { 2,4,6,8,10 };
my_memcpy(arr1, arr2, 20); //20的单位是字节
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]); //2 4 6 8 10 6 7 8 9 10
}
return 0;
}
//memmove
//相对于memcpy,memmove专门解决目标空间和源空间的内存重叠问题
//(函数需要包含头文件<string.h>)
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr + , arr + 2, 240);
//arr是数组名,表示数组首元素地址;arr + 4是数组第五个元素地址;arr + 2是数组第三个元素地址;20的单位是字节(即5个int类型数据)
//arr + 4是目标空间的起始地址,arr + 2是源空间的起始地址,即从arr + 2的位置开始向后复制20个字节(5个int型)的数据到以arr + 4为起始地址的目标空间
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]); //1 2 3 4 3 4 5 6 7 10
}
return 0;
}
//模拟实现memmove
//如果源空间和目标空间出现重叠:当目标空间的起始位置大于源空间的起始位置(即目标空间起始位置相对于源空间起始位置而言是较高地址)时,源空间内存储的数据从高地址向低地址的顺序依次拷贝到目标空间;其他情况均是从低地址向高地址的顺序依次拷贝
void* my_memmove(void* arr1, const void* arr2, size_t num)
{
void* ret = arr1;
if (arr1 <= arr2)
{
while (num--)
{
*(char*)arr1 = *(char*)arr2;
((char*)arr1)++;
((char*)arr2)++;
}
}
else
{
while (num--)
{
*((char*)arr1 + num) = *((char*)arr2 + num);
}
}
return ret;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr + 4, arr + 2, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]); //1 2 3 4 3 4 5 6 7 10
}
return 0;
}
//memcmp
//int memcmp(const void* ptr1, const void* ptr2, size_t num) 注意:这里的num单位是字节
//memcmp是比较从ptr1和ptr2指针开始的前num个字节
//memcmp和strcmp的区别是可以对任意类型的数据进行比较,其他无异
int main()
{
char arr1[] = "abcddef";
char arr2[] = "abcdefg";
int p1 = memcmp(arr1, arr2, 4);
int p2 = memcmp(arr1, arr2, 5);
printf("%d\n", p1); //0
printf("%d\n", p2); //-1
return 0;
}
//memset
//void* memset(void* ptr, int value, size_t num)
//memset是将ptr指向的内容的前num个字节的值设置成value 注意:num单位是字节 memset的返回值是ptr
int main()
{
char str[] = "hello world";
int arr[10] = { 0 };
memset(str, 'a', 5);
memset(arr, 1, 10);
printf("%s\n", str); //aaaaa world
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]); //16843009 16843009 257 0 0 0 0 0 0 0
//memset不能实现将arr的所有元素设置成1,主要原因还是memset中的参数num的单位是字节,它是按字节来设置的
}
return 0;
}