<string.h>的学习

目录

一、局限性(特指用到字符串的函数)

1.strlen()函数

2.strcpy()函数

3.strcat()函数

4.strcmp()函数

5.strncpy()函数

6.strncat()函数

7.strncmp()函数

8.my_strstr()函数实现

9.strtok()函数

10.strerror()函数

11.总结上述

二、解决局限性

1.memcpy()函数

2.memmove()函数

3.memcmp()函数

4.memset()函数

三.好用的库函数


一、局限性(特指用到字符串的函数)

1.strlen()函数

  • //strlen()函数的使用
  • //字符串中以'\0'为结束标志,其返回值数字个数不包括'\0'
  • //参数指向的字符串必须要有'\0'作为结束
  • //注意函数的返回值为size_t,是无符号(易错)
  • //my_strlen()实现  请回看计算字符串不同方式

#include <stdio.h>
#include <string.h>
//判断以下输出?
//答:你没看错,就是输出为hehe
//应为strlen的返回值是 size_t == unsigned int
//即 3 - 6 = 3
//为正数即打印 hehe,而不是haha
int main()
{
    if((strlen("abc") - strlen("abcdef"))>0)
    {
        printf("hehe");
    }
    else
    {
        printf("haha");
    }
}

2.strcpy()函数

  • 必须保证数组中含有'\0'
  • char arr2[] = {'b','c'};错误,里边必须要以'\0'结束
  • char*arr = "abcdef";错误,这是一个常量字符串,会发生出错
  • 目标空间必须要足够大,保证能存放源字符串
  • my_strcpy()函数实现,如下

char* my_strcpy(char *arr, char *arr1)
{
    assert(arr && arr1);
    char* ret = arr;
    // 1.找到arr的'\0'位置
    while(*arr != '\0')
    {
        arr++;
    }
    // 2.在后边插入arr1的值
    while(*arr1 != '\0')
    {
        *arr = *arr1;
        arr++;
        arr1++;
    }
    *arr = *arr1;
    // 2.第二种写法while(*arr++ = *arr1++);
    // 第一步 *arr = *arr1 将解引用,将arr1的值赋值给arr,如果即把' '替换'\0'为真
    // 第二步 arr++,arr1++,即arr又指向'\0'的位置,然后arr1指向'w'位置,循环 第一二两步
    // 最后,将arr1中的'\0'赋值给arr中,为'\0'的ASCII码值为0,循环结束

    // 3.返回值
    return ret;
}

3.strcat()函数

  • 源字符串必须以'\0'结束
  • 目标空间必须有足够的大,能容纳下源字符串的内容
  • 目标空间必须可修改
  • 实现my_strcat

#include <stdio.h>
#include <assert.h>
#include <string.h>

char* my_strcat(char *arr, char *arr1);

int main()
{
    char arr[] = "hello";
    char arr1[] = " world";
    printf("%s",my_strcat(arr,arr1));
    return 0;
}

char* my_strcat(char *arr, char *arr1)
{
    assert(arr && arr1);
    char* ret = arr;
    // 1.找到arr的'\0'位置
    while(*arr != '\0')
    {
        arr++;
    }
    // 2.在后边插入arr1的值
    while(*arr1 != '\0')
    {
        *arr = *arr1;
        arr++;
        arr1++;
    }
    *arr = *arr1;
    // 2.第二种写法while(*arr++ = *arr1++);
    // 第一步 *arr = *arr1 将解引用,将arr1的值赋值给arr,如果即把' '替换'\0'为真
    // 第二步 arr++,arr1++,即arr又指向'\0'的位置,然后arr1指向'w'位置,循环 第一二两步
    // 最后,将arr1中的'\0'赋值给arr中,为'\0'的ASCII码值为0,循环结束

    // 3.返回值
    return ret;
}

4.strcmp()函数

  • strcmp(string1,string2),比较两个字符串的中的元素一一对比
  • 比如 abc 与 fcd  a<f 返回<0的数字...
  • 比如 abc 与 acd  a<a 返回=0的数字...
  • 比如 fbc 与 acd  f>a 返回>0的数字...
  • my_strcmp()函数实现

