C进阶-字符串和内存函数

  • 文章目录

  • 一、求字符串长度
  • 二、长度不受限制的字符串函数
  • 三、长度受限制的字符串函数介绍
  • 四、字符串查找
  • 五、错误信息报告
  • 六、字符操作
  • 七、内存操作函数

前言

C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符串数组中。字符串常量适用于那些对他不做修改的字符串函数


1.函数介绍:

长度不受限制的字符串函数:strcpy,strcat,strcmp

长度受限制的字符串函数:strncpy,strncat,strncmp

1.1strlen

size_t strlen ( const char * str );

字符串已经'\0' 作为结束标志,strlen函数返回的是在字符串中'\0' 前面出现的字符个数(不包含'\0' )。

参数指向的字符串必须要以'\0' 结束。

注意函数的返回值为size_t,是无符号的( 易错)

学会strlen函数的模拟实现

// int main()
// {
//     if ((int)strlen("abc") - (int)strlen("abcdef") > 0)
//     {
//         printf("大于\n");
//     }
//     else
//     {
//         printf("小于等于\n");
//     }


//     return 0;
// }

//1
size_t my_strlen(const char* str)
{
    int count = 0;
    while (*str != '\0')
    {
        count++;
        str++;
    }
    return count;
}

//2.指针-指针
//3.递归的方法

int main()
{
    size_t sz = my_strlen("abc");
    printf("%d\n",sz);
    return 0;
}

 1.2 strcpy

char* strcpy(char * destination, const char * source );

Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).
源字符串必须以 '\0'结束。
会将源字符串中的 '\0'拷贝到目标空间。
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。
学会模拟实现。

char* my_strcpy(char* dest,const char* src)
{
    char* ret = dest;
    assert(dest != NULL);  //断言,dest不为空指针
    assert(src != NULL);
    // while(*src != '\0')
    // {
    //     *dest = *src;
    //     dest++;
    //     src++;
    // }
    // *dest = *src; // \0
    while(*dest++ = *src++)
    {
        ;
    }
    

    return ret;
}

int main()
{
    char arr1[20] = "hello xiaofan";
    //char arr2[40] = "hello xiaofan";
    char arr2[] = "xxxxx";
    //strcpy(arr1,arr2);
    my_strcpy(arr1,arr2);
    printf("%s\n",arr1);

    return 0;
}

1.3 stract

char * strcat ( char * destination, const char * source );

Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.
源字符串必须以 '\0'结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。

char* my_strcat(char* dest,const char* src)
{
    assert(dest != NULL);
    assert(src != NULL);
    char*  ret = dest;
    //1.找到目标空间中的\0
    while (*dest != '\0')
    {
        dest++;
    }
    while (*dest++ = *src++)
    {
        ;
    }

    return ret;

    
}

int main()
{
    char arr1[20] = "hello ";
    char arr2[] = "world";

    //strcat(arr1,arr2);
    my_strcat(arr1,arr2);

    printf("%s\n",arr1); //helloworld

    return 0;
}

1.4 strcmp

int strcmp ( const char * str1, const char * str2 );

标准规定:

    第一个字符串大于第二个字符串,则返回大于0的数字

    第一个字符串等于第二个字符串,则返回0
    第一个字符串小于第二个字符串,则返回小于0的数字

    那么如何判断两个字符串?

int my_strcmp(const char* str1,const char* str2)
{
    assert(str1 && str2 != NULL);
    while (*str1 == *str2)
    {
        if (*str1 == '\0')
        {
            return 0;
        }
        str1++;
        str2++;
    }
    // if(*str1 > *str2)
    // {
    //     return 1;
    // }
    // else
    // {
    //     return -1;
    // }
    return (*str1 - *str2);
    
}

int main()
{
    //char arr1[] = "abcdef\0";
    //char arr2[] = "abcddddd\0";
    int ret =  my_strcmp("abcdefa","abcdefb"); //-1
    printf("%d\n",ret);
    return 0;
}

