1.strlen函数,通过字符串的地址计算其长度,遇到/0进行计算.
strlen函数的三种实现办法:
#include<stdio.h>
#include<assert.h>
//1.计数器办法
int my_strlen1(char* p)
{
int count = 0;
assert(p != NULL);
while (*p != '\0')
{
p++;
count++;
}
return count;
}
//2递归办法
int my_strlen2(char* p)
{
assert(p!= NULL);
if (*p =='\0')
{
return 0;
}
else
{
return 1 + my_strlen2(p + 1);
}
}
//指针相减法
int my_strlen3(char* p)
{
assert(p!= NULL);
char* ret = p;
while (*p!='\0')
{
p++;
}
return p - ret;
}
int main()
{
char arr[] = "abcdefgh";
int ret = my_strlen1(arr);
printf("%d\n", ret);
}
2.strcpy函数
strcpy(char*destination,const char*source)
//拷贝时会把‘\0’一起拷贝
//指标空间必须足够大
//指标空间必须可变
//实现strcpy函数
char* my_strcpy(char* dest, const char* source)
{
assert(dest);
assert(source);
char* ret = dest;
while (*dest++= *source++)
{
;
}
return ret;
}
3.strcat函数,用于拼接字符串
char*strcat(char* destination, const char* source);
//指标字符串的空间得足够大
//detsintaion中的‘\0’会被所拼接的字符串得首字符所笼罩
//source中的‘\0’也会被拷贝过来
char* my_strcat(char* dest, const char* src)
{
assert(dest);
assert(src);
char* ret = dest;
while (*dest!= '\0')
{
dest++;
}
while (*dest++ = *src++)//此时dest曾经指向了指标函数的'\0'处
{
;
}
return ret;
}
4、strcmp函数
int strcmp(const char *str1, const char *str2)
//两个字符串自左向右一一字符相比(按ASCII值大小相比拟),直到呈现不同的字符或遇'\0'为止
//当两个字符串不相等时,C规范没有规定返回值会是1 或 -1,只规定了负数和正数,在不同的编译器下返回的后果不同
//代码实现
int my_strcmp(char* str1, char* str2)
{
assert(str1);
assert(str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
{
return 0;//二者的字符始终相等,直到str1指向了'\0',比拟完结,则此时二者相等,所以返回0;
}
str1++;
str2++;
}
return(*str1 - *str2);//在遇到'\0'之前,二者便曾经不相等了,跳出循环,间接返回二者不相等处字符的ASCII码的差值来判断大小
}
5.strncpy函数
char *strncpy(char *destinin, char *source, int maxlen);
//用来向指标字符数组复制制订长度的字符串
//这个函数与strcpy先比更加平安
//对于strcpy函数的函数实现,简略的实现就是依照制订长度把src中的字符一个一个拷贝到dest中
char* my_strncpy(char* dest, char* src,int len)
{
assert(dest);
assert(src);
char* ret = dest;//保留指标函数的首元素地址
while (len--)
{
*dest++ = *src++;//依据制订长度,按序拷贝
}
return ret;
}
//但依据各种材料以及网上大牛对此函数的了解,在实现strcpy函数时还须要思考两种状况,即指定的长度大于源字符串的长度以及两个字符串内存重叠的状况
上面是思考了指定长度的函数实现
char* my_strncpy1(char* dest, char* src, int len)
{
assert(dest);
assert(src);
int offest = 0;//源字符串和指定长度的差值
char* ret = dest;
if (len > strlen(src))//len>strlen(src)的状况
{
int offest = len - strlen(src);
int len = strlen(src);//令strlen(src)=len
}
while (len--)
{
*dest++ = *src++;
}
while (offest--)
{
*dest++ = '\0';//将多出的局部全副赋值为'\0'
}
return ret;
}
6.strstr函数
strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回str2在str1中首次呈现的地址;否则,返回NULL。
//函数的代码实现
char* my_strstr(const char* p1, const char* p2)
{
assert(p1);
assert(p2);
char* s1 = NULL;
char* s2 = NULL;
char* cur = (char*)p1;//cur指针用来保匹配的起始地位
if (*p2 == '\0')//如果str2是空字符串,则进行匹配
{
return (char*)p1;
}
while (*cur)//判断cur是否为空指针
{
s1 = cur;//s1是能够挪动的指针,以cur为终点往后挪动进行比拟匹配
s2 = (char*)p2;//s2代替p2往后检索匹配
while (*s1 && *s2 && (*s1 == *s2))//在s1,s不为空且匹配胜利的状况下,二者持续往后检索进行字符匹配
{
s1++;
s2++;
}
if (*s2 == '\0')//str2曾经检索完,且所有字符都和str1匹配胜利
{
return cur;//找到子串了,返回cur的地址
}
if (*s1=='\0')
{
return NULL;//如果str1的长度小于str2的长度,则匹配失败,返回空指针
}
cur++;//在str1和str2第一次检索匹配失败后,cur后移一位,从新的终点和str1开始进行匹配
}
return NULL;//找不到子串
}
7.strerror函数
strerror()用来依参数errnum 的错误代码来查问其谬误起因的形容字符串, 而后将该字符串指针返回.
//错误码 错误信息
//0 No error
//1 Operation not permitted
//strerror的作用是把错误信息翻译
//errno是一个全局的错误码变量,当c语言的库函数在执行过程中产生谬误,就会把对应的错误码赋值到errno中
char* str = strerror(1);
printf("%s\n", str);
//关上文件
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));//给出没有找到这个文件的谬误的起因
}
else
{
printf("open file success\n");
}
}
8.内存操作函数:memcpy
memcpy函数:memcpy函数的性能是从源src所指的内存地址的起始地位开始拷贝n个字节到指标dest所指的内存地址的起始地位中
#include<stdio.h>
#include<memory.h>
#include<assert.h>
void*my_memcpy(void* dest, const void* src, size_t num)//本人实现一个memcpy函数,size_int num拷贝的字节数
{
void* ret = dest;//把首元素地址存起来,不便返回
assert(dest != NULL);
assert(src != NULL);
while (num--)//一个字节一个字节的拷贝
{
*(char*)dest = *(char*)src;//强转成char*类型,不便一个字节一个字节的拷贝
//++(char*)dest;
//++(char*)src;
dest = (char*)dest + 1;
dest = (char*)src + 1;
}
return ret;
}
//c语言规定:memcpy只解决不重叠的内存拷贝,memmove解决重叠内存的拷贝
int main()
{
//memcpy函数,返回值是void*通用型指针//能够拷贝任何类型的数据,但若目标数组和源数组有所重叠,则memcpy不实用所有状况
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
//my_memcpy(arr + 2, arr, 20);
memmove(arr + 2, arr, 20);//memmove()函数能够实现重叠拷贝,把12345拷贝到34567上,重叠拷贝
for ( i = 0; i < 10; i++)
{
printf("%d", arr[i]);
}
}
memmove函数:同memcpy函数性能相似,其函数原型为 void * memmove(void *dest, const void *src, size_t num);与memcpy的区别在于,memmove能够解决内存重叠的状况
void* my_memmove(void* dest, const void* src, size_t num)//函数实现
{
void* ret = dest;//把首元素地址存起来,不便返回
assert(dest != NULL);
assert(src != NULL);
if(dest<src)//此时从前往后拷贝
while (num--)//一个字节一个字节的拷贝
{
*(char*)dest = *(char*)src;//强转成char*类型,不便一个字节一个字节的拷贝
dest = (char*)dest + 1;
dest = (char*)src + 1;
}
else
{
//从后往前拷贝
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
图1为从前往后拷贝的状况,蓝色框代表src,黄色框代表dest,此时二者有重叠的局部,要把src中的内容拷贝到dest中,则只能从前往后拷贝,即依照程序把34567拷到23456所在的内存空间,如果逆序拷贝,即先拷贝7,则会导致7笼罩掉6,导致6无奈拷贝,其余元素亦然,所以只能正向拷贝,此时归类于dest<src的状况
图2中,dest位于src和src+count之间的状况,则须要,从后往前拷贝,如果正向拷贝则也会呈现后面一个元素笼罩前面元素,导致前面元素无奈拷贝的状况,逆向拷贝即依照76543的程序拷贝。逆向拷贝的具体代码实现:
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}//参考下图
因为须要一个字节一个字节的拷贝,零碎是依照小端模式存储的字符串,假如num一开始是20,
在循环刚开始便num--,此时num变为了19,则*((char*)src + num)指向src最初一个数字的
最初一个字节的起始地址,*((char*)dest + num)指向dest最初一个数字的最初一个字节的起始地址,再拷贝,就胜利将scr的最初一个字节拷贝到dest的最初一个字节,num--管制循环终止条件,则最终实现了逆向拷贝
图3中,若dest位于src+count之后,此时正向拷贝,逆向拷贝都不会呈现笼罩元素的状况
发表回复