#include <stdio.h>
#include <assert.h>

int my_strcmp(const char *arr1,const char *arr2);

int main()
{
    char arr1[10] = {0};
    char arr2[10] = {0};
    scanf("%s",arr1);
    scanf("%s",arr2);
    int ret = my_strcmp(arr1,arr2);
    if(ret == 0)
    {
        printf("equal\n");
    }
    else if(ret == 1)
    {
        printf("arr1>arr2\n");
    }else{
        printf("arr2>arr1\n");
    }
}

int my_strcmp(const char *arr1,const char *arr2) {
    assert(arr1 && arr2);
    // 1.判断对应字符是否相同,一一比对
    while(*arr1 == *arr2)
    {
        // 1.1避免越界访问,设置条件
        if(*arr1 == '\0')
        {
            return 0;
        }
        arr1++;
        arr2++;
    }
    // 2.当比对的 一元素 与 零一元素 不同时,看ASCII码表
    if(*arr1 > *arr2)
    {
        return 1;
    } else{
        return -1;
    }

}

5.strncpy()函数

//strncpy()函数
//strncp(*destination,*src,size_t);
//当src的元素个数,没有size_t大时,补个'\0'
int main()
{
    char arr1[5] = "abc";
    char arr2[] = "ge";
    strncpy(arr1,arr2,4);
    printf("%s",arr1);
}

6.strncat()函数

#include <stdio.h>
#include <string.h>

//strncat()函数
//strnat(*destination,*src,size_t);
//当size_t > *src 长度时,将*src放入到*destination后补一个'\0'
//当size_t < *src 长度时,将*src制定个数size_t个元素放入到*destination后补一个'\0'
int main()
{
    char arr[30] = "hello\0xxxxxxxxxxx";
    char arr2[] = " world";
    strncat(arr,arr2,8);
    printf("%s",arr);
    return 0;
}

7.strncmp()函数

//strncmp()函数
//int strncmp(const char* string1,const char* string2,size_t count);
int main()
{
    // 常量字符串不能被修改,用const进行修饰
    const char* p1 = "abcdef";
    char* p2 = "abceff";
    int ret = strcmp(p1,p2);
    printf("%d\n",ret);//输出小于0的数,不一定是-1
    printf("%d",strncmp(p1,p2,3));//输出为 0 ,比较三个字符
    return 0;
}

8.my_strstr()函数实现

#include <stdio.h>
#include <string.h>
#include <assert.h>

//strstr查找字符串
char* my_strstr(const char* des,const char* src)
{
    assert(des && src);
    char* s1 = des;
    char* s2 = src;
    //记录每次匹配的起始位置
    char* cur = des;
    //判断子串是否为空,为空直接返回主串地址
    if(*src == '\0')
    {
        return des;
    }
    //进行注意匹配,匹配条件:*cur!=NULL
    while(*cur)
    {
        // 1.当匹配失败时,将cur的位置进行更新
        s1 = cur;
        //赋初值,字串要回到起始位置
        s2 = src;

        // 2.进行循环查找,比对主子串,相同主子两串+1,向下匹配
        while((*s1 != '\0') && (*s2 != '\0') && (*s1 == *s2))
        {
            s1++;
            s2++;
        }
        // 3.当匹配到子串为'\0',即找到了子串的全部,返回主串的起始地址cur
        if(*s2 == '\0')
        {
            return cur;
        }
        // 4.没有遇到子串的字符时,主串的起始位置,向下查找
        cur++;
    }
    // 5.没有找到与字串相符合的主串,返回空
    return NULL;


}
int main()
{
    char* p1 = "abcdefghij";
    char* p2 = "def";
    //库函数
    char* ret = strstr(p1,p2);
    //实现自己的my_strstr
    char* ret1 = my_strstr(p1,p2);
    printf("%s\n",ret);
    printf("%s",ret1);
    return 0;
}

9.strtok()函数

#include <stdio.h>
#include <string.h>

