常见的string.h库的函数

C语言的string.h库会经常用到接下来举出几个常见的函数,分别有strlen,(长度不受限制的字符串)strcmp,strcat,strcpy,(长度收限制的字符串,较为安全)strncmp,strncat,strncpy,strstr,strsok。

strlen#strlen

1.字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
size_t strlen ( const char * str );
2.参数指向的字符串必须要以 ‘\0’ 结束。
3.注意函数的返回值为size_t,是无符号的( 易错 )
函数原型:

size_t __cdecl strlen (
        const char * str
        )
{
        const char *eos = str;

        while( *eos++ ) ;

        return( eos - str - 1 );
}

strlen函数的模拟实现:

int my_strlen(const char* str)
{
	int l = 0;
	while (*str++)
		l++;
	return l;
}注意返回的是无符号整型
int main()
{

	char str[] = {"abcdef"};
	printf("%d", my_strlen(str));
	return 0;
}

strcpy#strcpy

1.源字符串必须以 ‘\0’ 结束。
2.会将源字符串中的 ‘\0’ 拷贝到目标空间。
3.目标空间必须足够大,以确保能存放源字符串。
4.目标空间必须可变。

函数原型:

extern "C" errno_t __cdecl strcpy_s(
    char*       const destination,
    size_t      const size_in_elements,
    char const* const source
    )
{
    return common_tcscpy_s(destination, size_in_elements, source);
}

模拟实现strcpy:

char* my_strcpy(char* str1, char* str)
{
	char* ret = str1;
	while (*str1++ = *str++)
	{
		;
	}
	return ret;
}

strcat#strcat


1.源字符串必须以 ‘\0’ 结束。
2.目标空间必须有足够的大,能容纳下源字符串的内容。
3.目标空间必须可修改。
函数原型:

char * __cdecl strcpy(char * dst, const char * src)
{
        char * cp = dst;

        while((*cp++ = *src++) != '\0')
                ;               /* Copy src over dst */

        return( dst );
}

strcat的模拟实现:

char* my_strcat(char* str, const char* str2)
{
	char* ret = str;
	while (*str)
		str++;;
	while (*str++ = *str2++);
	return ret;
}

strcmp#strcmp


标准规定:
1.第一个字符串大于第二个字符串,则返回大于0的数字
2.第一个字符串等于第二个字符串,则返回0
3.第一个字符串小于第二个字符串,则返回小于0的数字
函数原型:

int __cdecl strcmp (
        const char * src,
        const char * dst
        )
{
        int ret = 0 ;

        while((ret = *(unsigned char *)src - *(unsigned char *)dst) == 0 && *dst)
                {
                ++src, ++dst;
                }

        return ((-ret) < 0) - (ret < 0); // (if positive) - (if negative) generates branchless code
}

strcmp函数模拟:

int my_strcmp(char* str2, char* str)
{
	int l = 0;
	while (*str2++ == *str);
	l=*str2 - *str;
	if (l > 0)
		l = 1;
	else if (l < 0)
		l = -1;
	return l;
}

strncpy#strncpy


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

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

函数原型:

char * __cdecl strncpy (
        char * dest,
        const char * source,
        size_t count
        )
{
        char *start = dest;

        while (count && (*dest++ = *source++) != '\0')    /* copy string */
                count--;

        if (count)                              /* pad out with zeroes */
                while (--count)
                        *dest++ = '\0';

        return(start);
}

strncat#strncat


将源的前num个字符追加到目标,再加上一个终止的null字符。
如果源中的C字符串的长度小于num,则只有终止之前的内容复制空字符

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

模拟实现strncat:

#include<stdio.h>
char* my_strncat(char* di, char* sz, size_t s)
{
	char* ret = di;
	while (*di++);
	di--;
	while (s--)
	{
		*di++ = *sz++;
	}
	return ret;
}

int main()
{
	char str[20] = "hello ";
	char str1[20] = "word!";
	printf(my_strncat(str, str1, 4));
	return 0;
}

strncmp#strncmp


比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。满足任一条件结束。

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

函数原型:

