字符函数、字符串函数、内存函数

目录

求字符串长度:

size_t  strlen ( const char * str );

 无长度限制的字符串函数

字符串拷贝:

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

字符串追加:

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

字符串比较:

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

有长度限制的字符串函数

字符串拷贝:

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

 字符串追加:

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

 字符串比较:

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

字符串查找函数

在字符串中查找字符:

char * strchr ( const char * str, int character );

在一个字符串中查找另个一个字符串:

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

 字符串分割:

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

 获取错误信息:

 char * strerror ( int errnum );

 字符操作函数

字符分类函数:

字符转换函数:

int tolower ( int ch );

int toupper ( int ch );

 内存操作函数

内存拷贝:

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

 内存移动:

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

 内存比较:

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

 内存填充:

void * memset ( void * ptr, int value, size_t num )

 

  • 求字符串长度:

size_t  strlen ( const char * str );

  • 字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' );
  • str 指向的字符串必须要以 '\0' 结束;
  • 注意函数的返回值为size_t,是无符号的;
  • 若str 指向的字符串中有多个 ' \0 ',则strlen返回的是第一个' \0 '前的字符的个数。

 有如下代码:

#include<stdio.h>
int main()
{
	char arr1[] = "asdfghjkl";
	int len1 = strlen(arr1);
	char arr2[] = "asdf\0ghjkl";
	int len2 = strlen(arr2);
	printf("len1=%d\n", len1);
	printf("len2=%d\n", len2);
	return 0;
}

arr2数组比arr1数组中间多了一个' \0 ',因此使用strlen函数时,len1应为9,len2应为4。

代码运行结果:

 用自定义函数实现:

int mystrlen(char* str)
{
	int count = 0;
	while (*str!='\0')
	{
		count++;
		str++;
	}
	return count;
}

 实例:

 

  •  无长度限制的字符串函数

字符串拷贝:

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

  • 将source指向的字符串复制到destination指向的空间中,包括终止空字符(并在该点停止)。
  • source指向的字符串不能为空,且必须以 '\0' 结束;
  • 会将source指向的字符串中的 '\0' 拷贝到destination指向的空间中。
  • destination指向的空间必须足够大,以确保能存放source指向的字符串。
  • destination指向的空间必须可变。
  • destination指向的空间与source指向的空间不应有重叠。
  • 与strlen类似,strcpy遇到第一个‘ \0 ’时就会终止。

有如下代码:

int main()
{
	char str[] = "asdfg\0hgfd";
	char str1[] = "Sample string";
	char str2[40] = { 0 };
	char str3[40] = { 0 };
	char str4[40] = { 0 };
	strcpy(str2, str1);
	strcpy(str3, "copy successful");
	strcpy(str4, str);
	printf("str1: %s\n", str1);
	printf("str2: %s\n", str2);
	printf("str3: %s\n", str3);
	printf("str4: %s\n", str4);
	return 0;
}

运行结果:

 用自定义函数实现:

char* mystrcpy(char* des, const char* sour)
{
	char* cur = des;
	assert(des);
	assert(sour);
	while (*cur++ = *sour++)
	{
		;
	}
	return des;
}

实例:

 

字符串追加:

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

  • 将source指向的字符串追加到destination后边,若destination后边有‘  \0 ’,会覆盖掉‘ \0 
  • destination指向的空间必须可修改且足够大。
  • source指向的字符串不能为空,且必须以 '\0' 结束。
  • destination指向的空间和source指向的空间不可重叠。
  • 与strlen、strcpy类似,strcat遇到第一个‘ \0 ’时就会终止。

有如下代码:

int main()
{
	char str[80] = { 0 };
	strcpy(str, "these ");
	strcat(str, "strings ");
	strcat(str, "are ");
	strcat(str, "concat\0enated.");
	puts(str);
	return 0;
}

运行结果:

 自定义函数实现:

char* mystrcat(char* des,const char* sour)
{
	assert(des);
	assert(sour);
	char* cur = des;
	while (*cur)//找到尾
	{
		cur++;
	}
	while (*cur++ = *sour++)
	{
		;
	}
	return des;
}

运行实例:

字符串比较:

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

  • 比较两个字符串str1和str2
  • 从第一个字符开始依次比较,直至字符不同或到达终止字符
  • 比较两个字符时,比较的是ASCII码
  • 返回值表明
    <0两个内存块中不匹配的第一个字节在 ptr1 中的值低于 ptr2 中的值
    0两个内存块的内容相等
    >0两个内存块中不匹配的第一个字节在 ptr1 中的值大于在 ptr2 中的值

有如下代码:

int main()
{
	char str1[] = "abcdefg";
	char str2[] = "abcdegh";
	if (strcmp(str1, str2) > 0)
	{
		printf("str1>str2\n");
	}
	else if(strcmp(str1, str2) == 0)
	{
		printf("str1=str2\n");
	}
	else
	{
		printf("str1<str2\n");
	}
	return 0;
}

运行结果:

 自定义函数实现:

int mystrcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);

	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;

		str1++;
		str2++;
	}

	return (*str1 - *str2);
}

实例:

  • 有长度限制的字符串函数

字符串拷贝:

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

  • 从source指向的字符串中拷贝num个字符到destination在指向的空间中
  • destination指向空间要大于num个字节,否则无法在结尾追加终止字符
  • destination指向的空间和source指向的空间不能有重叠
  • 若source指向的字符串长度小于num,则拷贝完source指向的字符串后,继续在后边追加0,直至num个
  • 若source指向的字符串长度大于等于num,则拷贝num个字符后停止,不会自动加‘ \0 ’

有如下代码:

int main()
{
	char str1[]   = "To be or not to be";
	char str2[40] = "asdfghjklopiuytrewqbnchux";
	char str3[40];
	char str4[40];
	char str5[40];
	char str6[18];
	char str7[10];
	//拷贝长度等于str1长度
	strncpy(str2, str1, strlen(str1));
	//拷贝长度小于str1长度
	strncpy(str3, str2, 5);
	//拷贝长度等于str1长度
	strncpy(str4, str1, strlen(str1));
	//拷贝长度大于str1长度
	strncpy(str5, str1, strlen(str1) + 5);
	//目的地空间等于拷贝长度
	strncpy(str6, str1, strlen(str1));
	//目的地空间小于拷贝长度
	strncpy(str7, str1, strlen(str1));
	puts(str1);
	puts(str2);
	puts(str3);
	puts(str4);
	puts(str5);
	puts(str6);
	puts(str7);
	return 0;
}

运行结果:

 自定义函数实现:

char* mystrncpy(char* des, const char* sour, int num)
{
	assert(des);
	assert(sour);
	assert(num >= 0);
	char* cur = des;
	while (num)
	{
		if (*sour == '\0')
		{
			break;
		}
		*cur++ = *sour++;
		num--;
	}
	if (num != 0)
	{
		while (num--)
		{
			*cur++ = '\0';
		}
	}
	return des;
}

实例:

 字符串追加:

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

  • 在destination指向字符串末尾追加source指向字符串的前num个字符,并额外追加一个终止字符。
  • 若num大于source指向字符串长度,则仅复制终止字符之前的内容。

有如下代码:

int main()
{
	char str[] = "asdfg\0hjk";
	char str1[6] = "e";
	char str2[10] = "q";
	char str3[10] = "w";
	strncat(str1, str, 9);
	strncat(str2, str, 9);
	strncat(str3, str, 3);
	puts(str1);
	puts(str2);
	puts(str3);
	return 0;
}

运行结果:

 观察可以发现即使str1指向空间不够额外追加终止字符,strncat也会在str1指向空间后边强制追加一个终止字符。                                                                                                                                   自定函数实现:

char* mystrncat(char* des, const char* sour, int num)
{
	assert(des);
	assert(sour);
	assert(num >= 0);
	char* cur = des;
	while (*cur)
	{
		cur++;
	}
	while (num)
	{
		if (*sour == '\0')
		{
			break;
		}
		*cur++ = *sour++;
		num--;
	}
	*cur = '\0';
	return des;
}

实例;

 字符串比较:

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

  • 比较两个字符串str1和str2前num个字符
  • 从第一个字符开始依次比较,直至字符不同或到达终止字符或到达第num个字符
  • 比较两个字符时,比较的是ASCII码
  • 返回值表明
    <0两个内存块中不匹配的第一个字节在 ptr1 中的值低于 ptr2 中的值
    0两个内存块的内容相等
    >0两个内存块中不匹配的第一个字节在 ptr1 中的值大于在 ptr2 中的值

有如下代码:

int main()
{
	char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
	int n;
	for (n = 0; n < 3; n++)
	{
		//找前两个字符为“R2”的字符串
		if (strncmp(str[n], "R2xx", 2) == 0)
		{
			printf("found %s\n", str[n]);
		}
	}
	return 0;
}

运行结果:

 自定义函数实现:

int mystrncmp(const char* str1, const char* str2, int num)
{
	assert(str1 && str2);
	assert(num > 0);
	while ((*str1 == *str2) && num--)
	{
		if (*str1 == '\0'||num == 0)
		{
			return 0;
		}
		str1++;
		str2++;
	}
	return (*str1 - *str2);
}

实例:

  • 字符串查找函数

在字符串中查找字符:

char * strchr ( const char * str, int character );

  • 在字符串str中找字符character,并返回指向该字符的指针,若找不到返回NULL
  • 终止字符‘ \0 ’也被视为字符串str的一部分,因此也可以查找。
  • 字符character以int类型传递,但在内部会转换为char类型进行查找。

有如下代码:

int main()
{
	char str[] = "This is a sample string";
	char* pch = NULL;
	printf("Looking for the 's' character in \"%s\"\n", str);
	pch = strchr(str, 's');
	while (pch != NULL)
	{
		printf("found at %d\n", pch - str + 1);
		pch = strchr(pch + 1, 's');
	}
	int len = strlen(str);
	printf("len = %d\n", len);
	pch = strchr(str, '\0');
	printf("pch - str = %d\n", pch - str);
	return 0;
}

运行结果:

 自定义函数实现:

char* mystrchr(const char* str, int ch)
{
	assert(str);
	if (ch == '\0')
	{
		while (*str)
		{
			str++;
		}
		return str;
	}
	while (*str)
	{
		if (*str == ch)
		{
			return str;
		}
		str++;
	}
	return NULL;
}

实例:

​​​​​​​

在一个字符串中查找另个一个字符串:

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

  • 在str1中找str2第一次出现的位置并返回该位置的指针,否则返回NULL
  • 匹配过程不包括‘ \0 ’

有如下代码:

int main()
{
	char str[] = "This is a simple string";
	char* pch;
	pch = strstr(str, "simple");
	puts(pch);
	if (pch != NULL)
	{
		strncpy(pch, "SAMPLE", 6);
	}
	puts(pch);
	return 0;
}

运行结果:

 自定义函数实现:

char* mystrstr(const 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;
}

实例:

 字符串分割:

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[] = "asdfgh@yeah.net@666#777";
	char copy[30];
	strcpy(copy, arr);

	char sep[] = "@#.";
	char* ret = NULL;

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

运行结果:

  •  获取错误信息:

 char * strerror ( int errnum );

  • 返回错误码errnum所对应的错误信息

 有如下代码:打印错误码0~9所对应的错误信息

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

运行结果:

  •  字符操作函数

 使用字符操作函数徐要包含头文件<ctype.h>

字符分类函数:

函数如果他的参数符合下列条件就返回真
iscntrl任何控制字符
isspace空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v'
isdigit十进制数字 0~9
isxdigit十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F
islower小写字母a~z
isupper大写字母A~Z
isalpha字母a~z或A~Z
isalnum字母或者数字,a~z,A~Z,0~9
ispunct标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph任何图形字符
isprint任何可打印字符,包括图形字符和空白字符

字符转换函数:

int tolower ( int ch );

  • 若ch是大写字母,则转换为小写字母

int toupper ( int ch );

  • 若ch是小写字母,则转换为大写字母

有如下代码:

#include <ctype.h>
int main()
{
	int i = 0;
	char str[] = "Test String.";
	puts(str);
	char c;
	while (str[i])
	{
		c = str[i];
		if (isupper(c))
		{
			c = tolower(c);
		}
		putchar(c);
		i++;
	}
	printf("\n");
	i = 0;
	while (str[i])
	{
		c = str[i];
		if (islower(c))
		{
			c = toupper(c);
		}
		putchar(c);
		i++;
	}
	return 0;
}

运行结果:

  •  内存操作函数

内存函数的操作对象不再局限于字符串

内存拷贝:

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

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

有如下代码:

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 06 00 00 00

	int arr2[20] = { 0 };
	memcpy(arr2, arr1, 21);
	int i = 0;
	for (i = 0; i < 20; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

 运行结果:

 自定义函数实现:

void* mymemcpy(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(src && dest);

	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

实例:

 内存移动:

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

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

有如下代码:

int main()
{
	char str[] = "memmove can be very useful....?!";
	puts(str);
	memmove(str + 20, str + 15, 11);
	puts(str);
	return 0;
}

运行结果:

 自定义函数实现:

void* mymemmove(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;
}

实例:

 内存比较:

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

  • 比较从ptr1和ptr2指向位置开始的前num个字节的内容,如果它们都相等,则返回零,如果不匹配,则返回一个不同于零的值,表示哪个值更大。(注意:与 strcmp 不同,该函数在找到空字符后不会停止比较。)
  • 返回值表明
    <0两个内存块中不匹配的第一个字节在 ptr1 中的值低于 ptr2 中的值
    0两个内存块的内容相等
    >0两个内存块中不匹配的第一个字节在 ptr1 中的值大于在 ptr2 中的值

有如下代码:

int main()
{
	int arr1[] = { 1,2,3,4,5 };//01 00 00 00   02 00 00 00   03 00 00 00   04 00 00 00   05 00 00 00
	int arr2[] = { 1,2,257 };  //01 00 00 00   02 00 00 00   01 01 00 00 
	int ret = memcmp(arr1, arr2, 10);
	printf("%d\n", ret);
	return 0;
}

运行结果:

 自定义函数实现:

int mymemcmp(const void* str1, const void* str2, int len)
{
	assert(str1);
	assert(str2);
	while ((*(char*)str1 == *(char*)str2) && len--)
	{
		if (len == 0)
		{
			return 0;
		}
		str1 = (char*)str1 + 1;
		str2 = (char*)str2 + 1;
	}
	if (*(char*)str1 > *(char*)str2)
	{
		return 1;
	}
	if (*(char*)str1 < *(char*)str2)
	{
		return -1;
	}
}

实例:

 内存填充:

void * memset ( void * ptr, int value, size_t num );

  • 从ptr指向位置开始向后num个字节填充为value,且不会因遇到终止字符而停止

有如下代码:

int main()
{
	char arr[] = "hellohehe";
	memset(arr+1,'x',5);
	printf("%s\n", arr);
	return 0;
}

运行结果:

 自定义函数实现:

void* mymemset(void* ptr, int val, size_t num)
{
	assert(ptr);
	void* cur = ptr;
	while (num--)
	{
		*(char*)cur = val;
		cur = (char*)cur + 1;
	}
	return ptr;
}

实例:

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值