//strtok()函数
// char* strtok(char* str,const char* sep);
// sep代表标记(特殊符号)
// 1.第一个参数制定一个字符串,包含0或多个由sep字符串中一个或者多个分隔符的标记
//   比如:110@cn.com  字符串为110@cn.com    sep为 '@' '.'
// 2.strtok函数找到str中的下一个标记,并将其用'\0'结尾,返回一个指向这个标记的指针
//      [注]:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时变量的内容并且可修改
//   比如:110@cn.com 找到'@'后,将字符串变为110\0cn.com,返回1的地址。再调用时,从cn.com开始查找下一个sep
// 3.当strtok函数第一个参数不为NULL,函数找到str中的第一个标记,strtok函数将保存在他字符串中的位置
//   比如:110@cn.com 从110'\0'找到后,将'\0'替换为NULL
// 4.当strtok函数第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记,循环1,2,3步
// 5.如果字符串中不存在更多的标记,返回NULL,即将主串全部找完
//作用:比如:192.168.1.1 -> 返回 192 168 1 1
int main()
{
    //1.定义字符数数组
        //目标串
    char arr[] = "193.268.3.4";
        //切分
    char* p = ".";

    //2.将建临时数组,存储源字符串
        //由于strtok()函数会切分源字符串,所以要用重新定义一个临时字符数组接收源字符串的赋值
    char buf[1024] ={0};
        //做拼接
    strcpy(buf,arr);
    //3.切分buf中的字符串

    char* ret = NULL;
    //      初始化           第1,2,3步            第四步
    for (ret = strtok(buf,p);ret != NULL;ret = strtok(NULL,p))
    {
        printf("%s ",ret);
    }

    return 0;
}

10.strerror()函数

//char* strerror (int errnum)
//作用:返回错误码,所对应的错误信息
int main()
{
    FILE  *pf = fopen("test.txt","r");
    if(pf == NULL)
    {
        printf("%s",strerror(errno));
    }
    else
    {
        printf("open file success");
    }
    return 0;
}

11.总结上述

strcpy、strcat、strcmp、strncpy、strncat、strncmp
操作对象是:字符串,'\0',不能拷贝整型数组、浮点型数组、结构体数组

二、解决局限性

1.memcpy()函数

//memcpy()函数
//memcpy(void*des,void*src,size_t num) 目的地,复制源,操作字节个数(sizeof计算) 【注意】C语言规定必须是两个不同数组
//可以拷贝整型数组、浮点型数组、结构体数组、字符串
//模拟实现
#include <stdio.h>
#include <string.h>
#include <assert.h>
struct Stu{
    char name[20];
    int age;
};
void* my_memcpy(void* des,const void * src,size_t num)
{
    //断言,检测数据是否合法
    assert(des && src);
    // 4.返回首地址
    void *ret;
    // 3.当指定元素个数遍历完
    while (num--) {
        // 1.将src中元素放入des中
            //注意类型转换
        *(char *) des = *(char *) src;
        // 2.两个指针向后移
        des = (char*)des + 1;
        src = (char*)src + 1;
    }

    return ret;

}
int main()
{
    int arr1[] = {1,2,3,4,5};
    int arr2[5] = {0};
    int i = 0;
    // 1.memcpy(void* des,void* src,size_t num) 目的地,复制源,操作字节个数
    memcpy(arr2,arr1, sizeof(arr1));
    // 打印
    for (i = 0 ;i < sizeof(arr2)/ sizeof(arr2[0]);i++)
    {
        printf("%d ",arr2[i]);
    }
    // 2.模拟实现my_memcpy(),实现数组
    struct Stu stu1[] ={{"huang",15},{"lan",10}};
    struct Stu stu2[sizeof(stu1)/ sizeof(stu1[0])] ={0};
    my_memcpy(stu2,stu1, sizeof(stu2));
    // 打印
    for (i = 0 ;i < sizeof(stu2)/ sizeof(stu2[0]);i++)
    {
        printf("\n%s %d ",stu2[i].name,stu2[i].age);
    }
}

2.memmove()函数

// memmove()函数
// memcmp(void* des,const void* src,size_t num) 目的地,复制源,操作字节个数(sizeof计算) 【注意】可以是同一个数组,重叠内存拷贝
// 模拟实现my_memmove
#include <stdio.h>
#include <string.h>
#include <assert.h>