int __cdecl strncmp
(
    const char *first,
    const char *last,
    size_t      count
)
{
    size_t x = 0;

    if (!count)
    {
        return 0;
    }

    /*
     * This explicit guard needed to deal correctly with boundary
     * cases: strings shorter than 4 bytes and strings longer than
     * UINT_MAX-4 bytes .
     */
    if( count >= 4 )
    {
        /* unroll by four */
        for (; x < count-4; x+=4)
        {
            first+=4;
            last +=4;

            if (*(first-4) == 0 || *(first-4) != *(last-4))
            {
                return(*(unsigned char *)(first-4) - *(unsigned char *)(last-4));
            }

            if (*(first-3) == 0 || *(first-3) != *(last-3))
            {
                return(*(unsigned char *)(first-3) - *(unsigned char *)(last-3));
            }

            if (*(first-2) == 0 || *(first-2) != *(last-2))
            {
                return(*(unsigned char *)(first-2) - *(unsigned char *)(last-2));
            }

            if (*(first-1) == 0 || *(first-1) != *(last-1))
            {
                return(*(unsigned char *)(first-1) - *(unsigned char *)(last-1));
            }
        }
    }

    /* residual loop */
    for (; x < count; x++)
    {
        if (*first == 0 || *first != *last)
        {
            return(*(unsigned char *)first - *(unsigned char *)last);
        }
        first+=1;
        last+=1;
    }

    return 0;
}

strstr#strstr


返回指向str1中第一个出现的str2的指针,如果str2不是str1。

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

函数原型:太多了
1.暴力函数模拟实现

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strstr(char* str, char* p)
{
	assert(str && p);
	if (*p == '\0')
		return str;
	char* cp = str;//回溯指针
	char* s1 = cp;//比较指针
	char* s2 = p;//比较指针
	while (1)
	{
		while (*s1++ == *s2++ )
		{
			if (*s2 == '\0')
				return cp;
			else if (*s1 == '\0' && *s2 != '\0')
				return NULL;
		}
		cp++;
		s1 = cp;
		s2 = p;
	}
}
int main()
{
	char str[20] = "aaaabbbcde";
	char p[] = "\0";
	printf("%s",my_strstr(str, p));
	return 0;
}

下面这个在循环中少一层分支嵌套会好一些

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	if (*str2 == '\0')
	{
		return (char*)str1;
	}
	const char* s1 = NULL;
	const char* s2 = NULL;
	const char* cp = str1;

	while (*cp)
	{
		s1 = cp;
		s2 = str2;
		while (*s1 !='\0' && *s2!='\0' && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return (char*)cp;
		}
		cp++;
	}

	return NULL;
}

2.kml算法模拟strstr:

简述一下,代码还不会。

首先确定要查找的字符串如

char str[20]="abcabeabcabcde";
char p[]="abcabcde";

p的前缀:
就是字符串从前往后的字符串比如p的前缀有:

a
ab
abc
abca
abcab
abcabc
abcabcd
abcabcde

p的后缀:(简述后缀的形式和kmp关系不大)

e
de
cde
bcde
abcde
。。。。等

上述p的相等前后缀判别

a——0
ab——0
abc——0
abca——1//看这段中有前缀a ab abc 有后缀a ca bca 当前后缀相同时既全为a而是一个字母
abcab——2//看这段中有前缀a ab abc abcd 有后缀b ab cab bcab 当前后缀相同时有最长相等前后缀为ab是两个字母
abcabc——3//同理最长为三个字母abc为最长前后缀
abcabcd——0//前缀a ab abc abca abcab abcabc abcabcd 后缀有d cd bcd abcd cabcd babcd abcabcd最长相等前后缀没有为0

建立一个数组求上述p字符串的相等最长前后缀;

int arr[strlen(p)]={0,0,0,1,2,3,0,0};
//也有许多人将数组列,由于最后一个并不影响kmp算法,所以往后移动一项更为方便
int arr1[0]=-1;
for(int i=1;i<strlen(p);i++)
{
	arr1[i]=arr[i-1];
}
//使数组arr1
int arr1={-10001230}

建立好数组后

char str[20]="abcab e abcabcde";
char p[]=    "abcab c de";
int arr[strlen(p)]={0,0,0,1,2,3,0,0};//c对应的是3但要取出前一个,也就是b对应的数组值
int arr1={-10001230};
将p向后移动到e的前两位
char str[20]="abcab e abcabcde";
char p[]=       "ab c abcde";//这次对应的是0则继续下一次匹配这时指针指向e下一次将往前增加0个然后继续向后匹配
char str[20]="abcab e abcabcde";
char p[]=            "abcabcde";

最后匹配成功。
如果是arr数组那么每当匹配到不一样的字符时向后移动到匹配错误位置前arr

strtok#strtok

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

1.sep参数是个字符串,定义了用作分隔符的字符集合
2.第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标
记。
3.strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:
4.strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容
并且可修改。)
5.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串
中的位置。
6.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标
记。
如果字符串中不存在更多的标记,则返回 NULL 指针。
举列子说明:

#include<stdio.h>
#include<string.h>
int main()
{
	char str[20] = "adcnd,cwr_dd@www";
	char p[] = ",_@";
	char* ret = NULL;
	for (ret=strtok(str, p);ret;ret=strtok(NULL, p))
	{
		printf("%s\n", ret);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值