目录
字符串函数
求字符串长度函数——strlen
函数介绍
函数用法
模拟实现
长度不受限制的字符串函数
字符串拷贝函数——strcpy
函数介绍
函数用法
模拟实现
字符串追加函数——strcat
函数介绍
函数用法
模拟实现
字符串比较函数——strcmp
函数介绍
函数用法
模拟实现
长度不受限制的字符串函数
字符串拷贝函数——strncpy
函数介绍
函数用法
模拟实现
字符串追加函数——strncat
函数介绍
函数用法
模拟实现
字符串比较函数——strncmp
函数介绍
函数用法
字符串查找函数——strstr
函数介绍
函数用法
模拟实现
字符串分割函数——strtok
函数介绍
函数用法
字符串报错函数——sterror
函数介绍
函数用法
内存函数
内存拷贝函数——memcpy
函数介绍
函数用法
模拟实现
内存移动函数——memmove
函数介绍
函数用法
模拟实现
内存比较函数——memcmp
函数介绍
函数用法
内存初始化函数——memset
函数介绍
函数用法
size_t strlen(const char *str)
·字符串以'\0'作为结束标志,strlen函数返回的实在字符串中'\0'前面出现的字符个数(不包含'\0')
·参数指向的字符串必须要以'\0'结束
·主要函数的返回值为size_t,是无符号的(易错).
#include
#include
int main()
{
//1.
char arr1[] = "abcdef";
int len = strlen(arr1);
printf("%d\n", len);//6
//2.
char arr2[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
printf("%d\n", strlen(arr2));//随机值
//3.
char arr3[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
printf("%d\n", strlen(arr3[0]));//err
//4.打印hehe
const char *str1 = "abcdef";
const char *str2 = "bbb";
if (strlen(str2) - strlen(str1) > 0)
{
printf("hehe\n");
}
else
{
printf("haha\n");
}
return 0;
}
1.参数指向的字符串是以'\0'结束,满足strlen的要求
2.参数指向的字符串不是以'\0'结束,但是由于strlen的倔脾气必须要找到'\0'才肯结束,这里就会一直往后找,所以打印的就是随机值。
3.传的参数根本就不是地址,strlen以为传进来的a的ascii码值97就是地址,所以这里会发生错误。
4.由于stlen的返回值是size_t类型,也就是无符号类型,这里strlen(str2)的值为3,strlen(str1)的值为6,strlen(str2)-strlen(str1)的值为-3,但是由于strlen的返回值是size_t类型,我们知道
无符号数里的-3其实是一个很大的值(大于0的数),因此这里最后会打印hehe。
上面说的strlen函数的一些小细节希望大家能够记住哦,细节决定成败!!!
#include
//模拟strlen 计数器的方式
int My_Strlen(const char *p)
{
int count = 0;
while (*p)
{
p++;
count++;
}
return count;
}
//模拟strlen 不创建临时变量计数器
int My_Strlen(const char *p)
{
if (*p == '\0')
{
return 0;
}
else
{
return 1 + My_Strlen(p + 1);
}
}
//模拟strlen 指针-指针
int My_Strlen(char *p)
{
char *src = p;
while (*p)
{
p++;
}
return p - src;
}
int main()
{
char arr[10] = "abcdef";
int len = My_Strlen(arr);
printf("%d\n", len);
return 0;
}
字符串函数分为长度不受限制的字符串函数与长度受限制的字符串函数。长度受限制的字符串函数相较于长度不受限制的字符串函数会安全一些。下面我们来介绍长度不受限制的字符串函数吧。
char *strcpy( char *strDestination, const char *strSource );
·源字符串必须以'\0'结束
·会将源字符串的'\0'拷贝到目标空间
·目标空间必须足够大,以确保能存放源字符串
·目标空间必须可修改
#include
#include
int main()
{
//1.
char arr1[10] = "xxxxxx";
char arr2[] = "ac";
printf("%s\n", strcpy(arr1, arr2));//ac
//2.
char arr3[] = { 'a', 'b', 'c' };
printf("%s\n", strcpy(arr1, arr3));//err
//3.
char arr4[] = "abcccccccceeeeeeaaaa";
printf("%s\n", strlen(arr1, arr4));//目标空间不足以存放源字符串
//4.
const char arr[10] = "xxx";
char arr5[] = "aaa";
printf("%s\n", strcpy(arr, arr5));//目标空间不可修改
return 0;
}
1.源字符串是以'\0'结尾,目标空间可修改,目标空间足够大,满足strcpy的要求,所以这里会将源字符串的内容包含('\0')一同拷贝到目标空间。
2.源字符串不是以'\0'结尾,则strcpy就会向后一直访问到非法内存。
3.目标空间不足以存放源字符串的内容。
4.目标空间不可修改。
需要注意的是:我们在写代码时,应当避免出现后面三种情况。
#include
#include
char* My_Strcpy(char *dest, const char* src)
{
assert(dest&&src);
char *ret = dest;
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "abcdef";
char arr2[] = "okk";
printf("%s\n", My_Strcpy(arr1, arr2));
return 0;
}
char *strcat( char *strDestination, const char *strSource );
·源字符串必须以'\0'结束
·目标空间有足够的大,能容纳下源字符串的内容
·目标空间可修改
#include
#include
int main()
{
//1.
char arr[20] = "abcdef";
char arr1[] = "okk";
strcat(arr, arr1);
printf("%s\n", arr);//abcdefokk
//2.
char arr2[] = { 'a', 'b', 'c' };
strcat(arr, arr2);
printf("%s\n", arr);
//3.
char arr3[10] = "abcdefgh";
char arr4[] = "okkkk";
strcat(arr3, arr4);
printf("%s\n", arr3);
//4.
const char arr5[20] = "xxxxx";
char arr6[] = "okkk";
strcat(arr5, arr6);
printf("%s\n", arr5);
return 0;
}
1.源字符串以'\0'结束,并且目标空间足够大,能容纳下源字符串内容,目标空间可修改,符合strcat的要求所以最后打印的结果是abcdefokk。
2.源字符串没有以'\0'结束,因为strcat和strlen一样,必须要找到'\0'才肯停下来,所以这里会非法访问空间从而会发生错误。
3.目标空间不够大,不能够容纳源字符串的内容。
4.目标空间不可修改,同样不行。
以上就是strcat函数使用起来需要注意的细节了
#include
char *My_Stract(char *dest, const char *src)
{
assert(dest&&src);
char *ret = dest;
while (*dest)
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "abcdef";
char arr2[] = "okk";
printf("%s\n", My_Stract(arr1, arr2));
return 0;
}
int strcmp( const char *string1, const char *string2 );
二个字符串都必须以'\0'作为字符串的结尾,否则会发生越界访问
·标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
#include
#include
int main()
{
char arr[] = "abcdef";
char arr1[] = "abb";
char arr2[] = "abcdef";
char arr3[] = "abe";
printf("%d\n", strcmp(arr, arr1));//1
printf("%d\n", strcmp(arr, arr2));//0
printf("%d\n", strcmp(arr, arr3));//-1
return 0;
}
这里的字符串都以'\0'作结束,所以三次依次比较的结果是1,0,-1。作者用的编译器是VS2013,MSDN上面也说了当第一个字符串小于第二个字符串时,返回一个小于0的数(并不一定是-1)
当第一个字符串当于第二个字符串时,返回一个大于0的数(并不一定是1)
int My_Strcmp(const char *dest, const char*src)
{
assert(dest&&src);
while(*dest==*src)
{
if (*dest=='\0')
{
return 0;
}
dest++;
src++;
}
return *dest - *src;
}
int main()
{
char arr1[20] = "abcdef";
char arr2[] = "abb";
int len = My_Strcmp(arr1, arr2);
printf("%d\n", len);
if (len > 0)
{
printf(">\n");
}
else if (len == 0)
{
printf("=\n");
}
else
{
printf("<\n");
}
return 0;
}
char *strncpy( char *strDest, const char *strSource, size_t count );
·目标字符串空间够大,并且能修改
·如果源字符串的长度小于count,则拷完源字符串之后,在目标的后边追加\0,直到count个
#include
#include
int main()
{
char arr[20] = "abcdef";
char arr1[] = "obj";
strncpy(arr, arr1, 5);
printf("%s\n", arr);
return 0;
}
//模拟实现strncpy函数
char *My_Strncpy(char *dest, const char*src, size_t count)
{
assert(dest&&src);
char* ret = dest;
//count是无符号类型,当count小于源字符串长度时我们需要特别注意
while (count && (*dest = *src))
{
count--;
dest++;
src++;
}
while (count)
{
*dest++ = '\0';
count--;
}
return ret;
}
int main()
{
char arr[20] = "abcdef";
char arr1[] = "obj";
My_Strncpy(arr, arr1, 2);
printf("%s\n", arr);
return 0;
}
char *strncat( char *strDest, const char *strSource, size_t count );
int main()
{
char arr[20] = "abc\0xxxxxxx";
char arr1[] = "def";
strncat(arr, arr1, 5);
printf("%s\n", arr);
return 0;
}
源字符串应以'\0'结尾,在目标字符串的\0后面追加count个源字符串的字符,结尾会默认添加\0,若count超于源字符串的长度时,追加完源字符串之后便不会再追加其他内容。
#include
//模拟实现strncat
char *My_Strncat(char *dest, const char *src, size_t count)
{
assert(dest&&src);
char *ret = dest;//拿一个指针记录dest起始位置
//判断dest是否已经指向'\0'
while (*dest)
{
dest++;
}
while (count && (*dest++ = *src++))
{
count--;
}
//若count>源字符串长度,则不再增加,若小于则在后面主动添加一个'\0'
if (count == 0)
{
*dest = '\0';
}
return ret;
}
int main()
{
char arr[20] = "abc\0xxxxxxx";
char arr1[] = "def";
My_Strncat(arr, arr1, 2);
printf("%s\n", arr);
return 0;
}
int strncmp( const char *string1, const char *string2, size_t count );
·比较两个字符串的前count个字符,并返回相关的数值。
int main()
{
char arr[] = "abcdef";
char arr1[] = "abbd";
int len = strncmp(arr, arr1, 3);
printf("%d\n",len);
return 0;
}
char *strstr( const char *string, const char *strCharSet );
查找子字符串是否在目标字符串中,若存在则返回子字符串在目标字符串首次出现的位置,若不存在则返回空指针。
int main()
{
char arr[20] = "abdabcd ef";
char arr1[] = "abcd";
char arr2[] = "aaac";
char *ret = strstr(arr, arr1);
char *len = strstr(arr, arr2);
printf("%s\n", ret);
printf("%s\n", len);
return 0;
}
//模拟实现strstr字符串查找函数
char *My_Strstr(const char *dest, const char *src)
{
assert(dest&&src);
char *s1;
char *s2;
char *cp = dest;
//特殊情况
if (*src == '\0')
{
return dest;
}
while (*cp)
{
s1 = cp;
s2 = src;
while (*s1&&*s2&&*s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cp;
}
cp++;
}
//找不到
return NULL;
}
int main()
{
char arr1[] = "i am a good student, hehe student";
char arr2[] = "student";
//查找arr1中arr第一次出现的位置
char *ret = My_Strstr(arr1, arr2);
if (ret == NULL)
{
printf("找不到\n");
}
else
{
printf("%s\n",ret);
}
return 0;
}
char *strtok(char *str, const char *sep);
·sep参数是个字符串,定义了用作分隔符的字符集合
·第一个参数指定一个字符串,它包含了0个或者多个有sep字符串中一个或者多个分隔符分隔的标记
·strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针
·strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置
·strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记
·如果字符串中不存在更多的标记,则返回NULL指针
int main()
{
char arr[] = "www.yakjafg.com";
printf("%s\n", strtok(arr,"."));
printf("%s\n", strtok(NULL, "."));
printf("%s\n", strtok(NULL, "."));
return 0;
}
int main()
{
char arr[30] = "abc@jkajn-adf@nck";
char *ret = "@-";
char *str = NULL;
for (str = strtok(arr, ret); str != NULL; str = strtok(NULL, ret))
{
printf("%s\n", str);
}
return 0;
}
char *strerror( int errnum );
·返回错误码,所对应的错误信息
·当程序发生错误时,程序会自动将错误码存入内置全局变量errno中,此时我们调用strerror函数即可获得此次错误的报错信息
·更直接的报错函数perror,优点简单方便假如自定义信息,缺点就是必须打印错误信息
int main()
{
FILE *pFile;
pFile = fopen("unexist.ent", "r");
if (pFile == NULL)
{
printf("Error opening file unexist.ent:%s\n", strerror(errno));
return 0;
}
}
void *memcpy( void *dest, const void *src, size_t count );
·函数memcpy从src的位置开始向后复制num个字节的数据到dest的内存位置
·这个函数在遇到'\0'的时候并不会停下来
·如果src和dest有任何的重叠,复制的结果都是未定义的
·memcpy只要完成了不重叠的内存拷贝就算完成了它的任务
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
memcpy(arr + 4, arr, 16);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
void * My_Memcpy(void *dest, const void *src, size_t num)
{
void *ret = dest;
assert(dest&&src);
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
My_Memcpy(arr + 4, arr, 16);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
void *memmove( void *dest, const void *src, size_t count );
·和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的
·如果源空间和目标空间出现重叠,就得使用memmove函数来处理
int main()
{
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
memmove(arr+2, arr, 16);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
void * My_Memmove(void *dest, const void *src,size_t count)
{
assert(dest&&src);
void *ret = dest;
//dest在src的前面
if (dest < src)
{
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
//dest在src的后面
else
{
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
}
return ret;
}
int main()
{
int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
My_Memmove(arr+2, arr, 16);
for (int i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
int memcmp( const void *buf1, const void *buf2, size_t count );
·比较buf1和buf2开始的count个字节
·buf1小于buf2的话,返回小于0的数
·buf1等于buf2的话,返回0
·buf1大于buf2的话,返回大于0的数
int main()
{
int arr[] = { 1, 2, 3, 5, 6 };
int arr1[] = { 1, 2, 3, 4, 3 };
int len = memcmp(arr, arr1, 16);
printf("%d\n", len);
return 0;
}
这里我们比较了arr与arr1里面16个字节的内容,很明显arr是大于arr1的,返回了大于0的数,但并不是说返回大于0的数就一定要是1。当arr小于arr1时,返回小于0的数,也并不是说返回小于0的数就一定要是-1。
void *memset( void *dest, int c, size_t count );
将目标空间前count个字节的数据初始化为整型c
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 ,10};
memset(arr, 5, 16);//将arr数组内前16个字节的数据都初始化为5
return 0;
}
以上就是字符串与内存函数的所有内容了,码字不易如果觉得该内容对你有帮助的话,可以给作者点赞关注一波哦,你的点赞与关注就是对作者最大的支持。