void* my_mommove(void *des, const void *src, size_t count);

int main()
{
    int arr[] = {1,2,3,4,5,6,7,8,9,10};
    int arr2[] = {10,20,30,40,50,60,70,80,90,100};
    // 1.简单应用
    memmove(arr+2,arr,20);
    int i = 0;
        // 打印
    for (i = 0 ;i < sizeof(arr)/ sizeof(arr[0]);i++)
    {
        printf("%d ",arr[i]);
    }
    printf("\n=================\n");
    // 2.模拟实现
    //分析:先写逻辑,重叠时,des<src从前往后拷贝;反之,从后向前拷贝。不重叠时,都可。
    my_mommove(arr2+2,arr2,20);
        //打印
    for (i = 0 ;i < sizeof(arr2)/ sizeof(arr2[0]);i++)
    {
        printf("%d ",arr2[i]);
    }

}

void* my_mommove(void *des, const void* src, size_t count)
{
    assert(des && src);
    // 3.我们要从头打印串,所以要将des的首地址返回,用临时变量存储首地址,确保能全部打印
    void* ret = des;
    // 1.从前往后拷贝 即des < src 画图可知
    if(des < src)
    {
        //循环条件用替换字节的个数
        while (count--)
        {
            *(char *) des = *(char *) src;
            des = (char *) des + 1;
            src = (char *) src + 1;
        }
    }
    // 2.从后往前拷贝 即des >= src包含不重叠情况
    else
    {
        while(count--)
        {
            //将两个串从尾部开始拷贝,'+count'代表尾部
                //表示将从src后部对应des后部向前拷贝
            *((char*)des + count) = *((char*)src + count);
        }
    }
    return ret;
}

3.memcmp()函数

//memcmp()函数
#include <stdio.h>
#include <memory.h>

//memcmp(数组一,数组二,比较字节个数)
//相同返回0
//数组一 < 数组二 返回小于0的数值
//数组一 > 数组二 返回大于0的数值
int main()
{
    int arr1[] = {1,2,3,4,5};
    int arr2[] = {1,2,5,4,3};
    int ret = memcmp(arr1,arr2,9);
    printf("%d",ret);//结果为-1
    return 0;
}

4.memset()函数

//memset()函数 - 内存设置
#include <stdio.h>
#include <memory.h>

//memset(空间地址,字符,字节个数)
int main()
{
    char arr[5] = "";
    int arr1[5] = {0};
    int i = 0;
    // 1.放入字符
    memset(arr,'#',5);
    for (i = 0;i < 5;i++)
    {
        printf("%c ",arr[i]);
    }
    printf("\n=====\n");
    // 2.放入数字
    memset(arr1,1,20);
    for (i = 0;i < 5;i++)
    {
        printf("%d ",arr1[i]);
    }
    //输出  16843009 16843009 16843009 16843009 16843009
    // 原因:内存中存储格式为 【 01 01 01 01 】【 01 01 01 01 】【 01 01 01 01 】【 01 01 01 01 】【 01 01 01 01 】
    //  转为十进制 即为 16843009 16843009 16843009 16843009 16843009
    return 0;
}

三.好用的库函数

//           好用的函数
函数                 符合参条件返回为真(是真就返回比0的数,不是就返回0)
//iscntrl             任何控制字符
//isdigit             十进制数字0-9
//isxdigit            十六进制数字,包括所有十进制数字,小写字母a-f,大写字符A-F
//islower             小写字母a-z
//isupper             大写字母A-Z
//isalpha             字母a-z或A-Z
//isalnum             字母或者数字,a-z,A-Z,0-9
//ispunct             标点符号,热河不属于数字或者字母的图形字符(可打印)
//isprint             任何可打印字符包括图形字符和空白字符
//tolower             大写转小写
//toupper             小写转大写

#include <stdio.h>
#include <ctype.h>

//运用一下库函数
int main()
{
    char arr[] ="I am A Student";
    int i = 0;
    while (arr[i])
    {
        if(isupper(arr[i]))
            arr[i] = tolower(arr[i]);
        i++;
    }
    printf("%s",arr);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值