1.5 strncpy

char * strncpy ( char * destination, const char * source, size_t num );

拷贝num个字符从源字符串到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

int main()
{
    char arr1[20] = "abcdef";
    char arr2[] = "ab";
    strncpy(arr1,arr2,4);
    printf("%s\n",arr1);

    return 0;
}

1.6 strncat

char * strncat ( char * destination, const char * source, size_t num ); 

int main()
{
    char arr1[20] = "abcdef";
    char arr2[] = "ab";
    strncat(arr1,arr2,0);
    printf("%s\n",arr1);

    return 0;
}

1.7 strncmp

int strncmp ( const char * str1, const char * str2, size_t num )

int main()
{
    char arr1[] = "abcqbertyui";
    char arr2[] = "abcqcfg";
    printf("%d\n",strncmp(arr1,arr2,5));

    return 0;
}

 1.8 strstr  -字符串中找子字符串

char * strstr ( const char *, const char * );

char* my_strstr(const char* str1,char* str2)
{
    assert(str1 && str2 != NULL);
    char* cp = str1;
    char* s1 = cp;
    char* s2 = str2;
    while (*cp)
    {
        //开始匹配
        s1 = cp;
        s2 = str2;
        while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
        {
            s1++;
            s2++;
        }
        if (*s2 == '\0')
        {
            return cp;
        }
        
        
        cp++;
    }
    
    return NULL;

}

int main()
{
    char arr1[] = "abcdefabcdef";
    //char arr2[] = "deq"; //null
    char arr2[] = "def";
    //char* ret = strstr(arr1,arr2);
    char* ret = my_strstr(arr1,arr2);
    if (ret != NULL)
    {
        printf("%s\n",ret);
    }
    else
    {
        printf("找不到\n");
    }
    

    return 0;
}

 1.9 strtok

char * strtok ( char * str, const char * sep );

sep参数是个字符串,定义了用作分隔符的字符集合

第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。


strtok函数找到str中的下一个标记,并将其用 \0结尾,返回一个指向这个标记的指针(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)


strtok函数的第一个参数不为 NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。 strtok函数的第一个参数为 NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。


如果字符串中不存在更多的标记,则返回 NULL指针。

int main()
{
    char arr[] = "fsy@qq.com@77#2222";
    char copy[20];
    strcpy(copy,arr);

    char sep[] = "@.#";
    // char* ret = strtok(copy,sep);
    // printf("%s\n",ret);
    // ret = strtok(NULL,sep);
    // printf("%s\n",ret);
    // ret = strtok(NULL,sep);
    // printf("%s\n",ret);

    char* ret = NULL;

    for(ret = strtok(copy,sep); ret != NULL; ret = strtok(NULL,sep))
    {
        printf("%s\n",ret);
    }

    return 0;
}

 1.10 strerror

char * strerror ( int errnum );  

返回错误码,所对应的错误信息

库函数在执行的时候吗,发生了错误,会将一个错误码放在errno这个变量中

errno是C语言提供的一个全局的变量

int main()
{
    int i = 0;
    for (i= 0; i < 10; i++)
    {
        printf("%s\n",strerror(i));
    }

    return 0;
}

int main()
{
    //C语言中可以操作文件
    //操作文件的步骤
    //1.打开文件
    //2.读/写文件
    //3.关闭文件
    //FILE* pf = fopen("/Users/fan/Documents/c_study/c_test20/data.txt","r");
    FILE* pf = fopen("fan/Documents/c_study","r");
    if (pf == NULL)
    {
        printf("%s\n",strerror(errno));
        perror("fopen");
        return 1;
    }

    //读文件

    //关闭文件
    fclose(pf);

    return 0;
}

1.11字符分类函数

