C语言 关于字符函数和字符串函数

在C语言中经常会使用到字符和字符串,但其实C语言本身是没有字符串类型的,所以字符串通常被存放在常量字符串字符串常量适用于那些对它不做修改的字符串函数)中或字符数组中。

※字符串函数

1.strlen

size_t strlen(const char* str);

·字符串以  '\0' 作为结束标志, strlen 函数返回的是在字符串中 '\0' 前面 出现的字符个数( 不包含 '\0' )
·参数指向的字符串必须要以 '\0' 结束。
·函数的返回值为size_t,是 无符号 的。
·模拟实现:
 ① 计数器方式:
#include<stdio.h>
#include<assert.h>

size_t my_strlen(const char* str)
{
	assert(str != NULL);         //断言
	char* pstr = str;            //参数保护
	int count=0;
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}

//测试程序
void main()
{
	char str1[] = "abcdefghijk";
	size_t len=my_strlen(str1);
	printf("%d\n", len);
}
  不创建临时变量(递归实现):
#include<stdio.h>
#include<assert.h>

size_t my_strlen(const char * str) 
{ 
    assert(str);
    if(*str == '\0') 
        return 0; 
    else 
        return 1+my_strlen(str+1); 
}

//测试程序
void main()
{
	char str1[] = "abcdefghijk";
	size_t len=my_strlen(str1);
	printf("%d\n", len);
}

 

2.strcpy

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

·源字符串必须以 '\0' 结束。
·会将源字符串中的 '\0' 拷贝到 目标空间
·目标空间 必须足够大 ,以确保能存放源字符串。
·目标空间 必须可变
·模拟实现:
#include<stdio.h>
#include<assert.h>

char* my_strcpy(char* des, const char* src)
{
	assert(des != NULL);         //断言
	assert(src != NULL);         //断言
	char* pdes = des;            //参数保护
	while (*src != '\0')
	{
		*pdes = *src;
		pdes++;
		src++;
	}
	*pdes = '\0';
	return des;
}

//测试程序
void main()
{
	char des[] = "abcdefhg";
	my_strcpy(des, "abcde");
	printf("%s\n", des);
}

3.strcat

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

·源字符串必须以 '\0' 结束。
·目标空间必须有 足够的大 ,能容纳下源字符串的内容。
· 目标空间必须 可修改
·模拟实现:
#include<stdio.h>
#include<assert.h>

char* my_strcat(char *des, char *src)
{
	char *pdes = des;        //参数保护
	assert(des);             //断言
	assert(src);             //断言
	while (*pdes!='\0')
	{
		pdes++;
	}
	while (*src!='\0')
	{
		*pdes=*src;
		pdes++;
		src++;
	}
	*pdes = '\0';
	return des;
}

//测试程序
void main()
{
	char arr1[15] = "abcd";
	char *arr2 = "ef";
	printf("%s\n", my_strcat(arr1, arr2));
}

※那么问题来了,假如字符串自己给自己追加,会怎么样呢?

   追加过程如下图所示。

因为源字符串永远比目的字符串走得快覆盖了 '\0',从而导致永远找不到 '\0' 而陷入死循环

 

4.strcmp

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

·标准规定:
 第一个字符串大于第二个字符串,则返回大于 0 的数字;
 第一个字符串等于第二个字符串,则返回 0;
 第一个字符串小于第二个字符串,则返回小于 0 的数字。
·模拟实现:
#include<stdio.h>
#include<assert.h>

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

//测试程序
void main()
{
	int ret = my_strcmp("helloA", "hello");
	if (ret == 0)
		printf("两个字符串相等。\n");
	if (ret == 1)
		printf("str1大于str2。\n");
	if (ret == -1)
		printf("str1小于str2.\n");
}

 

5.strncpy

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

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

6.strncat

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

7.strncmp

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

·比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。

 

8.strstr

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

·返回一个指向str1中str2第一次出现的指针,如果str2不是str1的一部分则返回一个空指针。

·模拟实现:

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

char* my_strstr(const char* str1, const char* str2)
{
	assert(str1);                      //断言
	assert(str2);                      //断言
	const char* start = str1;          //参数保护
	while (*str1 != '\0'&&*str2 != '\0')
	{
		if (*str1 == *str2)
		{
			str1++;
			str2++;
		}
		else
		{
			str1++;
			start = str1;
		}
	}
	if (*str2 == '\0')
	{
		return start;
	}
	return NULL;
}

//测试程序
void main()
{
	char* p = my_strstr("abcd", "bc");
	printf("%s\n", p);
}
 
 
 
9.strerror
 
char * strerror ( int errnum );
 
·返回错误码所对应的错误信息。
· 应用举例:
/* strerror example : error list */

#include <stdio.h>
#include <string.h>
#include <errno.h>//必须包含的头文件

int main () 
{ 
    FILE * pFile; 
    pFile = fopen ("unexist.ent","r"); 
    if (pFile == NULL) 
        printf ("Error opening file unexist.ent: %s\n",strerror(errno)); 
        //errno: Last error number 
    return 0; 
} 

·运行结果:

常用 字符分类函数
 
函数
如果他的参数符合下列条件就返回真
islower
小写字母 a~z
isupper
大写字母A ~Z
isalpha
字母a~z或A~Z
isalnum

字母或数字,a~z,A~Z,0~9

 

 
 
 
 
 
 
 
 
 
 
※字符转换
 
· int tolower(int c);
 
· int toupper(int c);
 
·应用举例:
/* isupper example */ 

#include <stdio.h> 
#include <ctype.h>
 
int main () 
{ 
    int i=0; 
    char str[]="Test String.\n"; 
    char c; 
    while (str[i]) 
    { 
        c=str[i]; 
        if (isupper(c)) 
            c=tolower(c); 
        putchar (c); 
        i++; 
    } 
    return 0; 
}
10.memcpy
 
void * memcpy ( void * destination, const void * source, size_t num );
 
·函数 memcpy source 的位置开始向后复制 num 字节 的数据到 destination 的内存位置。
·   这个函数在遇到 '\0' 的时候 并不会停下来  
· 如果source和destination有任何的重叠,复制的结果都是未定义的
·模拟实现:
#include<stdio.h>
#include<assert.h>

char* my_mommove(void* des, const void* src, size_t count)
{
	assert(des != NULL);
	assert(src != NULL);
	char* pdes = (char*)des;
	char* psrc = (char*)src;
	while (count-- > 0)
	{
		*pdes = *psrc;
		pdes++;
		psrc++;
	}
	return des;
}

void main()
{
	char str1[20] = "abcdefghijk";
	my_mommove(str1+2,str1,3);
	printf("%s\n", str1);
}
11.memmove
 
void * memmove ( void * destination, const void * source, size_t num );
 
·该函数和memcpy函数 差别 就是 memmove 函数处理的源内存块和目标内存块 是可以重叠的 。 因此,如果源空间和目标空间出现重叠,就得使用memmove 函数处理。
 
※source和destination的关系有6种(大类5种),分别如下图所示:
 显然,最后一种情况会发生内存重叠,因此需要分情况实现模拟代码,并且我们可以通过从后往前拷贝的方式解决重叠问题。
 
·模拟实现:
#include<stdio.h>
#include<assert.h>

char* my_mommove(void* des, const void* src, size_t count)
{
	assert(des != NULL);
	assert(src != NULL);
	char* pdes = (char*)des;
	char* psrc = (char*)src;
	if (psrc >= pdes || pdes >= psrc + count)
	{
		while (count-- > 0)
		{
			*pdes = *psrc;
			pdes++;
			psrc++;
		}
	}
	else
	{
		pdes = pdes + count - 1;
		psrc = psrc + count - 1;
		while (count-- > 0)
		{
			*pdes =*psrc;
			pdes--;
			psrc--;
		}
	}
	return des;
}

void main()
{
	char str1[20] = "abcdefghijk";
	my_mommove(str1+2,str1,3);
	printf("%s\n", str1);
}
12.memcmp
 
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
 
·比较从 ptr1 ptr2 指针开始的 num 个字节。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值