字符串函数和内存操作函数

目录

0.字符串回顾

1.函数介绍

1.1 strlen

1.2 strcpy

1.3 strcat

1.4 strcmp

1.5 strncpy

1.6 strncat

1.7 strncmp

1.8 strstr

1.9 strtok

1.10 strerror

1.11 memcpy

1.12 memmove

1.13 memcmp

1.14 memset

1.15 字符相关函数

字符分类函数

字符转换函数

2.函数模拟实现

2.1模拟实现strlen

2.2模拟实现strcpy

2.3模拟实现strcat

2.4模拟实现strcmp

2.5模拟实现strstr

2.6模拟实现memcpy

2.7模拟实现memmove


0.字符串回顾

#include 

int main()
{
	char str1[] = "hello bit";
	const char* str2 = "hello bit";

	printf("%s\n", str1);
	printf("%s\n", str2);

	return 0;
}

字符指针除了表示字符的指针,还可以表示字符串

代码:const char* pstr = "hello bit.";
  • 字符串可以用字符数组字符指针来表示。

  • 字符指针表示的字符串是常量字符串

  • 这里的const在有的编译器可以不加,有的编译器要求严格必须加上。

  • 字符指针表示字符串不是把整个字符串放入字符指针中,本质是把字符串“hello bit“的首字符h的地址放入字符指针pstr中。

内存分区:

字符串函数和内存操作函数_第1张图片

栈,堆,数据段(全局变量和静态变量),代码段(可执行代码,常量)

1.函数介绍

长度不受限制的字符串函数(依赖'\0'):strlen,strcpy,strcat,strcmp

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

字符串查找:strstr,strtok

错误信息报告:strerror


1.1 strlen


size_t strlen ( const char * str );
  • 参数是const char*,返回值是size_t。

  • 字符串以‘\0’作为结束标志,strlen函数就是通过'\0'来统计字符个数的。

  • 参数指向的字符串必须要以‘\0’结尾。

  • 函数的返回值为size_t,表示的是无符号整数。

注意:

int main()
{
    const char* str1 = "abcdef";
    const char* str2 = "bbb";
    if (strlen(str2) - strlen(str1) > 0)
    {
        printf("str2>str1\n");
    }
    else
    {
        printf("str1>str2\n");
    }
​
    return 0;
}

strlen函数返回的是无符号数,所以无论怎么样都是大于0的数,结果是str2>str1.

1.2 strcpy


char * strcpy ( char * destination, const char * source );
  • 源字符串必须要以'\0'结尾。

  • 该函数会将源字符串(soure)的​ '\0' ​拷贝到目标字符串(destination)中。

  • 目标字符串要足够大,保证能够存放源字符串。

  • 目标字符串必须是可变的。(char*指向的字符串就不行​,因为char*指向的字符串是常量区中的常量字符串)。

展示:

字符串函数和内存操作函数_第2张图片 

1.3 strcat


​char * strcat ( char * destination, const char * source );
  • 源字符串必须以‘\0'结束。

  • 在目标字符串后面追加源字符串。

  • 目标空间必须足够的大,能容纳下源字符串的内容。

  • 目标空间必须可修改。

注意:strcat不能自己给自己追加,程序会崩溃。(追加时会覆盖'\0',此时找不到‘\0’会出错)

1.4 strcmp


int strcmp ( const char * str1, const char * str2 );
  • 第一个字符串大于第二个字符串,则返回大于0的数字。

  • 第一个字符串等于第二个字符串,则返回0。

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

1.5 strncpy


char * strncpy ( char * destination, const char * source, size_t num );
  • 拷贝源字符串中的前num个字符到目标字符串中。

num<=len时,是不会拷贝'\0'的。

num>len时,多余的会补'\0'。

1.6 strncat


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

1.7 strncmp


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

表示最多比较多少个字符。

1.8 strstr


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

char * strstr ( char * str1, const char * str2 );
  • 返回 str1 中第一次出现的 str2 时的指针,如果 str2 不是 str1 的一部分,则返回一个空指针。**

  • str2是空字符串,返回str1。

1.9 strtok


char * strtok ( char * str, const char * sep );
  • sep参数是个字符串,定义了用作分隔符的字符集合。

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

  • strtok函数找到str中的标记,并将其变成'\0',然后返回一个指针,这个指针指向首元素(str)

  • strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。

  • strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。(是一个有记录功能的函数)。

  • strtok函数的第一个参数为NJLL,函数将在同一个字符串中被保存的位置开始(起始位置指针str其实就是被保存的位置指针+1),查找下一个标记。

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

