字符函数和字符串函数
C语言本身是没有字符串类型的,字符串通常放在 常量字符串 中或者 字符数组 中。
1.库函数介绍
1.1、strlen——求字符串长度
size_t strlen (const char* str);
注:
a、字符串以 ' \0 ' 作为结束标志,strlen函数返回的是在字符串 ' \0 ' 前面出现的字符个数(不包含 ' \0 ' )。
b、参数指向的字符串必须要以 ' \0 ' 结束。
c、注意函数的返回值为 size_t ,是无符号的。
演示如下:
//strlen 函数使用
//strlen 函数返回字符串长度,不计算'\0'
int main()
{
char ch[] = "abcd";
int a = strlen(ch); //将strlen返回值赋给a 。
printf("%d\n", a); //打印结果 4 。可见strlen不计算 '\0' 。
printf("%d\n",strlen(ch)); //打印结果 4 。直接使用strlen返回值。
return 0;
}
1.2、strcpy——字符串拷贝
char* strcpy ( char* destination, const char* source );
注:
a、源字符串必须以 ' \0 ' 结束。
b、会将源字符串中的 ' \0 ' 拷贝到目标空间。
b、目标空间必须足够大,能容纳源字符串的内容。
c、目标空间必须可修改。
演示如下:
//strcpy 函数使用
//strcpy 函数实现字符串拷贝功能
//将第二个操作数中的字符串拷贝到第一个字符串中
int main()
{
char ch1[20] = "*********";
char ch2[] = "abcde";
//strcpy(ch1, ch2);
//printf("%s\n", ch1); //打印结果 abcde 。说明'\0'也被拷贝进ch1了。
printf("%s\n", strcpy(ch1, ch2)); //打印结果 abcde 。说明strcpy返回值是ch1的地址。
return 0;
}
1.3、strcat——字符串追加
char* strcat ( char* destination, const char* source );
注:
a、源字符串必须以 ' \0 ' 结束。
b、目标空间必须足够大,能容纳源字符串的内容。
c、目标空间必须可修改。
演示如下:
//strcat 函数使用
strcat 函数实现字符串追加功能
//将第二个操作数中的字符串追加到第一个字符串后面
int main()
{
char ch1[20] = "****\0***";
char ch2[] = "abcd";
//strcat(ch1, ch2);
//printf("%s\n", ch1); //打印结果****abcd。说明是从ch1中的 '\0'开始粘贴的。
printf("%s\n", strcat(ch1, ch2)); //打印结果****abcd。说明strcat返回值是ch1地址。
return 0;
}
1.4、strcmp——字符串比较
int strcmp ( const char* str1, const char* str2 );
注:
a、第一个字符串大于第二个字符串,则返回大于0的数字。
b、第一个字符串等于第二个字符串,则返回0。
c、第一个字符串小于第二个字符串,则返回小于0的数字。
演示如下:
//strcmp 函数使用
//strcmp 比较的是对应位字符的ASCII码值。
//根据ASCII码值比较结果返回 <0 、 >0 或0。
int main()
{
char ch1[20] = "abcde";
char ch2[] = "abcde";
char ch3[] = "abb";
int ret1 = strcmp(ch1, ch2);
if (ret1 > 0)
{
printf(">\n");
}
else if (ret1 < 0)
{
printf("<\n");
}
else
{
printf("=\n"); //打印结果 = 。可见strcmp只比较到'\0'处,跟数组长度无关。
}
int ret2 = strcmp(ch1, ch3);
if (ret2 > 0)
{
printf(">\n"); //打印结果 > 。因为C的ASCII码大于b的ASCII码。
}
else if (ret2 < 0)
{
printf("<\n");
}
else
{
printf("=\n");
}
return 0;
}
1.5、strncpy——字符串拷贝
char* strncpy ( char* destination, const char* source, size_t num );
注:
a、从源字符串拷贝num个字符到目标空间。
b、如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
演示如下:
//strncpy 函数使用
//拷贝指定数量个字符。
int main()
{
char ch1[20] = "abcdefg";
char ch2[] = "bjlak";
strncpy(ch1, ch2, 2);
printf("%s\n", ch1); //打印结果 bjcdefg 。strcpy只拷贝了 前两个字符。
return 0;
}
1.6、strncat——字符串追加
char* strncat ( char* destination, const char* source,size_t num );
注:
a、追加num个字符
演示如下:
//strncat 函数使用
//追加指定数量个字符。
int main()
{
char ch1[20] = "abcde ";
char ch2[] = "bbbbbb";
strncat(ch1, ch2, 3);
printf("%s\n", ch1); //打印结果 abcde bbb 。strncat 只追加了3个字符。
return 0;
}
1.7、strncmp——字符串比较
int strncmp ( const char* str1, const char* 2, size_t num );
注:
a、比较到两个字符不一样 或者 一个字符串结束 或者 num个字符全部比较完。
演示如下:
//strncmp 函数使用
//比较指定数量个字符
int main()
{
char ch1[20] = "abcdef";
char ch2[] = "abcddd";
int ret1 = strncmp(ch1, ch2, 3);
if (ret1 > 0)
{
printf(">\n");
}
else if (ret1 < 0)
{
printf("<\n");
}
else
{
printf("=\n"); //打印结果 = 。strncmp只比较了3个字符,所以是 = 。
}
int ret2 = strncmp(ch1, ch2,5);
if (ret2 > 0)
{
printf(">\n"); //打印结果 > 。strncmp比较了5个字符,所以是 > 。
}
else if (ret2 < 0)
{
printf("<\n");
}
else
{
printf("=\n");
}
return 0;
}
1.8、strstr——字符串查找
char* strstr ( const char* str1, const char* str2 );
注:
a、在str1中查找str2
演示如下:
//strstr 函数使用
//strstr 函数实现查找字符串功能
//从第一个操作数中查找第二个操作数
//如果在第一个字符串中找到第二个字符串
//返回第一个字符串中第二个字符串的首字符地址
//找不到返回NULL
int main()
{
char ch1[] = "abcdefgh";
char ch2[] = "cde";
char ch3[] = "cdd";
char* find1 = strstr(ch1, ch2);
char* find2 = strstr(ch1, ch3);
printf("%s\n", find1); //打印结果 cdefgh 。说明返回的是abcdefgh 中 cde的c地址。
printf("%s\n", find2); //打印结果 (NULL) 。 不建议这样使用,建议先if判断再使用
printf("%s\n", strstr(ch1, ch2)); //打印结果 cdefgh 。说明返回的是abcdefgh 中 cde的c地址。
return 0;
}
1.9、strtok——分解字符串
char* strtok ( char* str, const char* sep );
注:
a、sep参数是个字符串,定义了用作分隔符的字符集合。
b、第一个参数指定一个字符串,它包含了0个 或 多个由sep字符串中一个 或 多个分隔符分割的标记。
c、strtok函数找到str中的下一个标记,并将其用 ' \0 ' 结尾,返回一个指向这个标记的指针。(strtok函数会改变被操作的字符串,所以使用strtok函数切分的字符串一般都是临时拷贝的内容,并且可修改。)
d、strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
e、strtok函数的第一个参数不为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
f、如果字符串中不存在更多的标记,则返回NULL指针。
演示如下:
//strtok 函数使用
//strtok 函数实现将字符串按指定字符分割。
//strtok 会保存当次分隔符的地址
//新参数输入NULL时,它会调用之前保存的地址。
//字符串中没有指定字符时,它会返回NULL。
int main()
{
char ch1[] = "www.abc dd! e. f@d.com";
char ch2[] = ".@ ";
char tmp[30] = { 0 };
strcpy(tmp,ch1); //strtok会操作字符串,一般用拷贝的数组作为参数。
char* test1 = strtok(tmp, ch2);
printf("%s\n", test1); //打印结果 www ,分隔符是 '.',从ch1中找到ch2中的字符,将ch1分割。
char* test3 = strtok(NULL, ch2);
printf("%s\n", test3); //打印结果 abc ,分隔符是 ' ',输入为NULL,从上次分隔符开始往下分割。
char* test4 = strtok(NULL, ch2);
printf("%s\n", test4); //打印结果 dd! ,分隔符是 ' ',输入为NULL,从上次分隔符开始往下分割。
char* test2 = strtok(tmp, ch2);
printf("%s\n", test2); //打印结果是 www,分隔符是 '.'。可见strtok记录的并不是字符串,而是之前的地址。
return 0;
}
这样使用太繁琐,简化如下:
//上面使用太麻烦,不可能每次写很多行
int main()
{
char ch1[] = "www.abc dd! e. f@d.com";
char ch2[] = ".@ ";
char tmp[30] = { 0 };
strcpy(tmp,ch1); //strtok会操作字符串,一般用拷贝的数组作为参数。
char* test1 = NULL;
for (test1 = strtok(tmp, ch2); test1 != NULL; test1 = strtok(NULL, ch2))
{
printf("%s\n", test1);
//打印结果
//www
//abc
//dd!
//e
//f
//d
//com
}
return 0;
}
1.10、strerror——错误信息报告,返回错误码所对应的错误信息
char* strerror (int errnum);
演示如下:
//strerror 函数使用
//strerror 函数返回参数对应的错误信息。
int main()
{
printf("%s\n", strerror(5));
//打印结果 Input/output error 。即错误代码编号5的错误信息是输入输出错误
//strerror 函数使用场景为出现错误代码时输出错误信息。
//如 if(XXXX) printf("%s\n",strerror(errno));
//这里的errno 是当前错误代码,使用时需要 #include <errno.h>
return 0;
}
perror——错误信息打印。
演示如下:
//perror 函数使用
//perror 函数可打印错误信息。
int main()
{
perror("abdc"); //运行结果,打印 abdc: No error ,字符串abdc 无错误。
//perror函数会直接打印错误信息。
return 0;
}
字符操作函数
字符分类函数,参数符合条件返回真
函数名——条件
iscntrl——任何控制字符
isspace——空白字符:空格 ' ' ,换页 ' \f ' ,换行 ' \n ',回车 ' \r ',制表符 ' \t ' 或垂直制表符 ' \v '
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 ——标点符号,任何不属于数字或者字母的圆形字符(可打印)
isgraph——任何图形字符
isprint——任何可打印字符,包括图形字符和空白字符
演示如下:
//字符分类函数介绍
//使用方法基本相同,测试十进制数字分类isdigit 和大写字母分类isupper
//使用字符分类函数需要 #include <ctype.h>
#include <ctype.h>
int main()
{
char c1 = 'A';
char c2 = '3';
int ret1 = isdigit(c1); //判断c1 是不是十进制数字
int ret2 = isupper(c1); //判断c1 是不是大写字母。
printf("%d\n", ret1); //打印结果 0 。 c1不是十进制数字,返回结果是 0 。
printf("%d\n", ret2); //打印结果 1 。 c1是大写字母,返回结果是 1 (非0)。
int ret3 = isdigit(c2); //判断c2是不是十进制数字
int ret4 = isupper(c2); //判断c2是不是大写字母。
printf("%d\n", ret3); //打印结果 4 。 c2是十进制数字,返回结果是 4 (非0)。
printf("%d\n", ret4); //打印结果 0 。 c2不是大写字母,返回结果是 0。
//字符分类函数,字符不符合分类返回 0 ,符合分类返回非0数字。
return 0;
}
字符转换函数
int tolower( int c ); ——把大写字母转换成小写字母
int toupper( int c );——把小写字母转换成大写字母
演示如下:
//字符转换函数
//tolower 可以将大写字母转换成小写字母
//使用 tolower 函数需要 #include <stdlib.h>
#include <stdlib.h>
int main()
{
char ch1 = 'A';
ch1 = tolower(ch1);
printf("%c\n", ch1); //打印结果是 a 。ch1被转换成小写字母a。
char ch2[] = "AbCdEf";
int len = strlen(ch2);
int i = 0;
for (i = 0; i < len; i++)
{
if (isupper(ch2[i])) //如果ch2[i]是大写字母,则将其转换为小写字母
{
ch2[i] = tolower(ch2[i]);
}
printf("%c ", ch2[i]); //打印结果 a b c d e f 。 ch2 数组中的大写字母被转换成小写字母了。
}
return 0;
}
内存操作函数
1.11、memcpy——内存拷贝
void* memcpy ( void* destination, const void* source,size_t num );
注:
a、函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
b、这个函数在遇到 ' \0 ' 的时候不会停下来。
c、如果source和destination有任何的重叠,复制的结果都是未定义的。
演示如下:
//memcpy 函数使用
//memcpy 可以实现内存拷贝。
//可以对非字符类元素进行拷贝。
int main()
{
int a[20] = { 1,2,3,4,5,6,7,8,9,0 };
int b[20] = { 0 };
memcpy(b, a, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", b[i]); //打印结果 1 2 3 4 5 0 0 0 0 0 ,数组a中的前5个整型数字拷贝到数组b中了。
}
//memcpy可以拷贝指定数量个字节。
//int类型元素是4个字节,20个字节就是5个元素。
return 0;
}
1.12、memmove——拷贝重叠内存块
void* memove ( void* destination,const void* source,size_t num );
注:
a、和memcpy的差别就是memmove函数处理的源内存块和目标内存块可以重叠。
b、如果源空间和目标空间出现重叠,就得使用memmove函数处理。
演示如下:
//memmove 函数使用
//memmove 可以把源地址往后的指定数量个元素拷贝到目标地址
//功能和memcpy相似,但C语言标准中,memcpy不能拷贝重叠的内存地址上的内容
//memmove 可以拷贝重叠地址上的内容。
//有些编译器中memcpy也能做到memmove的功能
int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9,0 };
memmove(a + 3, a, 20); //把地址a开始的20个字节拷贝到a+3开始的20个字节中。
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", a[i]); //打印结果 1 2 3 1 2 3 4 5 9 0
}
printf("\n");
int b[10] = { 1,2,3,4,5,6,7,8,9,0 };
memmove(b, b + 2, 20); //把地址a开始的20个字节拷贝到a+3开始的20个字节中
for (i = 0; i < 10; i++)
{
printf("%d ",b[i]); //打印结果 3 4 5 6 7 6 7 8 9 0
}
return 0;
}
1.13、memcmp——内存比较函数
int memcmp ( const void* ptr1, const void* ptr2, size_t num );
注:
a、比较从ptr1和ptr2指针开始的num个字节。
b、将内存中数据以 unsigned char 类型值比较。
c、两个内存块中第一个不相等的字节对比,ptr1小于ptr2,返回小于0的数字。
d、两个内存块相等,返回0。
e、两个内存块中第一个不相等的字节对比,ptr1大于ptr2,返回大于0的数字。
演示如下:
//memcmp 函数使用
//memcmp 函数用于比较两个地址中指定字节的内容是否相等
//相等返回0
//目标地址内容小于源地址返回<0的数
//目标地址内容大于源地址返回>0的数
int main()
{
int arr1[] = { 1,2,3,4,5,6,6,7 };
int arr2[] = { 1,2,2,4,5,6 };
int a = memcmp(arr1, arr2, 8); //比较arr1和arr2前8个字节内容。这里是前两个整型。
int b = memcmp(arr1, arr2, 12); //比较arr1和arr2前20个字节内容。这里是前五个整型。
printf("%d\n", a); //打印结果 0 。arr1和arr2前8个字节相等,返回 0 。
printf("%d\n", b); //打印结果 1 。arr1前12个字节比arr2大,返回 1 。
return 0;
}
1.14、memset——内存设置函数
void* memset ( void* dest, int c, size_t count);
注:
a、将 dest 地址往后 count 个字节设置成 c 。
演示如下:
//memset 函数使用
//memset 函数可以将目标地址中的指定数量个字节设置成指定值
int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9 };
memset(a, 0, 8); //将a地址往后的前8个字节设置成0 。
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", a[i]); //打印结果 0 0 3 4 5 6 7 8 9 0 ,
}
//要注意,memset是按字节设置数,而不是按整型!
return 0;
}
2.库函数的模拟实现
2.1、模拟实现strlen
a、计数器版本
演示如下:
//模拟实现strlen函数
//计数器版本
int my_strlen(const char* arr)
{
assert(arr); //断言,防止空指针
int count = 0; //设置计数器
//*arr 内容不为 0 则判断为真,循环继续,为 0 则判断为假,循环停止。
//arr是char*,其中的内容判断为字符,'\0'的ASCII码就是 0 。
//因此,将 *arr != ’\0’ 简化成 *arr 。
while (*arr)
{
arr++;
count++;
}
return count;
}
int main()
{
char ch[] = "abcd";
int a = my_strlen(ch);
printf("%d\n", a); //打印结果 4 。
printf("%d\n", my_strlen(ch)); //打印结果 4 。
return 0;
}
b、递归版本
演示如下:
//模拟实现strlen函数
//递归版本
int my_strlen(const char* arr)
{
assert(arr); //断言,防止空指针
if (*arr) //*arr 不为'\0'则返回 1+ my_strlen(arr + 1)
return 1 + my_strlen(arr + 1);
else
return 0; //*arr 为'\0' 则返回0
//即每次进入下一个地址,下一个地址不为 '\0'就 +1
}
int main()
{
char ch[] = "abcd";
int a = my_strlen(ch);
printf("%d\n", a); //打印结果 4 。
printf("%d\n", my_strlen(ch)); //打印结果 4 。
return 0;
}
c、指针减指针版本
演示如下:
//模拟实现strlen函数
//指针减指针版本
int my_strlen(const char* arr)
{
assert(arr); //断言,防止空指针
char* ori = (char*)arr; //记录起点处地址。
while (*ori) //若*arr 不为'\0',则进入下一个字符地址
{
ori++;
}
//地址到 *arr == '\0' 时循环停止
return ori - arr; //用'\0'处的地址 减去起始地址,就是元素个数。
}
int main()
{
char ch[] = "abcd";
int a = my_strlen(ch);
printf("%d\n", a); //打印结果 4 。
printf("%d\n", my_strlen(ch)); //打印结果 4 。
return 0;
}
2.2、模拟实现strcpy
演示如下:
//模拟实现strcpy
char* my_strcpy(char* arr1, const char* arr2)
{
assert(arr1 && arr2); //断言,arr1 和arr2 都不能是空指针
char* ch = arr1; //记录arr1地址。
int len = strlen(arr2); //计算arr2长度。
int i = 0;
for (i = 0; i <= len; i++) //按arr2长度 +1 循环赋值,将arr2中的字符赋给arr1。
{
*arr1++ = *arr2++;
}
return ch;
}
int main()
{
char ch1[20] = "*********";
char ch2[] = "abcde";
//my_strcpy(ch1, ch2);
//printf("%s\n", ch1); //打印结果 abcde 。
printf("%s\n", my_strcpy(ch1, ch2)); //打印结果abcde 。
return 0;
}
2.3、模拟实现strcat
演示如下:
//strcat 模拟实现
char* my_strcat(char* arr1, const char* arr2)
{
assert(arr1 && arr2);
char* ch = arr1; //将arr1赋给 ch。
while (*ch) //找到 *ch == '\0' 的ch。
{
ch++;
}
while (*ch++ = *arr2++) //将arr2中的字符粘贴到ch中,然后++。直到 *arr2 中出现'\0'
{
;
}
return arr1;
}
int main()
{
char ch1[20] = "****\0***";
char ch2[] = "abcd";
//my_strcat(ch1, ch2);
//printf("%s\n", ch1); //打印结果****abcd。
printf("%s\n", my_strcat(ch1, ch2)); //打印结果****abcd。
return 0;
}
2.4、模拟实现strcmp
演示如下:
//模拟实现 strcmp 函数
int my_strcmp(const char* arr1, const char* arr2)
{
assert(arr1 && arr2); //断言
while (*arr1 == *arr2) //*arr1 等于 *arr2 时,arr1++,arr2++。
{
if (*arr1 == '\0') //如果*arr1 == '\0',返回0。
{
return 0;
}
arr1++;
arr2++;
}
//*arr1 != *arr2 时跳出循环
return *arr1 - *arr2; //返回*arr1 - *arr2
}
int main()
{
char ch1[20] = "abcde";
char ch2[] = "abcde";
char ch3[] = "abb";
int ret1 = my_strcmp(ch1, ch2);
if (ret1 > 0)
{
printf(">\n");
}
else if (ret1 < 0)
{
printf("<\n");
}
else
{
printf("=\n"); //打印结果 = 。
}
int ret2 = my_strcmp(ch1, ch3);
if (ret2 > 0)
{
printf(">\n"); //打印结果 > 。
}
else if (ret2 < 0)
{
printf("<\n");
}
else
{
printf("=\n");
}
return 0;
}
2.5、模拟实现strstr
演示如下:
//模拟实现strstr 函数
char* my_strstr(const char* arr1, const char* arr2)
{
assert(arr1 && arr2); //断言
char* find = (char*)arr1; //将arr1首元素地址赋给 find。
char* c1 = NULL; //定义字符指针c1,c2,后续用
char* c2 = NULL;
if (*arr2 == '\0') //arr2 如果是空指针,返回字符串arr1地址。
{
return ((char*)arr1);
}
while (*find) //find 中还有字符就继续查找
{
c1 = find; //记录当次查找的起始地址
c2 = (char*)arr2; //从arr2 的首字符开始查找
while (*c2 && (*c1 == *c2)) //c2不为0,且c1中字符与c2中字符一样则继续往后查找
{
c1++; //下一个字符
c2++; //下一个字符
}
if (*c2 == '\0') //c1中字符和c2中字符不一样时,判断c2是否为结束符。
{
return find; //c2是结束符说明找到了arr2中的所有字符串。
}
find++; //从find开始没找到arr2,则从find++开始查找。
}
return NULL;
}
int main()
{
char ch1[] = "abcdefgh";
char ch2[] = "cde";
char ch3[] = "cdd";
char* find1 = my_strstr(ch1, ch2);
char* find2 = my_strstr(ch1, ch3);
printf("%s\n", find1); //打印结果 cdefgh 。
printf("%s\n", find2); //打印结果 (NULL) 。
printf("%s\n", my_strstr(ch1, ch2)); //打印结果 cdefgh 。
return 0;
}
2.6、模拟实现memcpy
演示如下:
//模拟实现 memcpy 函数
void* my_memcpy(void* destination, const void* source, int num)
{
assert(destination && source);
char* ret = (char*)destination;
while (num--)
{
*ret = *(char*)source;
ret++;
source = (char*)source + 1;
}
return destination;
}
int main()
{
int a[20] = { 1,2,3,4,5,6,7,8,9,0 };
int b[20] = { 0 };
my_memcpy(b, a, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", b[i]); //打印结果 1 2 3 4 5 0 0 0 0 0 ,数组a中的前5个整型数字拷贝到数组b中了。
}
//memcpy可以拷贝指定数量个字节。
//int类型元素是4个字节,20个字节就是5个元素。
return 0;
}
2.7、模拟实现memmove
演示如下:
//模拟实现memmove 函数
void* my_memmove(void* dest,const void* src, int num)
{
assert(dest && src); //断言
char* ret = (char*)dest; //将dest赋给 ret
if (dest < src) //目标地址在源地址前面时,从前往后拷贝
{
while (num--)
{
*ret = *(char*)src;
ret = ret + 1;
src = (char*)src + 1;
}
}
else //目标地址在源地址后面时,从后往前拷贝
{
while (num--)
{
*(ret + num) = *((char*)src + num);
}
}
return dest;
}
int main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9,0 };
my_memmove(a + 3, a, 20); //把地址a开始的20个字节拷贝到a+3开始的20个字节中。
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", a[i]); //打印结果 1 2 3 1 2 3 4 5 9 0
}
printf("\n");
int b[10] = { 1,2,3,4,5,6,7,8,9,0 };
my_memmove(b, b + 2, 20); //把地址a开始的20个字节拷贝到a+3开始的20个字节中
for (i = 0; i < 10; i++)
{
printf("%d ",b[i]); //打印结果 3 4 5 6 7 6 7 8 9 0
}
return 0;
}