int main()
{
    //判断为真是非0,为假是0
    //printf("%d\n",isupper('A'));
    //printf("%d\n",isdigit('1'));

    //字符转换
    // printf("%c\n",tolower('A'));
    // printf("%c\n",tolower('s'));

    char arr[20] = {0};
    gets(arr); //遇到空格也会往后读
    printf("%s\n",arr);

    char* p = arr;
    while(*p)
    {
        if(isupper(*p)) //*p >= 'A' && *p<='Z'
        {
            *p = tolower(*p); //*p = *p+32
        }
        p++;
    }
    printf("%s\n",arr);
    return 0;
}

1.11 memcpy

void * memcpy ( void * destination, const void * source, size_t num );

函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。这个函数在遇到 '\0'的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。

//memcpy(void* dest,)
//memcpy 是内存拷贝  拷贝字符串,拷贝整型数组,拷贝结构体数据
// int main()
// {
//     // int arr1[] = {1,2,3,4,5,6,7,8,9,10};
//     // int arr2[20] = {0};
//     float arr1[] = {1.0,2.0,3.0};
//     float arr2[5] = {0};
//     //将arr1的内容,拷贝到arr2中
//     memcpy(arr2,arr1,8);
//     int i = 0;
//     for (i = 0 ;i < 5; i++)
//     {
//         printf("%f ",arr2[i]);
//     }

//     return 0;
// }

//模拟实现

//函数拷贝结束后,返回目标空间的起始地址
void* my_memcpy(void* dest,const void* src,size_t num)
{
    assert(dest && src != NULL);
    void* ret = dest;
    while (num--) //4,3,2,1,0
    {
        *(char*)dest = *(char*)src;
        dest = (char*)dest+1;  //强制转换成char* ,跳过一个字节
        src = (char*)src+1;
    }
    return ret;

}

int main()
{
    int arr1[] = {1,2,3,4,5,6,7,8,9,10};
    //01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 00
    int arr2[20] = {0};
    //my_memcpy(arr2,arr1,21);
    //my_memcpy(arr1+2,arr1,21); //memcpy函数是用来处理,不重叠的内存拷贝的
    memmove(arr1+2,arr1,20); //memmove函数可以用来处理重叠的内存拷贝
    int i = 0;
    for (i = 0 ;i < 10; i++)
    {
        printf("%d ",arr1[i]);
    }


    return 0;
}

 1.12 memmove

void * memmove ( void * destination, const void * source, size_t num );

和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。如果源空间和目标空间出现重叠,就得使用memmove函数处理。

 

void* my_memmove(void* dest,void* src,size_t num)
{
    void* ret = dest;
    assert(dest && src != NULL);
    if (dest < src)
    {
        //前->后
        while (num--)
        {
            *(char*)dest = *(char*)src;
            dest = (char*)dest +1;
            src = (char*)src +1;
        }
    }
    else
    {
        //后->前
        while (num--) //20
        {
            *((char*)dest + num) = *((char*)src + num);
        }
    }
    return ret;
}

int main()
{
    int arr1[] = {1,2,3,4,5,6,7,8,9,10};
    //01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 00
    //int arr2[20] = {0};
    //my_memcpy(arr2,arr1,21);
    //my_memcpy(arr1+2,arr1,21); //memcpy函数是用来处理,不重叠的内存拷贝的
    //memmove(arr1+2,arr1,20); //memmove函数可以用来处理重叠的内存拷贝
    my_memmove(arr1+2,arr1,20);
    //memcpy(arr1+2,arr1,20);err
    int i = 0;
    for (i = 0 ;i < 10; i++)
    {
        printf("%d ",arr1[i]);
    }


    return 0;
}

1.13 memcmp

int memcmp ( const void * ptr1,const void * ptr2,size_t num );

比较从ptr1和ptr2指针开始的num个字节

// int main()
// {
//     char arr[] = "hello bit";
//     memset(arr+1,'x',4);//以字节为单位设置的
//     printf("%s\n",arr); // hxxxx bit

//     return 0;
// }

int main()
{
    int arr[10] = {0};
    //memset(arr,1,10); err
    memset(arr,1,40);

    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值