8.C语言字符串

本文详细介绍了C语言中处理字符串的常用函数,如strcpy、strncpy、strcat、strcmp、strncmp等,以及内存管理相关的函数如strlen、memmove、memcmp等,展示了字符串操作和内存处理的关键点。
摘要由CSDN通过智能技术生成

字符数组

字符数组是元素的数据类型为字符类型的数组

char c[10], ch[3] [4];

字符数组的初始化:

逐个字符赋值

用字符串常量

char ch[6] = {"Hello"};
char ch[6] = "Hello";
char ch[] = "Hello";

内存分布

在这里插入图片描述

字符串

C语言中无字符串变量,用字符数组处理字符串,字符串结束标志:‘\0’。

内存存放的是字符ASCII码

字符串函数(string.h)

库:#include<string.h>

转载:【C语言】string.h中str函数源码实现解析(strlen、strcpy、strncpy、strcat、strcmp、strstr、memcpy、memmove)_strncpy源码-CSDN博客

strcpy

char *strcpy(char *str1, const char *str2);
//把字符串str2(包括'\0')拷贝到字符串str1当中,并返回 str1

char str1[20];
char *str2 = "Hello World";
strcpy(str1,str2);
printf("str1 = %s\r\n",str1);
char str3[20];
char str4[20] = {'H','e','l','l','o',' ','W','o','r','l','d','\0'};
strcpy(str3,str4);
printf("str3 = %s\r\n",str3);
char str5[20]={'A','B','\0'};
char str6[20] = {'H','e','l','l','o',' ','W','o','r','l','d','\0'};
strcpy(str5,str6);
printf("str5 = %s\r\n",str5);	
//str1 = Hello World
//str3 = Hello World
//str5 = Hello World

//源码
char * strcpy(char *dst,const char *src)
{
    assert(dst != NULL && src != NULL);  
    char *ret = dst;
    while ((*dst++=*src++)!='\0'); 
    return ret;
}

strncpy

char *strncpy(char *str1, const char *str2, size_t count);
//把字符串str2中最多count 个字符拷贝到字符串 str1 中,并返回 str1。如果 str2 中少于count 个字符,那么就用'\0'来填充,直到满足 count个字符为止。


char *strncpy(char *dst, const char *src, size_t count)
{
    assert(dst != NULL && src != NULL); 
    char *start = dst;
    while (count && (*dst++ = *src++))
        count--;
    if (count)
        while (--count)
            *dst++ = '\0';
    return (start);
}
//考虑内存重叠
char *strncpy(char *dst, const char *src, size_t len)
{
    assert(dst != NULL && src != NULL);
    char *res = dst;
    if (dst >= src && dst <= src + len - 1) // 重叠,从后向前复制
    {
        dst = dst + len - 1;
        src = src + len - 1;
        while (len--)
            *dst-- = *src--;
    }
    else
    {
        while (len--)
            *dst++ = *src++;
    }
    return res;
}

strcat

char *strcat(char *str1, const char *str2);
//把str2(包括'\0')拷贝到 str1的尾部(连接),并返回 str1。其中终止原 str1的'\0'被str2的第一个字符覆盖。

char *strcat(char *dst, const char *src)
{
    assert(dst != NULL && src != NULL);
    char *tmp = dst;
    while (*dst)
        dst++;
    while ((*dst++ = *src++) != '\0')
        ;
    return tmp;
}

strncat

char *strncat(char *str1, const char *str2, size_t count);
//把str2中最多count 个字符连接到str1 的尾部,并以'\0'终止 str1,返回 str1。其中终止原str1的'\0'被str2的第一个字符覆盖。
//注意,最大拷贝字符数是count+1。

strcmp

int strcmp(const char *str1, const char *str2);
/*
	按字典顺序比较两个字符串,返回整数值的意义如下:
   • 小于0,str1 小于str2;
   • 等于0,str1 等于str2;
   • 大于0,str1 大于str2;
*/