int main()
{
    char* p = "zhouwenjun:[email protected]";
    const char* sep = ":@.";
    char arr[30];
    char* str = NULL;
    strcpy(arr, p);//使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。
​
    for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
    {
        printf("%s\n", str);
    }
​
​
    return 0;
}

1.10 strerror


补充:库函数在执行过程中发生了错误,会将一个错误码存放在errno这个变量中,errno是C语言中提供的一个全局变量。

错误码:0(没有错误),1,2,3,....


char * strerror ( int errnum );

参数errnum就是错误码,返回的char*是将错误码所对应的错误信息以字符串形式打印出来。

展示:

字符串函数和内存操作函数_第3张图片

补充:

perror和strerror的区别:

perror直接自带打印功能,错误信息的报告会更加彻底。

perror("fopen");等价于printf("fopen:%s\n",strerror(errno));

1.11 memcpy


void * memcpy ( void * destination, const void * source, size_t num );
  • 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。

  • 这个函数可以拷贝任何类型的数据,包括字符串,整型,以及结构体,所以这个函数不看'\0'的。

  • 这里source和destination有重叠的话,拷贝的结果是错误的,所以memcpy只能用于不重叠空间的拷贝

拷贝整型

字符串函数和内存操作函数_第4张图片

 拷贝字符串/结构体

​​字符串函数和内存操作函数_第5张图片

1.12 memmove


void * memmove ( void * destination, const void * source, size_t num );
  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。

  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理。

注意:vscode的memcpy函数经过特殊处理,和memmove函数有着相同的功能,都可以拷贝重叠的内存空间。

1.13 memcmp


int memcmp ( const void * ptr1, const void * ptr2, size_t num );
  • 比较从ptr1和ptr2指针开始的num个字节。

  • 按字节比较。

1.14 memset


void * memset ( void * ptr, int value, size_t num );
  • 将 ptr 指向的内存块的前num个字节数设置为指定值。

  • 以字节为单位设置的。

1.15 字符相关函数


头文件

字符分类函数

字符转换函数

int tolower(int C);

int toupper(int C);

2.函数模拟实现

2.1模拟实现strlen


//strlen实现
//1.计数方式实现:
size_t _strlen_1(const char* str)
{
    int count = 0;
    while (*str)
    {
        count++;
        str++;
    }
    return count;
}
​
//2.指针-指针实现
size_t _strlen_2(const char* str)
{
    char* p = str;
    while (*p)
    {
        p++;
    }
​
    return p - str;
}
​
//3.递归实现
size_t _strlen_3(const char* str)
{
    if (!*str)
    {
        return 0;
    }
    else
    {
        return 1 + _strlen_3(str + 1);
    }
}

2.2模拟实现strcpy


//strcpy模拟实现
​
//NULL指针不指向任何有效空间,不能被使用,不能被解引用。
//const修饰的好处:指针指向的内容不能被改变
//优先级:++ >  *  >  =
char* _strcpy(char* dst, const char* src)
{
    assert(dst && src);
    char* ret = dst;
​
    while (*dst++ = *src++)//这种写法很简洁,'\0'一起被拷贝
    {
        ;
    }
​
    return ret;
}

2.3模拟实现strcat


char* _strcat(char* dst, const char* src)
{
    assert(dst && src);
    char* ret = dst;
​
    //1、找到‘\0’
    while (*dst)
    {
        dst++;
    }
​
    //2、拷贝
    while (*dst++ = *src++)
    {
        ;
    }
​
    return ret;
}

2.4模拟实现strcmp


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

2.5模拟实现strstr


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

2.6模拟实现memcpy


void* my_memcpy(void* dest, const void* src, size_t num)
{
    void* ret = dest;
    assert(dest && src);
​
    while (num--)
    {
        *(char*)dest = *(char*)src;
        dest = (char*)dest + 1;
        src = (char*)src + 1;
    }
​
    return ret;
}

2.7模拟实现memmove


void* my_memmove(void* dest, const void* src, size_t num)
{
    void* ret = dest;
    assert(dest && src);
​
    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;
}
  • 如果dest < src,src只需要从前往后拷贝即可。

  • 如果dest > src,src需要从后往前拷贝。

你可能感兴趣的:(C语言,c语言,字符串,内存操作,算法)