字符函数及内存函数
- 一.字符串函数函数
- 1.strlen函数
- 2.strcpy函数
- 3.strcat函数
- 4.strcmp函数
- 5.strncpy函数
- 6.strncat函数
- 7.strncmp函数
- 8.strstr函数
- 9.strtok函数
- 10.strerror函数
- 二.内存函数
- 1.memcpy函数
- 2.memmove函数
- 3.memcpy函数
- 4.memset函数
一.字符串函数函数
1.strlen函数
size_t strlen ( const char * str );
作用: 计算字符串长度,返回的是字符串长度,无符号整数
- strlen()函数以\0作为结束标志,返回的是\0之前的字符个数,不包含\0
- 参数指向的字符串必须以\0结束
- 参数的返回值是一个无符号整数,所以在做差比较时要切记,防止负数但数值很大的情况
- strlen()函数模拟实现如下
//计数法
size_t my_strcopy(const char* str)
{assert(str != NULL);int count = 0;while (*str!='\0'){count++;str++;}return count;
}
2.strcpy函数
char* strcpy(char * destination, const char * source )
作用: 将源字符串拷贝到目标字符串中,返回的是目标字符串的地址
- 源字符串必须以\0结尾
- 会将源字符串中的\0拷贝到目标空间
- 目标空间足够大,以确保能放下源字符串
- 目标空间必须可变,不能是常量字符串,常量字符串不可变
- strcpy()函数模拟如下
char* my_strcopy(char* dest, const char* src)
{assert(dest != NULL);assert(src != NULL);char* result = dest;while (*src!='\0'){*dest = *src;dest++;src++;}*dest = *src;return result;
}
3.strcat函数
char * strcat ( char * destination, const char * source )
作用: 将源字符串拼接到目标字符串的后面,返回的是目标字符串的地址
- 源字符串必须以\0结束
- 目标空间必须足够的大,能容纳的下源字符串
- 目标空间必须可修改
- 切记该函数不能自己追加自己
- 模拟strcat()函数
char* my_strcat(char* dest, const char* src)
{assert(dest != NULL);assert(src != NULL);char* result = dest;while (*dest!='\0'){dest++;}while (*src != '\0'){*dest = *src;dest++;src++;}*dest = *src;return result;
}
4.strcmp函数
作用: 比较两个字符串的大小关系
int strcmp ( const char * str1, const char * str2 );
- 第一个数大于第二个数返回>0的数
- 第一个数小于第二个数返回<0的数
- 第一个数等于第二个数返回==0的数
- 模拟strcmp函数
int my_strcmp(const char* s1,const char* s2)
{assert(s1 != NULL);assert(s2 != NULL);while (*s1==*s2){if (*s1 == '\0'){return 0;}s1++;s2++;}if (*s1 - *s2 > 0){return 1;}else {return -1;}}
上面四种都是字符串长度不受限制的,下面介绍三种字符串长度受限制的
5.strncpy函数
char * strncpy ( char * destination, const char * source, size_t num )
- 可见比strcpy只是多了一个num的参数
- 此函数复制时,只会复制指定长度n个
- 若n>要复制的字符串长度,那么后面会复制\0
6.strncat函数
char * strncat ( char * destination, const char * source, size_t num )
- 可见只是比strcat多了一个长度限制参数
- 该函数会将指定长度num个字符拼接到目标函数后面,如果num>源字符串时,也只会拼接源字符串的长度个字符
- 该函数拼接完后,会在末尾拼接一个\0
7.strncmp函数
int strncmp ( const char * str1, const char * str2, size_t num )
- 该函数比strcmp函数多了一个参数num的长度限制
- 该函数只会比较num个字符
- 这num个字符相同就返回0,第一个字符大于第二个字符返回>0的数,第一个字符小于第二个字符返回<0的数
8.strstr函数
char * strstr ( const char *str1, const char * str2)
作用: 在一个字符串中查找指定子串存不存在,存在返回第一次出现的位置到结束的字符串
- 模拟实现strstr函数
char* my_strstr(const char* s1, const char* s2)
{assert(s1 != NULL);assert(s2 != NULL);char* position = s1;char* move1 = s1;char* move2 = s2;while (*position!=NULL){move1 = position;move2 = s2;while (*move1==*move2&&*move1!=NULL&&*move2!=NULL){move1++;move2++;}if (*move2 == NULL){return position;}position++;}
}
9.strtok函数
char * strtok ( char * str, const char * sep )
==作用:==将一个字符串按照特定的字符串进行分割
- const char* sep这个参数是一个字符串,定义了分隔符的集合
- 第一个参数是一个字符串,该字符串里面可以包含0个或多个分隔符字符
- strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。注:
strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容
并且可修改。 - 如果第一个参数不为NULL,那么该函数会找到该字符串中第一次出现该分隔符的位置,进行分割,并且记录下一次出现分隔符的位置
- 如果第一个参数为NULL,那么该函数会从下一次被标记的位置开始,进行分割
- 如果字符串中不存在更多的标记那么返回NULL
strtok函数的使用
int main()
{char s1[] = "LC@AI>Ming@666";char s2[] = { '@','>','\0' };char s3[30];strcpy(s3, s1);for (char* i = strtok(s3, s2);i != NULL;i = strtok(NULL,s2)){printf("%s\n", i);}
}
10.strerror函数
char * strerror ( int errnum )
==作用:==将程序中产生的错误码转为字符串,方便我们直到哪里有错
- 库函数在执行的时候,发生了错误会将一个错误码存放在errno这个变量中errno是C语言提供的一个全局的变量
- 参数为错误码,只要给一个错误码,就会返回当前错误码对应的错误信息
int main()
{FILE* pf = fopen("data.txt", "r");if (pf == NULL){printf("%s\n", strerror(errno));//perror(字符串);自带打印return 1;}fclose(pf);return 0;
}
- 这里我们在传错误码时,直接传errno,这个变量当程序发生错误时,会将错误存放在这个变量中
- printf(“%s\n”, strerror(errno))这句代码可以用perror()这个函数替换,perror()里面可以传一个参数,以确保我们知道哪里出了问题,它自带打印
//这两句代码等价
printf("fopen:%s\n", strerror(errno));
perror("fopen");
二.内存函数
下面是几个常用的内存函数
1.memcpy函数
void * memcpy ( void * destination, const void * source, size_t num )
作用: 拷贝内存中的数据
- 函数从source所指向的地址开始,复制num个字节数据到destination所指向的内存地址
- 这个函数在遇到\0时并不会停下来,因为它可以复制所有类型数据,与\0无关,与内存有关
- 如果source和destination有任何的重叠,复制的结果都是未定义的,即不能复制重叠部分的内容
- memcpy函数模拟实现
void* my_memcpy(void* dest, const void* src,size_t num)
{assert(dest != NULL);assert(src != NULL);void* result = dest;while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}return result;
}
2.memmove函数
void * memmove ( void * destination, const void * source, size_t num )
作用: 拷贝内存中的数据
- 和memcpy作用类似,但它可以拷贝重叠部分的内容,也可以拷贝不重叠部分的内容
- 如果源空间和目标空间出现重叠,就得使用memmove函数处理,如果没有重叠,两者都可以
- 模拟实现memmove函数
void* my_memmove(void* dest,const void* src,size_t num)
{assert(dest != NULL);assert(src != NULL);void* result = dest;if (dest < src){while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}}else {while (num--){*((char*)dest+num) = *((char*)src+num);}}return result;
}
3.memcpy函数
int memcmp ( const void * ptr1, const void * ptr2, size_t num )
作用: 两个数据进行比较,以内存字节为基准
- 按照一个一个字节比较,如果这些字节都相等就返回0.如果第一个字节大返回>0的数,如果第一个字节小返回<0的数
4.memset函数
void * memset ( void * ptr, int value, size_t num )
作用: 将ptr所指向的内存空间,按字节填充为value
- 这里要注意是将内存空间里的字节里的值填充为value,并不是将数据直接填充为value
比如我执行下面代码
int main()
{int arr[] = { 1,2,3,4,5 };memset(arr, 1, 20);for (int i = 0;i < 5;i++){printf("%d ", arr[i]);}
}
初学者看到,有可能会以为我是要将arr数组中的五个元素全部设置为1,但是实际上并不是,这样设置会将内存中每个字节都设置为1,结果是一个很大的数
而此时内存图如下:
可见该函数是以字节进行内存设置的,如果要将该数组全部填充为某一值(0除外),这个方法是不行的