int strcmp ( const char* src, const char* dst )
{
	assert(dst != NULL && src != NULL);
    int ret = 0 ;
    while( !(ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
        ++src, ++dst;
    if ( ret < 0 )
        ret = -1 ;
    else if ( ret > 0 )
        ret = 1 ;
    return( ret );
}

strncmp

int strncmp(const char *str1, const char *str2, size_t count);
/*
    同strcmp,除了最多比较 count 个字符。根据比较结果返回的整数值如下:
    • 小于0,str1 小于str2;
    • 等于0,str1 等于str2;
    • 大于0,str1 大于str2;
*/

char str[][5] = {"R2D2", "C3PO", "R2A6"};
int n;
puts("Looking for R2 as tromechdroids...");
for (n = 0; n < 3; n++)
{
    if (strncmp(str[n], "R2xx", 2) == 0)
    {
        printf("found%s\n", str[n]);
    }
}


int strncmp(const *s1, const *s2, size_t n)
{
    if (!n)
    {
        return 0;
    }
    while (--n && *s1 && *s1 == *s2)
    {
        s1++;
        s2++;
    }
    return (*s1 - *s2);
}

strchr

char *strchr(const char *str, int ch);
//返回指向字符串str 中字符ch 第一次出现的位置的指针,如果 str中不包含ch,则返回NULL。

char *strchr(const char *str, int ch)
{
    while (*str && *str != (char)ch)
        str++;
    if (*str == (char)ch)
        return ((char *)str);
    return (NULL);
}

strrchr

char *strrchr(const char *str, int ch);
//返回指向字符串str 中字符ch 最后一次出现的位置的指针,如果 str中不包含ch,则返回NULL。

char *strrchr(const char *str, int ch)
{

    char *start = (char *)str;
    while (*str++)
        ;
    while (--str != start && *str != (char)ch)
        ;
    if (*str == (char)ch)
        return ((char *)str);
    return (NULL);
}

strspn

size_t strspn(const char *str1, const char *str2);
//strspn函数是C语言中的一个字符串函数,用于计算字符串str1中连续包含字符串str2中字符的长度

size_t strspn(const char *str1, const char *str2) {
    const char *s1 = str1;
    const char *s2;

    while (*s1) {
        for (s2 = str2; *s2; s2++) {
            if (*s1 == *s2) {
                break;
            }
        }
        if (!*s2) {
            break;
        }
        s1++;
    }

    return s1 - str1;
}

strcspn

size_t strcspn(const char *str1, const char *str2);
//strcspn 函数是 C 语言中的一个字符串函数,用于计算字符串 str1 中连续不包含字符串 str2 中任何字符的最长前缀的长度。

size_t strcspn(const char *str1, const char *str2) {
    const char *p1, *p2;
    size_t count = 0;

    for (p1 = str1; *p1 != '\0'; p1++) {
        for (p2 = str2; *p2 != '\0'; p2++) {
            if (*p1 == *p2) {
                return count;
            }
        }
        count++;
    }

    return count;
}

strpbrk

char *strpbrk(const char *str1, const char *str2);
//返回指向字符串str2中的任意字符第一次出现在字符串 str1中的位置的指针;如果 str1中没有与str2相同的字符,那么返回 NULL。

char *strpbrk(const char *cs, const char *ct)
{
    const char *sc1, *sc2;
    for (sc1 = cs; *sc1 != '\0'; ++sc1)
    {
        for (sc2 = ct; *sc2 != '\0'; ++sc2)
        {
            if (*sc1 == *sc2)
            {
                return (char *)sc1;
            }
        }
    }
    return NULL;
}

strstr

char *strstr(const char *str1, const char *str2);
//返回指向字符串str2第一次出现在字符串 str1中的位置的指针;如果 str1中不包含str2,则返回NULL。如果str2 = "\0",直接返回str1地址

char *strstr(const char *str1, const char *str2)
{
    assert(str1 != NULL && str2 != NULL);
    char *cp = (char *)str1;
    char *s1, *s2;
    if (!*str2)
        return ((char *)str1);
    while (*cp)
    {
        s1 = cp;
        s2 = (char *)str2;
        while (*s2 && !(*s1 - *s2))
            s1++, s2++;
        if (!*s2)
            return (cp);
        cp++;
    }
    return (NULL);
}

strlen

size_t strlen(const char *str);
//返回字符串str 的长度,'\0'不算在内。

int strlen(char *s){
    char *p = s;
    while (*p != '\0')
    {
        p++;
    }
    return p - s;
}

strerror

char *strerror(int errnum);
//返回指向与错误序号errnum对应的错误信息字符串的指针(错误信息的具体内容依赖于实现)。

strtok

char *strtok(char *str1, const char *str2);
//strtok()不适用于多线程操作,因为用静态变量保存分割下个字符串首地址,且内部有动态分配内存,所以延伸出可重入的安全函数strtok_s()。

//注意:linux平台下对应的接口名为strtok_r(),用法一致,具体使用方法如下:
	char str[] = "a.b.c/d.e,ee,eee";
    const char demlit[] = ",./";

    char *context = NULL; // context指针保存分割后下一个字符串首地址
    char *p = str;
    p = strtok_s(p, demlit, &context); // &context为二级指针,便于存储一级指针
    while (p != NULL)
    {
        printf("%s\n", p);
        p = strtok_s(NULL, demlit, &context);
    }
/*
a
b
c
d
e
ee
eee
*/

memcpy

void *memcpy(void *to, const void *from, size_t count);
//把from中的count 个字符拷贝到to 中。并返回 to。


void *memcpy(void *dest, const void *src, size_t n)
{
    if (NULL == dest || NULL == src)
    {
        return NULL;
    }
    void *ret = dest;
    char *d;
    const char *s;
    // 内存不重叠的情况,从低地址开始复制
    if ((dest > (src + n)) || (dest < src))
    {
        d = dest;
        s = src;
        while (n--)
            *d++ = *s++;
    }
    else
    {                               // 内存重叠的情况,从高地址开始复制
        d = (char *)(dest + n - 1); /* offset of pointer is from 0 */
        s = (char *)(src + n - 1);
        while (n--)
            *d-- = *s--;
    }
    return ret;
}

memmove

void *memmove(void *to, const void *from, size_t count);
//功能与memcpy类似,不同之处在于,当发生对象重叠时,函数仍能正确执行。


void *memmove(void *dest, void *src, size_t num)
{
    // dest落在了src的左边,从前往后拷贝
    // dest落在了src的右边,同时没有超过那个重叠的边界的时候,从后往前拷贝
    assert(dest != NULL);
    assert(src != NULL);
    void *ret = dest;
    // void* 不能直接解引用,那么如何复制呢?
    // 给了num个字节,也就是需要复制num个字节
    // 那就转换成char*,一个一个字节的复制过去
    if (dest < src)
    // if (dest < src || dest > (char*)src + num)
    {
        // dest落在了src的左边,从前往后拷
        while (num--)
        {
            *(char *)dest = *(char *)src;
            (char *)dest++;
            (char *)src++;
        }
    }
    else
    {
        // 从后往前拷
        // 找到最后一个字节
        while (num--)
        {
            *((char *)dest + num) = *((char *)src + num);
        }
    }
    return ret;
}

memcmp

int memcmp(const void *buf1, const void *buf2, size_t count);
//比较buf1和buf2的前 count 个字符,返回值与 strcmp 的返回值相同。
/*
	按字典顺序比较两个字符串,返回整数值的意义如下:
   • 小于0,str1 小于str2;
   • 等于0,str1 等于str2;
   • 大于0,str1 大于str2;
*/

int memcmp(const void *buf1, const void *buf2, size_t count)
{
    if (!count)
    {
        return 0;
    }
    // 当比较位数不为0时,且每位数据相等时,移动指针
    while (count-- && *(char *)buf1 == *(char *)buf2)
    {
        buf1 = (char *)buf1 + 1; // 转换类型,移动指针
        buf2 = (char *)buf2 + 1;
    }
    // 返回超过比较位数之后 比较的大小
    return (*((unsigned char *)buf1) - *((unsigned char *)buf2));
}

memchr

void *memchr(const void *buffer, int ch, size_t count);
//从buffer所指内存区域的前count个字节查找字符ch,当第一次遇到字符ch时停止查找。如果成功,返回指向字符ch的指针;否则返回NULL。

void *memchr(const void *buffer, int ch, int count)
{
    while (count && (*(unsigned char *)buffer != (unsigned char)ch))
    {
        buffer = (unsigned char *)buffer + 1;
        count--;
    }
    return (count ? (void *)buffer : NULL);
}

memset

void *memset(void *buf, int ch, size_t count);
//把buf 中的前count个字符替换为 ch,并返回 buf。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值