size_t strlen(const char*string);
头文件:
功能:
计算字符串的长度,遇到'\0'便停止,统计'\0'之前字符的个数。
模拟实现:
//创建临时变量实现
int my_strlen(char* arr)
{
int count = 0;
while (*arr)
{
arr++;
count++;
}
return count;
}
//指针-指针实现
int my_strlen(char* arr)
{
char* str = arr;
while (*str)
{
str++;
}
return str - arr;
}
//递归实现
int my_strlen(char* arr)
{
if (*arr != '\0')
return 1 + my_strlen(++arr);
else
return 0;
}
int main()
{
char arr[] = "abcdef";
int ret = my_strlen(arr);
printf("%d\n", ret);
return 0;
}
int main()
{
char arr[] = "abcdef";
int ret = my_strlen(arr);
printf("%d\n", ret);
return 0;
}
char*strcpy(char*strDestination,const char*strSource);
头文件:
功能: 将strSource对应的字符串(源字符串)复制到strDestination对应的地址空间(目标空间)中
注意:
目标空间必须足够大
目标空间必须可以被修改
源字符串必须以 '\0' 结束
会将源字符串中的 '\0' 拷贝到目标空间
内存监视:会发现'\0'确实也拷贝到了新的数组中
模拟实现:
char* my_strcpy(char* arr1, char* arr2)
{
char* str = arr1;
while (*arr1++ = *arr2++)
{
;
}
return str;
}
int main()
{
char arr1[20] = "xxxxxxxxxx";
char arr2[] = "abcd";
char* str=my_strcpy(arr1, arr2);
printf("%s\n", str);
return 0;
}
char* strcat(char* strDestination,const char* strSource);
头文件:
功能: 将strSource对应字符串(源字符串)连接到strDestination所指向字符串尾部
注意:
目标空间必须足够大
目标空间必须可变
连接会从目标空间的'\0'开始
源字符串必须以'\0'结束
源字符串的‘\0’也会被复制到目标空间
然而如果字符串自己给自己追加就会出现问题
模拟实现:
#include
char* my_strcat(char* arr1, const char* arr2)
{
assert(arr1 && arr2);
char* str1 = arr1;
while (*arr1)
{
arr1++;
}
while (*arr1++ = *arr2++)
{
;
}
return str1;
}
int main()
{
char arr1[20] = "xxxxxx";
char arr2[4] = "def";
char* str = my_strcat(arr1, arr2);
printf("%s", str);
return 0;
}
int strcmp(const char*string1, const char*string2);
头文件:
功能 :比较字符串的大小(一个个字符依次比较)
string1>string2 |
返回大于0的数字 |
string1==string2 |
返回0 |
string1 |
返回小于0的数字 |
而在VS这种编译器下,
string1>string2 |
返回1 |
string1==string2 |
返回0 |
string1 |
返回-1 |
模拟实现:
int my_strcmp(const char* arr1, const char* arr2)
{
assert(arr1&&arr2);
if (*arr1 == *arr2 && *arr1 == '\0')
return 0;
while (*arr1 == *arr2 )
{
arr1++;
arr2++;
}
if(*arr1>*arr2)
return 1;
else if(*arr1<*arr2)
return -1;//VS上的写法
//return *arr1 - *arr2;//其他编译器上的写法
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abcq";
int ret = my_strcmp(arr1, arr2);
if (ret == 0)
printf("arr1==arr2.\n");
else if (ret > 0)
printf("arr1>arr2.\n");
else
printf("arr1
char*strncpy(char*strDest,constchar*strSource,size_tcount);
头文件:
功能:
从源字符串中拷贝count个字符到目标空间
如果源字符串的长度小于count,则拷贝完后在目标的后面补'\0',直到count个为止
模拟实现:
char* my_strncpy(char* arr1, char* arr2, int num)
{
assert(arr1 && arr2);
char* dst=arr1;
while (*arr2!='\0' && num>0)
{
*arr1++ = *arr2++;
num--;
}
while (num)
{
*arr1 = '\0';
arr1++;
num--;
}
return dst;
}
int main()
{
char arr1[] = "xxxxxxxx";
char arr2[] = "abcd";
char* str = strncpy(arr1, arr2, 6);
printf("%s\n", str);
return 0;
}
char* strncat(char*strDest,constchar*strSource,size_tcount);
头文件:
功能:将源字符串的count个字符追加到目标空间对应字符串末尾(从'\0'开始)
若追加元素个数小于源字符串的长度,会在追加count个字符之后再加上一个'\0'
模拟实现:
char* my_strncat(char* arr1, const char* arr2, int num)
{
assert(arr1 && arr2);
char* str = arr1;
while (*arr1 != '\0')
{
arr1++;
}
while (*arr2!='\0'&&num>0)
{
*arr1++ = *arr2++;
num--;
}
if(num==0)
*arr1='\0';
while (num--)
{
*arr1++ = '\0';
}
return str;
}
int main()
{
char arr1[20] = "xxxxxxxxx";
char arr2[] = "abdes";
char* dst = my_strncat(arr1, arr2, 6);
printf("%s\n", dst);
return 0;
}
int strncmp(constchar*string1,constchar*string2,size_tcount);
头文件:
功能:比较两个字符串count个字符的大小(一个个字符依次进行比较)
模拟实现:
int my_strncmp(const char* arr1, const char* arr2, int num)
{
assert(arr1 && arr2);
while (*arr1 == *arr2&&num>0)
{
if (*arr1 == '\0')
return 0;
//if (num == 0)
// return *arr1 - *arr2;
arr1++;
arr2++;
num--;
}
//情况1:*arr1!=*arr2跳出循环
if (num != 0)
return *arr1 - *arr2;
//情况2:由于num==0跳出循环
else if (num == 0)
return 0;
}
int main()
{
char arr1[] = "abcdptr";
char arr2[]="abcdeh";
int ret = my_strncmp(arr1,arr2,5);
if (ret > 0)
printf("arr1>arr2\n");
else if (ret == 0)
printf("arr1==arr2\n");
else
printf("arr1
char*strstr(constchar*str1,constchar*str2);
头文件:
功能: 在str1对应字符串中寻找str2对应字符串是否存在,若存在则返回str2在str1中对应位置的起始位置,若不存在则返回NULL
模拟实现:
char* my_strstr(const char* arr1, const char* arr2)
{
char* pc1 = (char*)arr1, *pc2 = (char*)arr2;
if (*arr2 == '\0')
return pc1;
while (*arr1 != '\0')
{
while (*arr1 == *arr2)
{
arr1++;
arr2++;
if (*arr2 == '\0')
{
return pc1;
}
}
arr2 = pc2;
pc1++;
arr1 = pc1;
}
return NULL;
}
int main()
{
char arr1[] = "abbcdef";
char arr2[] = "bcde";
char* ret=my_strstr(arr1, arr2);
if (ret != NULL)
printf("%s\n", ret);
else
printf("no find!\n");
return 0;
}
char*strtok(char*strToken,constchar*strDelimit);
头文件:
功能:分割字符串,其中 strDwlimit是存放分隔符的字符串;若找到其中的分隔符则将分隔符改为'\0'
返回值:1.字符串 strToken不为空,如果找到对应的分隔符,则返回分隔符之前字符串的首地址(指向 标记开头的指针);如果到达字符串末尾'\0'则返回NULL;
2.若字符串 strToken为空,则返回空指针NULL
注意:第一次传参时第一个字符指针传递字符串的地址,但在第二次及之后传参时,传递NULL,因为在找到分隔符后函数会记录并标记相关地址,以便后续查找。
char*strerror(interrnum);
头文件:
功能: 打印错误信息
补充:C语言的库函数在运行时,如果发生错误,就会将错误码存在一个变量中,这个变量是:errno 错误码是一些数字:1 2 3 4 5 ,而我们为了明白错误,需要将错误码翻译成错误信息。使用strerroe函数就可以将错误信息的地址返回,从而打印出错误信息。
同时有一个和strerror类似的也是打印错误信息的函数perror
void perror(const char *string);
头文件:
功能: 直接打印错误信息,但在打印错误信息之前会打印自定义的信息。
strerror与perror用法比较:
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)//判断是否读取成功
{
printf("%s\n", strerror(errno));
//使用strerror函数要将错误码作为参数传参
perror("fopen");
//使用perror函数则直接传递自定义信息即可
}
//读文件
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
字符分类函数
字符转换函数
int tolower(int c);//大写变小写
int toupper(int c);//小写变大写
来看一个题目:
如何将一串字符串都变为小写?
如何将一串字符串都变为大写?
因此字符串函数是只针对字符串而言的,不具有普遍性,因此引出针对所有类型而言的内存函数
void*memcpy(void*dest,constvoid*src,size_tcount);
头文件:
功能:实现任意类型数据的拷贝,以src指向的地址为起点,将连续的n个字节数据,复制到以dest指向的地址为起点的内存中。
返回值:目标空间起始地址
模拟实现:
void* my_memcpy(void* dest, const void* src, size_t count)
{
assert(dest && src);
void* ret = dest;
//写法1:通过char*型的指针分别接收源地址和目标地址,再进行操作
char* dst = (char*)dest;
char* str = (char*)src;
while (count)
{
*dst = *str;
dst++;
str++;
count--;
}
//写法2:通过直接强制类型转换进行操作
//while (count)
//{
// *(char*)dest = *(char*)src;
// dest = (char*)dest + 1;
// src = (char*)src + 1;
// //(char*)dest++;
// //这种强制类型转换只是临时的,在转换之后便会复原
// //因此是错误的
// count--;
//}
return ret;
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7 };
int arr2[10] = { 0 };
void* ret = my_memcpy(arr2, arr1, 16);
for (int i = 0; i < 4; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
这种写法很可能在某些情况下出现问题:
当src与dest所指向的内容有所重叠的时候,如果还是按照从前向后的顺序可能拷贝不成功
eg:将arr1数组中的1,2,3,4,5拷贝至3,4,5,6,7时
出现这种情况的原因是在从前向后拷贝时会把还未拷贝的数据覆盖,从而导致无法达到预期效果
我们来分析一下dest与src位置与拷贝顺序的关系,会发现可以分为三种情况:
当dest在src之前时,由前至后拷贝
当dest在src所指向要拷贝内容的起始位置与终端位置之间时,由后至前拷贝
当dest在src所指向要拷贝内容的末端位置之后时,由前至后拷贝与由后至前拷贝都是可行的
由此我们引出memmove函数
void*memmove(void*dest,constvoid*src,size_tcount);
头文件:
功能:拷贝src在内存对应内容的count个字节到dest中,可以实现重叠内存的拷贝。
模拟实现:由于上面提到三种情况中,第二种和第三种都可以用由后->前的思路来实现,为了简便我们分为dest
void* my_memcpy(void* dest, const void* src, size_t count)
{
assert(dest && src);
void* ret = dest;
//由前->后
if (dest < src)
{
while (count)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
count--;
}
}
//由后->前
else
{
while (count--)
{
*((char*)dest + count) = *((char*)src + count);
}
//最后因此count为1判断为真,之后--变为0进入循环,第一个字节也有拷贝过去
}
return ret;
}
int main()
{
int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
void* ret = my_memcpy(arr1 + 2, arr1, 20);
for (int i = 2; i < 7; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
但很多编译器上也将memcpy设置为可重叠拷贝的函数,使用时可以选择都用memmove函数,也可以选择在重叠时用memmove,不重叠用memcpy。
void* memset(void* dest,int c,size_t count);
头文件:
功能:内存设置函数,以字节为单位来设置内存中的数据,将dest在内存中对应count个字节的内容改为c
使用:
int main()
{
char arr[] = "hello world";
memset(arr, 'x', 5);
printf("%s\n", arr);
memset(arr+6, 'y', 5);
printf("%s\n", arr);
//int arr[10] = { 0 };
//memset(arr, 0, 40);
//一般初始化为0如果初始化内容超过一字节在使用时可能会出现问题
return 0;
}
int memcmp(const void*buf1,const void*buf2,size_t count);
头文件:
功能: 比较buf1与buf2内存块的count个字节的内容
前两个参数就是要比较的内存块的地址;
第三个参数就是要比较的字节数。
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 1,2,3,0,0 };
int ret = memcmp(arr1, arr2, 12);
printf("%d\n", ret);
return 0;
}
//前12个字节的内容都一样,所以返回0
注意:这里比较的以字节为单位的,所以是要牵扯到大小端存储的
不太了解大小端的宝宝们可以看看这篇文章http://t.csdn.cn/5QaTY
以arr1数组为例:
若是小端存储则:
若是大端存储则:
12字节无论是大端还是小端都是相等的
若是访问11字节内容:
小端存储:
大端存储: