字符串与内存函数

一、字符串操作函数
1.strlen函数
(1)'\0'不算进字符串长度
(2)字符串必须有'\0’结尾
(3)函数返回类型是size_t,无符号类型
int main()
{
    //char arr[] = "abc";
    char arr[] = { 'a','b','c' };
    int len = strlen(arr);//随机值
    printf("%d\n", len);
    return 0;
}

1.计数器版本
int my_strlen1(const char* str)
{
    assert(str);
    int count = 0;
    while (*str)
    {
        count++;
        str++;
    }
    return count;
}

2.递归版本
int my_strlen2(const char* str)
{
    if (*str)
    {
        return 1 + my_strlen2(str + 1);
    }
    return 0;
}

3.指针-指针版本
int my_strlen3(const char* str)
{
    const char* find = str;
    while (*find)
        find++;
    return find - str;
}

int main()
{
    char arr[] = "abcdef";
    printf("%d\n", my_strlen1(arr));
    printf("%d\n", my_strlen2(arr));
    printf("%d\n", my_strlen3(arr));
}

int main()
{
    //无符号数 - 无符号数 = 无符号数
    //unsigned int 3 - unsigned int 6 = (unsigned int)-3
    //10000000000000000000000000000011(原)
    //11111111111111111111111111111100(反)
    //11111111111111111111111111111101(补)
    //4294967293(很大的正数,一定 > 0)

    if (strlen("abc") - strlen("abcdef") > 0)
    {
        printf(">\n");
    }
    else
    {
        printf("<=\n");
    }
    return 0;
}


2.strcpy函数
(1)拷贝时直接将源字符串的'\0'也拷贝进了目标空间
(2)确保源字符串添加了'\0'结束
(3)确保目标空间有足够的空间存储源字符串
(4)目标空间必须可变
int main()
{
    char arr[10] = { 0 };
    arr = "hello";  //err! arr是首元素地址,应把hello放进arr所指向的空间而不是arr这个编号本身
    strcpy(arr, "hello");  //实际传参的是"hello"的首元素h地址
    
    char arr2[] = { 'a','b','c' };  //err! '\0'是拷贝结束的标志
    strcpy(arr, arr2);

    char arr[5] = { 0 };
    const char* p = "abcdef";
    strcpy(arr, p);  //err,超过了dest的个数,越界访问

    char *str = "############";  //目标空间不可变
    char* p = "abcdef";
    strcpy(str, p);

    return 0;
}

void my_strcpy(char* str1, const char* str2)
{
    while (*str2)
    {
        *str1++ = *str2++;
    }
    *str1 = *str2;
}
int main()
{
    char arr[20] = { 0 };
    const char* arr2 = "abcdef";
    my_strcpy(arr, arr2);
    puts(arr);
}


3.strcat函数 - 字符串追加(连接)
(1)源字符串必须以\0结束
(2)目标空间必须足够大,能容纳下源字符串的内容
(3)目标空间必须可修改

int main()
{
    char arr[20] = "hello \0############";
    //strcat(arr, "world");
    //my_strcat(arr, "world");
    //hello \0############\0
    //      world\0
    //hello world\0#######\0
    //printf("%s\n", arr);
    printf("%s\n", my_strcat(arr, "world"));
    //没有打印#,说明字符串里\0也被追加到了第一个\0后面
    return 0;
}

int main()
{
    char arr[20] = "abcd";
    strcat(arr, arr);  //err!
    //abc\0
    //abca
    //abcab
    //abcabcabc.....找不到\0
    printf("%s\n", arr);
    return 0;
}

char* my_strcat(char* dest, const char* src)
{
    assert(dest && src);
    char* cp_dest = dest;
    //1.找到目标字符串中的\0
    while (*cp_dest)
    {
        cp_dest++;
    }
    //2.追加源字符串,包括'\0'
    while (*cp_dest++ = *src++)
    {
        ;
    }
    return dest;  //返回目标空间的起始地址
}


4.strcmp函数
int main()
{
    //char p[] = "abcccc";
    char q[] = "abcdef";
    //if (p > q)   //0x00AFF834 0x00AFF824
    //    printf(">\n");
    //else
    //    printf("<\n");
    int ret = strcmp(q, "aaa");
    printf("%d\n", ret);
    return 0;
}

int my_strcmp(const char* str1, const char* str2)
{
    assert(str1 && str2);
    while (*str1 == *str2 && *str1)
    {
        str1++;
        str2++;
    }
    return *str1 - *str2;
}
int main()
{
    const char* p = "abcdef";
    const char* q = "abcccc";
    //int ret = strcmp(p, q);
    int ret = my_strcmp(p, q);
    if (ret > 0)
    {
        printf("p > q\n");
    }
    else if (ret < 0)
    {
        printf("p < q\n");
    }
    else
        printf("p == q\n");
}

strcpy -                             strncpy
strcat -                             strncat
strcmp -                             strncmp
长度不受限制的字符串函数             长度受限制的字符串函数


strncpy函数 - 长度受限制
char* my_strncpy(char* str1, const char* str2, size_t count)
{
    char* start = str1;
    while ((*str1 = *str2) && count)
    {
        str1++;
        str2++;
        count--;
    }
    if (count)
        while(count--)
    {
        *str1++ = '\0';
    }
    return start;
}

int main()
{
    char arr1[20] = "abcdefghi";
    char arr2[] = "qwer";
    //strncpy(arr1, arr2, 2);
    //printf("%s\n", arr1);  //qwcdefghi
    //strncpy(arr1, arr2, 6);  //如果拷贝的个数超过了arr2的长度,则补'\0'
    my_strncpy(arr1, arr2, 6);
    printf("%s\n", arr1);  //qwcdefghi
    return 0;
}

strncat - 长度受限制
char* my_strncat(char* str1, char* str2, size_t count)
{
    char* start = str1;
    while (*str1++)
        ;
    str1--;
    while (count && (*str1 = *str2))
    {
        str1++;
        str2++;
        count--;
    }
    if (count)
    {
        while (count--)
            if ((*str1++ = *str2++) == '\0')
                return start;
    }
    *str1 = '\0';
    return start;
}
int main()
{
    char arr1[30] = "hello \0####################";
    //                     world\0      (追加5个)
    //               hello world\0###############
    char arr2[] = "worldlife";
    //strncat(arr1, arr2, 15);  //连接arr2的k个字符到arr1之后,在arr1添加\0
    my_strncat(arr1, arr2, 15);
    printf("%s\n", arr1);
}

strncmp - 限制长度
int my_strncmp(const char* str1,const char* str2, size_t count)
{
    while (*str1 == *str2 && *str1 && --count)
    {
        str1++;
        str2++;
    }
    return *str1 - *str2;
}
int main()
{
    const char* p = "abcdef";
    const char* q = "abcqwert";
    //int ret = strcmp(p, q);
    //int ret = strncmp(p, q, 3);
    int ret = my_strncmp(p, q, 3);
    printf("%d\n", ret);
}

5.strstr函数 - 在一个字符串中找另一个字符串出现的位置
int main()
{
    char arr1[] = "abcdefabcdef";
    char arr2[] = "bcd";
    //在arr1中查找是否包含arr2字符串,如果arr2是arr1子串则返回arr2第一次出现的位置,如果找不到则返回空指针
    char* ret = strstr(arr1, arr2);
    if (ret)
    {
        printf("找到了:%s\n",ret);
    }
    else
    {
        printf("没找到\n");
    }
    return 0;
}


char* my_strstr(char* str1, const char* str2)
{
    assert(str1 && str2);
    char* cp_str1 = NULL;
    const char* cp_str2 = NULL;

    while (*str1)
    {
        cp_str1 = str1;
        cp_str2 = str2;
        while (*cp_str1 == *cp_str2 && !*cp_str2)
        {
            cp_str1++;
            cp_str2++;
        }
        if (*cp_str2)
            return str1;
        str1++;
    }

    //int len = strlen(str2);
    //while (*str1)
    //{
    //    if (*str1 == *str2)
    //    {
    //        if (strncmp(str1, str2, len)==0)
    //        {
    //            return str1;
    //        }
    //    }
    //    str1++;
    //}
    //return NULL;
}

int main()
{
     char arr1[] = "abcdef";
    char arr2[] = "abc";
    //在arr1中查找是否包含arr2字符串,如果arr2是arr1子串则返回arr2第一次出现的位置,如果找不到则返回空指针
    char* ret = my_strstr(arr1, arr2);
    if (ret)
    {
        printf("找到了:%s\n", ret);
    }
    else
    {
        printf("没找到\n");
    }
    return 0;
}


6.strtok函数 - 字符串切割

zpw@biteedu.cn
分隔符:@.
zpw
bitedu
tech

192.168.3.122
192
168
3
122

char* strtok(char* str , const char* sep)
                         sep参数是个字符串,用作分隔符的字符集合
第一个参数指定一个字符串,它包含了0个或者多个sep字符串中的一个或多个分隔符分割的标记

1. strtok找到str中的下一个标记,并将其用'\0'结尾,返回一个指向这个标记的指针(返回的是查找的初始元素(第一个分隔符的下一个元素)的地址)
   (strtok函数会改变被操作的字符串,所以在调用的时候最好传tmp数组做拷贝)
2. strtok的第一个参数不为NULL,函数将找到str中的第一个标记,strtok函数将保存它在字符串中的位置
   strtok的第一个参数为NULL,函数将在同一个字符串被保存的位置开始,查找下一个标记
   找不到则返回NULL

int main()
{
    char arr[] = "Lucid Winter@163.com";
    //拷贝str做切割
    char tmp[30] = { 0 };
    strcpy(tmp, arr);
    const char* p = "@. ";
    char* ret = NULL;
    for (ret = strtok(tmp, p); ret ; ret = strtok(NULL,p))
    {
        printf("%s\n", ret);
    }
    return 0;
}

7.strerror函数 - 把错误码转换成错误信息,需要的时候自己%s形式打印
调用库函数失败的时候,都会设置错误码
strerror将错误码翻译成错误信息,以char*字符串形式的字符串打印出来
errno是全局的错误码,头文件<errno.h>
char* strerror(int errno);

#include <errno.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));
    FILE* pf = fopen("test.txt", "r");
    if (pf == NULL)  //如果调用(打开文件)失败,返回空指针,自动就把错误码放到全局变量errno里面
    {
        printf("%s", strerror(errno));
        return 1;
    }
    //...
    //关闭文件
    fclose(pf);
    pf = NULL;
    return 0;
}

8.perror函数 - 直接打印错误信息 - print error
void perror(const char* str)
1.首先把错误码转换成错误信息
2.打印错误信息(包含自定义信息)

int main()
{
    FILE* pf = fopen("testing.txt", "r");
    if (pf == NULL)
    {
        perror("fopen is error");  //fopen:No such file or directory
                                   //把你编写的自定义信息打印之后打印':',再打印错误信息
        return 1;
    }
      return 0;
}


二、字符操作函数

1.字符分类函数
如果符合条件返回非0的值,如果不符合条件则返回0
iscntrl - 任何控制字符
isspace - 空白字符:空格'',换页'\f',换行'\n',回车'\r',制表符'\t'或者垂直制表符'\v'
isdigit - 十进制数字0-9
isxdigit - 十六进制数字,包括0-9,a-f,A-F
islower - 小写字母a-z
isupper - 大写字母A-Z
isalpha - 字母a-z或A-Z
isalnum - 字母或者数字,a-z,A-Z,0-9
ispunct - 标点符号,任何不属于数字或者字母的图形字符
isgragh - 任何图形字符
isprint - 任何可打印字符,包含图形字符和空白字符

int main()
{
    //char ch = '2';
    //int ret = isdigit(ch);  //如果是数字字符返回非0的值,如果不是数字字符,则返回0
    char ch = 'A';
    int ret = islower(ch);
    printf("%d\n",ret);
    return 0;
}


2.字符转换函数
int main()
{
    char arr[20] = { 0 };
    fgets(arr, 20, stdin);
    char* p = arr;
    while (*p)
    {
        if (isupper(*p))
        {
            *p = tolower(*p);
        }
        putchar(*p++);
    }
    return 0;
}


三、内存函数
1.memcpy() - 内存拷贝
void* memcpy(void* destination , const void* source, size_t num);
num是要拷贝的字节数
memcpy - 只要实现了不重叠拷贝就行了,而VS中的实现既可以拷贝不重叠,也可以拷贝重叠内存
void* my_memcpy(void* dest, const void* src, size_t num)
{
    assert(dest && src);
    char* cp_dest = (char*)dest;
    char* cp_src = (char*)src;
    while (num--)
    {
        *cp_dest++ = *cp_src++;
        //*(char*)dest++ = *(char*)src++;  //错误!char*强制类型转换是一个状态,后置++已经没有了强制类型转换这个状态
    }
    return dest;
}
int main()
{
    int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    int arr2[10] = { 0 };
    //char* strcpy(char* dest,const char* src);  //数组类型不同而且\0的值是整型0会导致拷贝错误,无法拷贝整型!
    //memcpy(arr2, arr1, sizeof(int) * 5);
    int n = 0;
    scanf("%d", &n);
    //my_memcpy(arr2, arr1, sizeof(int) * n);
    //my_memcpy(arr1+2, arr1, sizeof(int) * n); - 12121218910,错误
    int i = 0;
    for (i = 0; i < sizeof(arr1)/sizeof(arr1[0]); i++)
    {
        printf("%-2d ", arr1[i]);
    }
    printf("\n");
    for (i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
    {
        printf("%-2d ", arr2[i]);
    }
    return 0;
}

2.memmove() - 处理内存重叠的情况
void* memmove(void* dest, const void* src, size_t num);
void* my_memmove(void* dest, const void* src, size_t num)
{
    size_t cp_num = num;
    char* cp_src = (char*)src;
    char* cp_dest = (char*)dest;
    char* p = (char*)malloc(sizeof(char) * cp_num);
    char* rec = p;
    char* free_p = p;
    while (cp_num--)
    {
        *p++ = *cp_src++;
    }
    while (num--)
    {
        *cp_dest++ = *rec++;
    }
    free(free_p);
    return dest;
}

void* my_memmove(void* dest, const void* src, size_t num)
{
    char* cp_dest_last = (char*)dest + num;
    char* cp_src_last = (char*)src + num;
    char* cp_dest_first = (char*)dest;
    char* cp_src_first = (char*)src;
    while (num-- && dest<(char*)src+num-1)
    {
        *(cp_dest_last--) = *(cp_src_last--);
    }
    while (num--)
    {
        *(cp_dest_first++) = *(cp_src_first++);
    }
    return dest;
}

void* my_memmove(void* dest, const void* src, size_t num)
{
    assert(dest&&src);
    char* cp_dest_first = (char*)dest;
    char* cp_src_first = (char*)src;
    //dest落在src的整个范围左侧时,从前向后
    //dest落在src的整个范围内时,从后向前
    //dest落在src的整个范围右侧时,无所谓,假设从后向前
    //综上,dest<src,从前向后 ; dest>=src,从后向前
    if (dest < src)
    {
        //前->后
        while (num--)
        {
            *cp_dest_first++ = *cp_src_first++;
        }
    }
    else
    {
        //后->前
        while (num--)
        {
            *(cp_dest_first+num) = *(cp_src_first+num);
        }
    }
    return dest;
}
int main()
{
    int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
    //my_memmove(arr1, arr1+2, sizeof(int) * 5);
    memcpy(arr1+2, arr1, sizeof(int) * 5);
    return 0;
}

3.memcmp - 内存比较
int memcmp(const void* ptr1, void* ptr2, size_t num)
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
    while(*(char*)ptr1==*(char*)ptr2 && num--)
    {
        ;
    }
    return *(char*)ptr1 - *(char*)ptr2;
}
int main()
{
    float arr1[] = { 1.0,2.0,3.0,4.0 };
    float arr2[] = { 1.0,3.0 };
    int ret = memcmp(arr1, arr2, 4);
    printf("%d\n", ret);
}

4.memset - 内存设置
void* memset(void* ptr, int value, size_t num);
void* my_memset(void* ptr, int value, size_t num)
{
    char* cp_ptr = (char*)ptr;
    while (num--)
    {
        *cp_ptr++ = value;
    }
    return ptr;
}
int main()
{
    int arr[10] = { 0 };
    memset(arr, 1, 20);  //以字节为单位设置内存,因此监视不方便看(一个int为4个字节)
    //如果要以元素为单位进行memset,只能对字符数组进行
    char ch[10] = { 0 };
    memset(ch, 'a', 9);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值