目录
前言
1.字符串函数
1.1.strlen
1.2.strcpy
1.3.strcat
1.4.strcmp
1.5.strncpy
1.6.strncat
1.7.strncmp
1.8.strstr
1.9.strtok
1.10.strerror
2.字符函数
2.1字符分类函数
2.2字符转换函数
3.内存函数
3.1.mencpy
3.2.memmove
3.3.memcmp
前言
本文重点叙述字符串函数和内存函数,字符函数的使用简单并且较好理解,顺带一提字符函数。内存函数会列举四个 memcpy,menmove,memcmp,memset,重点放在字符串函数中。学习函数基本作用,并模拟函数是如何实现的,可以更好的理解函数。若有错误,请各位批评指正。
1.字符串函数
1.1.strlen
(1)功能:string length 字符串的长度,函数用来计算字符串的长度 。
(2)使用形式:
size_t strlen ( const char * str );
从接受的参数指向的地址开始寻找到'\0'之间的字符个数。
1.size_t 为无符号整型
2.const char * str 为字符指针,接收参数必须是字符指针
3.字符串中 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )。
4.所测的字符串中没有'\0',返回值可能为随机值
(3)示例1
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcdef";//创建字符串
char arr2[6] = {'a','b','c','d','e','f'};
int ret1= strlen(arr1);
int ret2 = strlen(arr2);
printf("%d\n", ret1);
printf("%d", ret2);
return 0;
}
arr2为错误实例,字符串中没有 '\0',因此输出的是随机值,我输出的是22 。
arr2数组首元素指针为0xxxDBFEA4,字符在内存中存储是他的ASCLL,占一个字节;在内存中'\0'就是以00表示,每行8个字节,在00字节处停止。
示例2
strlen所求出的值是字符串的长度,不可能是负数,返回类型是无符号整型,size_t
下述例子可以看出strlen返回数据类型数无符号整型。
#include <stdio.h>
#include <string.h>
int main()
{
if (strlen("abc") - strlen("abcdef") > 0)
printf("正数");
else
printf("负数");
return 0;
}
(4) 模拟实现
下述有三钟模拟类型,第一种是增加局部变量加加,第二种使用递归的方式,遇到'\0'后就返回,第三种使用指针减指针得到指针的步长(元素的多少)。
#include <stdio.h>
#include <assert.h>
//普通方式
int my_strlen1(const char* str)
//const修饰的指针所指向的内容不能通过指针来修改
{
assert(str);//判断是否为空指针
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
//递归方式
int my_strlen2(const char* str)
{
assert(str);
if (*str != '\0')
return 1 + my_strlen2(++str);
else
return 0;
}
//指针-指针
int my_strlen3(const char* str)
{
assert(str);
char* start = str;
while (*str != '\0')
{
str++;
}
return str - start;
}
int main()
{
char arr[] = "abcdef";
int ret = my_strlen3(arr);
printf("%d", ret);
return 0;
}
1.2.strcpy
(1)功能:Copy string,复制字符串,将一个源(source)字符串复制到另一个目标(destination)字符串中。
(2)使用形式:
char* strcpy(char * destination, const char * source );
char * destination 目的地的指针;
const char * source 被复制的字符串的指针,字符串的来源;
char* 函数的返回值为目的地字符串的指针。
注意:
1.源字符串(source)中必须有'\0'的结束标志,复制会将'\0'复制到目标字符串中;
2.函数会识别到源字符串的'\0'结束 ;
3.目标字符串可以修改(常量字符串是不可以被修改的);
4.目标空间要足够,避免非法访问
(3)示例1
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20] = { 0 };
char * p = "abcedf";//常量字符串
char arr2[] = "hello world ";
strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
输出 hello world
示例2
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20] = { 0 };
char * p = "abcedf";//常量字符串
char arr2[] = "hello\0 world ";
strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
输出只有hello,因为函数识别到 \0就会停止复制
(4)模拟实现
#include <stdio.h>
#include <string.h>
#include <assert.h>
char * my_strcpy(char * dest, const char * src)//source简写就是为src
{
char * ret = dest;
assert(dest && src);//空指针警告
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = { 0 };
char arr2[] = "hello world";
char * ret = my_strcpy(arr1,arr2);
printf("%s\n", arr1);
return 0;
}
1.3.strcat
(1)功能:Concatenate strings 文本连接函数,将源字符串追加到目标字符串的后面
(2)使用形式:
char * strcat ( char * destination, const char * source );
函数定义中的字符含义同上。
注意事项
1.源字符串和目标字符串必须含有'\0'结束标志。
2.目标字符串空间够容纳源字符串,且可以修改 没有const修饰
(3)示例1
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
示例2 自身追加(错误示例)
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20] = "hello ";
strcat(arr1, arr1);
printf("%s\n", arr1);
return 0;
}
字符串追加自身的时候,会将字符串自身的'\0'替换掉,字符串无法停止复制,函数在找到'\0'处结束。
(4)模拟实现
实现思路 :strcat函数寻找到目标字符串中'\0',然后在此地址开始追加,追加到自身'\0'处结束。
#include <stdio.h>
#include <string.h>
#include <assert.h>
char * my_strcat(char * dest, const char * src)
{
assert(dest&&src);
char * ret = dest;
while (*dest != '\0')
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret ;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
char * ret = my_strcat(arr1, arr2);
printf("%s\n", ret);
return 0;
}
1.4.strcmp
(1)功能:Compare two strings 比较两个字符串的大小,大小比较为ASCLL值的大小。
(2)使用形式:
int strcmp ( const char * str1, const char * str2 );
1.第一个字符串大于第二个字符串,则返回大于0的数字;
2.第一个字符串等于第二个字符串,则返回0;
3.第一个字符串小于第二个字符串,则返回小于0的数字。4.在VS环境下,返回值为 1 0 -1,但是其他编辑器不一定。
(3)示例
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abq";
int ret1 = strcmp(arr1, arr2);//arr1小于arr2
printf("%d\n", ret1);
char arr3[] = "aba";
int ret2 = strcmp(arr1, arr3);//arr1大于arr3
printf("%d\n", ret2);
char arr4[] = "abcdef";
int ret3 = strcmp(arr1, arr4);//arr1等于arr4
printf("%d\n", ret3);
return 0;
}
(4)模拟实现
#include <stdio.h>
#include <string.h>
#include <assert.h>
int my_strcmp1(char * str1, const char * str2)
{
assert(str1&&str2);
//一个一个比较
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;//相等返回值为0
str1++;
str2++;
}
if (*str1 > *str2)//大于返回值大于0
return 1;
else //小于返回值小于0
return -1;
}
int my_strcmp2(char * str1, const char * str2)
{
assert(str1&&str2);
//一个一个比较
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;//相等返回值为0
str1++;
str2++;
}
return str1 - srt2;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abq";
char arr3[] = "aba";
char arr4[] = "abcdef";
int ret1 = my_strcmp1(arr1, arr3);//arr1小于arr2
printf("%d\n", ret1);
return 0;
}
上述是长度不受限制的字符串函数,仅仅靠'\0'来限制函数的比较长度,不安全。
下面三个函数是长度受限制的字符串函数,相对前三个函数是比较安全的。
1.5.strncpy
(1)功能:Copy characters from string, 从字符串中复制字符,复制字符串中num个字符的内容。
(2)使用形式:
char * strncpy ( char * destination, const char * source, size_t num );
size_t num ,无符号整型,num为复制字符的个数
注意:
1.拷贝num个字符从源字符串到目标字符串中;
2.如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。3.不会拷贝到'\0',只会按照num的个数来拷贝几个字符。
(3)示例
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "xxxxxxxxxx";
strncpy(arr2, arr1,6);
//num等于源字符串长度abcdefxxxx
//num小于目标字符串长度 例如5 abcdexxxxx
//num大于源字符串长度 10 abcdef,剩余位置会补上'\0',不会输出
printf("%s", arr2);
return 0;
}
(4)模拟实现
实现的要求
#include <stdio.h>
#include <string.h>
#include <assert.h>
char * my_strncpy(char * dest, const char * src, int num)
{
assert(dest&&src);
char * ret = dest;//返回值的为字符指针的形式
while (num)
{
if (*src == '\0')//当num大于src所有的字符串长度,会将\0复制过去
{
*dest++ = '\0';
}
else
{
*dest++ = *src++;//复制num小于等于字符串的长度
}
num--;
}
return ret;
}
int main()
{
char arr1[] = "abcdef";
char arr2[20];
char * ret = my_strncpy(arr2, arr1, 10);
printf("%s", arr2);
return 0;
}
1.6.strncat
(1)功能:Append characters from string,给字符串附加num个字符。
(2)使用形式:
char * strncat ( char * destination, const char * source, size_t num );
注意:
1.追加num个字符从源字符串到目标字符串中;
2.追加完成后会自动加上'\0';
3.目标空间足够容纳追加的字符串。
(3)示例
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
strncat(arr1, arr2,6);
printf("%s", arr1);
return 0;
}
(4)模拟实现
实现思路;
1.寻找目标字符的\0位置处
2.追加字符串;
3.完成之后追加 \0。
#include <stdio.h>
#include <string.h>
#include <assert.h>
char * my_strncat(char * dest, const char * src, int num)
{
char* ret = dest;
//寻找追加位置
while (*dest != '\0')
{
dest++;
}//此时dest指向的是'\0'的位置
//追加
while (num)
{
*dest++ = *src++;
if (*src == '\0')
{
num = 0;
}
}
*dest = '\0';
}
int main()
{
char arr1[20] = "hello ";
char arr2[20] = "world";
char * ret = my_strncat(arr1, arr2, 7);
printf("%s", arr1);
return 0;
}
1.7.strncmp
(1)功能:Compare characters of two strings ,比较字符串中指定num个字符大小。
(2)使用形式:
int strncmp ( const char * str1, const char * str2, size_t num );
需要注意的是比较和strcmp是相同的是一个字符一个字符的比较,
(3)示例
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abcqgy";
int ret = strncmp(arr1, arr2, 4);
printf("%d\n", ret);
return 0;
}
(4)模拟实现
#include <stdio.h>
#include <string.h>
#include <assert.h>
int my_strcmp(char * str1, const char * str2, size_t num)
{
assert(str1&&str2);
//一个一个比较
int i = num;
for (i = 0; i < num; i++)//判断大于和小于的
{
if (*str1++ > *str2++)
return 1;
else if(*str1++>*str2)
return -1;
}
return 0;//除去大于和小于只有等于了
}
int main()
{
char arr1[] = "abcd";
char arr2[] = "abc";
int ret = strncmp(arr1, arr2, 4);
printf("%d\n", ret);
return 0;
}
1.8.strstr
(1)功能:Locate substring 查找字符串中的字符位置。
(2)使用形式:
char * strstr ( const char * str1, const char * str2 );
注意:
1. 在第一个字符串中寻找第二个字符串第一次出现的地址,如果找到返回的是指针(str1出现str2的位置),没有找到返回的就是空指针。
2.没有找到的返回的指针就是空值,NULL (以地址的形式打印出来为00000000);
(3)示例
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "cd";
char * ret = strstr(arr1, arr2);
printf("%p", ret);
return 0;
}
(4)模拟实现
模拟实现的思路:
1.判断要寻找的字符串是否为空字符串,字符串中仅仅有'\0',返回空指针;
2.情况1: 在 abcdef 寻找 bc;一一比对需要一个循环结构;
3.情况2:在 abbcdef中寻找bc;需要寻找两次,所以需要一个循环循环。
#include <stdio.h>
#include <string.h>
#include <assert.h>
char * my_strstr(const char * str1, const char * str2)
{
assert(str1&&str2);
if (*str2 == '\0')
{
return (char*)str1;
}
const char * s1 = str1;
const char * s2 = str2;
const char * cp = str1;
while (*cp)
{
s1 = cp;
s2 = str2;
while (*s1 != '\0'&& * s2 != '\0'&& * s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cp;
}
cp++;
}
return NULL; //未找到的时候
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "cd";
char * ret = my_strstr(arr1, arr2);
if (ret == NULL)
{
printf("没有找到");
}
else
{
printf("找到了");
}
return 0;
}
1.9.strtok
(1)功能:Split string into tokens,根标记分割字符串。
(2)使用形式:
char * strtok ( char * str, const char * delimiters );
1.str是被分割的部分,delimiters是分隔符;
2.strtok函数找到str中的分隔符,将其用 \0 结尾,返回一个指向这个分隔符的指针。一次调用只能查找一个分隔符,后面的调用有些特殊请看5.6条。4.strtok会修改字符串的内容,将分割符号换成'\0',应该创建临时的数据拷贝完成。
5.查找第一个分隔符,函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
6.查找第二个以及后面的分隔符时,函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
7.如果字符串中不存在更多的标记,则返回 NULL 指针。
(3)示例
#include <stdio.h>
#include <string.h >
int main()
{
char arr[] = "123$456 789%";
char * p = "$ %";
char buf[20] = { 0 };
strcpy(buf, arr);
char * ret = NULL;
for (ret = strtok(buf, p); ret != NULL; ret = strtok(NULL, p))
{
printf("%s\n", ret);
}
return 0;
}
1.10.strerror
(1)功能:Get pointer to error message string 得到错误信息字符串的指针
(2)使用形式:
1.C语言的函数在运行的时候,如果发生错误,就会将错误存在一个变量中,变量为errno
这个变量是全局变量,当调用库函数出错的时候,将会把错误码赋值给errno;当然不及时的输出,errno也会更新的
2.错误码为一些数字 1 、2、3、4、5,等等,将错误码翻译成错误信息。
3.srerror函数的作用就是根据错误码找到错误信息的首地址,没有输出的功能。
(3)示例1
#include <stdio.h>
#include <string.h>
int main()
{
printf("%s\n", strerror(0));
printf("%s\n", strerror(1));
printf("%s\n", strerror(2));
printf("%s\n", strerror(3));
printf("%s\n", strerror(4));
printf("%s\n", strerror(5));
return 0;
}
输出结果:
示例2使用范例
fopen函数的使用
FILE * fopen ( const char * filename, const char * mode );
1.第一个参数是打开文件的名称,第二个参数是打开文件的形式;
2.打开文件成功返回有效指针,打开文件失败返回空指针;
#include <stdio.h>
#include <string.h >
#include <errno.h >
int main()
{
FILE * pf = fopen("test.txt", "r"); //读取的形式 打开文件test.txt寻找文件的路径可能在本工程文件里面
if (pf == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
//
//关闭文件
fclose(pf);
return 0;
}
1.fopen在未规划寻找路径的前提下,默认为当前工程文件下。
2.当调用库函数失败的时候,会给errno赋值。
2.字符函数
2.1字符分类函数
函数 | 如果他的参数符合下列条件就返回真 |
iscntrl | 任何控制字符 |
isspace | 空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v' |
isdigit | 十进制数字 0~9 |
isxdigit | 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F |
slower | 小写字母a~z |
isupper | 大写字母A~Z |
isalpha | 字母a~z或A~Z |
isalnum | 字母或者数字,a~z,A~Z,0~9 |
spunct | 标点符号,任何不属于数字或者字母的图形字符(可打印) |
isgraph | 任何图形字符 |
isgraph | 任何可打印字符,包括图形字符和空白字符 |
上述均是判断函数,判断为真返回非零数,判断不是返回值为0;
#include <stdio.h>
#include <ctype.h>
int main()
{
int ret = islower('a');
printf("%d\n", ret);
return 0;
}
2.2字符转换函数
int tolower ( int c );将大写字母转换成小写字母
int toupper ( int c );将小写字母转换成大写字母
字符的存储形式是ASCLL,本质上是int类型,因此上述式子没错。
tolower示例
#include <stdio.h>
int main()
{
char arr[] = "I Have An Apple";
int i = 0;
while (arr[i])
{
if (isupper(arr[i]))
{
printf("%c", tolower(arr[i]));//把转换的小写字母直接打印出来
}
else
{
printf("%c", arr[i]);
}
i++;
}
return 0;
}
toupper示例
#include <stdio.h>
int main()
{
char arr[] = "I Have An Apple";
int i = 0;
while (arr[i])
{
if (isupper(arr[i]))
{
printf("%c", toupper(arr[i]));//把转换的小写字母直接打印出来
}
else
{
printf("%c", arr[i]);
}
i++;
}
return 0;
}
3.内存函数
3.1.mencpy
(1)功能:Copy block of memory 拷贝内存函数。
(2)使用形式:
void * memcpy ( void * destination, const void * source, size_t num );
注意:
1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置;
2.函数不会识别'\0',只会按照第一条执行;3.void * 指针可以接受任何数据类型的指针,但是此指针无法使用,需要强制转换类型(在模拟实现函数的时候)。
(3)示例
将arr1中的前20个字节的内容复制到arr2中
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20];
memcpy(arr2, arr1, 20);
return 0;
}
(4)模拟实现
思路:按照字节来复制,将整型指针强制转换成字符指针,字符指针指向的就是一个字节,然后开始赋值。
#include <stdio.h>
#include <string.h>
void * my_memcpy(void * dest, const void * src, size_t num)
{
char * dest1 = (char *)dest;
char * src1 = (char *)src;
while (num)
{
*dest1++ = *src1++;
num--;
}
return dest;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
my_memcpy(arr2, arr1, 20);
int i = 0;
for (i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
3.2.memmove
(1)功能:Move block of memory
(2)使用形式:
void * memmove ( void * destination, const void * source, size_t num );
1.和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
2.如果源空间和目标空间出现重叠,就得使用memmove函数处理。
(3)示例
#include<stdio.h>
#include<string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr1 + 2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
(4)模拟实现
思路:
1.当dest指针比src指针低的时候如何处理;
2.当dest指针比src指针高的如何处理。(指针比较大小就是地址的高低)
#include<stdio.h>
#include<string.h>
void * my_memmove(void * dest, const void * src, size_t num)
{
char* ds = (char*)dest;//强制转换的字符指针
char* sr = (char*)src;
void* ret = ds;
if (ds >= sr)// dest的指针比src指针高或等于
{
while (num--)
{
*(ds + num) = *(sr + num);
}
}
else
{
while (num)
{
*ds++ = *sr++;
num--;
}
}
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr1, arr1+2, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
3.3.memcmp
(1)功能:Compare two blocks of memory,比较内存中的内容的大小。
(2)使用形式:
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
注意:
1.比较从ptr1和ptr2指针开始的num个字节;
2.当ptr1中的内容大于ptr2中的内容输出大于0值;
当ptr1中的内容小于ptr2中的内容输出小于0值;
当ptr1中的内容等于ptr2中的内容输出0.
(3)示例
#include<stdio.h>
int main()
{
int arr1[] = { 1,3,5 };//小端存储 01 00 00 00 03 00 00 00 05 00 00 00
int arr2[] = { 2,4,6 }; // 02 00 00 00 04 00 00 00 06 00 00 00
int ret = memcmp(arr1, arr2,5);
printf("%d", ret);
return 0;
}
(4)模拟实现
和strncmp类似
#include<stdio.h>
#include<string.h>
int my_memcmp(const void * str1, const void * str2, size_t num)
{
char* s1 = (char*)str1;
char* s2 = (char*)str2;
int i = 0;
for (i = 0; i < num; i++)
{
if (*s1 > *s2)
return 1;
else if (*s1 < *s2)
return -1;
}
return 0;
}
int main()
{
int arr1[] = { 1,3,5 };//小端存储 01 00 00 00 03 00 00 00 05 00 00 00
int arr2[] = { 1,3,5 }; // 02 00 00 00 04 00 00 00 06 00 00 00
int ret = my_memcmp(arr1, arr2, 5);
printf("%d", ret);
return 0;
}
3.4.memset
(1)功能:Fill block of memory,填充内存,设置内存函数
(2)使用形式
void * memset ( void * ptr, int value, size_t num );
(3)示例
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "hello word";
memset(arr, 'x', 5);
printf("%s\n", arr);
memset(arr + 6, 'x', 4);
printf("%s\n", arr);
return 0;
}