[C语言基础]11.字符串函数和内存函数

11.1求字符串长度

strlen

Get the length of a string.
size_t strlen( const char *string );

typedef unsigned int size_t;
strlen 返回值为 unsigned int
strlen返回字符串中 \0 前面出现的字符个数
参数指向的字符串必须要以\0 结束

int main() {
	char arr[] = "hello ruarua";
	printf("%u\n", strlen(arr));
	return 0;
}

strlen simulation

//方案1.计数器
size_t my_strlen(const char* str){
	int count = 0;
	while (*str != '\0') {
		count++;
		str++;
	}
	return count;
}
//方案2.指针-指针
size_t my_strlen(const char* str) {
	char* end = str;
	while (*end != '\0')
		end++;
	return end - str;
}
//方案3.递归
size_t my_strlen(const char* str) {
	if (*str == 0)
		return 0;
	else
		return 1 + my_strlen(str + 1);
}

int main() {
	int sz = my_strlen("ruarua");
	printf("%u\n", sz);//%u unsigned int
	return 0;
}

11.2长度不受限制的字符串函数

strcpy

Copy a string.
char *strcpy( char *strDestination, const char *strSource );

源字符串必须以\0结束,\0会拷贝到目标空间
目标空间必须足够大,以确保能存放源字符串
目标空间必须可修改

int main() {
	char arr1[20] = { 0 };
	char arr2[] = "hello ruarua";
	//char arr2[] = {'r','u','a'};//没有'\0' err
	strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

strcpy simulation

#include <assert.h>
char* my_strcpy(char* dest, const char* src) {
	assert(dest != NULL);
	assert(src != NULL);
	char* ret = dest;
	while (*src != '\0') {
		*dest = *src;
		dest++;
		src++;
	}
	*dest = *src;//copy '\0'
	return ret;
}
//简化-->
char* my_strcpy(char* dest, const char* src) {
	assert(dest != NULL);
	assert(src != NULL);
	char* ret = dest;
	while (*dest++ = *src++) {
		;
	}
	return ret;
}

int main() {
	char arr1[20] = { 0 };
	char arr2[] = "hello ruarua";
	printf("%s\n", my_strcpy(arr1, arr2));//链式访问
	return 0;
}

strcat

Append a string.
char *strcat( char *strDestination, const char *strSource );

源字符串必须以 ‘\0’ 结束
目标空间必须有足够的大,能容纳下源字符串的内容
目标空间必须可修改

int main() {
	char arr1[20] = "hello";
	char arr2[] = "world";
	strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

helloworld

strcat simulation

#include <assert.h>
char* my_strcat(char* dest, const char* src) {
	assert(dest);
	assert(src);
	char* ret = dest;
	//1.find dest's \0
	while (*dest) {
		dest++;
	}
	//2.copy
	while (*dest++ = *src++) {
		;
	}
	return ret;
}

int main() {
	char arr1[20] = "hello";
	char arr2[] = "world";
	my_strcat(arr1, arr2);
	printf("%s\n", arr1);//无法给自己追加,因为判断条件\0会被追加掉
	return 0;
}

strcmp

Compare strings.
int strcmp( const char *string1, const char *string2 );

逐字符对比ASCII大小
str1 > str2, return > 0 返回大于0的数字
str1 = str2, return 0
str1 > str2, return < 0

int main() {
	int ret = strcmp("abcdef", "abq");
	printf("%d\n", ret);
	return 0;
}

-1

strcmp simulation

int  my_strcmp(const char* str1, const char* str2) {
	while (*str1 == *str2) {
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	return (*str1 - *str2)
}

int main() {
	int ret = my_strcmp("abcdef", "abq");
	printf("%d\n", ret);
	return 0;
}

11.3长度受限制的字符串函数

strncpy

Copy characters of one string to another.
char *strncpy( char *strDest, const char *strSource, size_t count );

拷贝num个字符从源到目标空间。
源长度小于num,拷贝源之后,在后边追加0到num个

int main() {
	char arr1[20] = "abcdef";
	char arr2[] = "xxxxxxxx";
	strncpy(arr1, arr2, 3);
	printf("%s\0", arr1);
	return 0;
}

xxxdef

int main() {
	char arr1[20] = "abcdef";
	char arr2[] = "xxx";
	strncpy(arr1, arr2, 6);
	printf("%s\0", arr1);
	return 0;
}

xxx

strncat

Append characters of a string.
char *strncat( char *strDest, const char *strSource, size_t count );
int main() {
	char arr1[20] = "abcdef";
	char arr2[] = "xxxxxxxx";
	strncat(arr1, arr2, 5);
	printf("%s\0", arr1);
	return 0;
}

abcdefxxxxx

strncmp

Compare characters of two strings.
int strncmp( const char *string1, const char *string2, size_t count );

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

int main() {
	char arr1[] = "abcdefg";
	char arr2[] = "abcdxyz";
	printf("%d\n", strncmp(arr1, arr2, 4));
	return 0;
}

0

int main() {
	char arr1[] = "abcdefg";
	char arr2[] = "abcdxyz";
	printf("%d\n", strncmp(arr1, arr2, 5));
	return 0;
}

-1

11.4字符串查找

strstr

Find a substring.
char *strstr( const char *string, const char *strCharSet );

返回str1中str2字符首次出现的位置
找不到会返回空指针

int main() {
	char arr1[] = "abcdefabcdef";
	char arr2[] = "def";
	char* ret = strstr(arr1, arr2);
	if (*ret != NULL)
		printf("%s", ret);
	else
		printf("Not Find");
	return 0;
}

defabcdef

strstr simulation

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

int main() {
	char arr1[] = "bbccnnnews";
	char arr2[] = "cnn";
	char* ret = my_strstr(arr1, arr2);
	if (*ret != NULL)
		printf("%s", ret);
	else
		printf("Not Find");
	return 0;
}

ccnnnews
请添加图片描述

strtok

Find the next token in a string.
char *strtok( char *strToken, const char *strDelimit );

strDelimit:定界符: @ . --> char delimit[] = “@ .”;
strToken:由定界符分开的字符串:“192.168.1.1” ; “ruarua@mail.com”
strtok函数:找到str中下一个标记,将其置 ‘\0’ ,返回一个指向这个标记的指针。
(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改)

  • strToken不为 NULL ,函数将找到str中第一个标记,strtok函数保存它在字符串中的位置
  • strToken为 NULL ,函数将在同一字符串中被保存的位置开始,查找下一个标记
  • 如果字符串中不存在更多的标记,则返回 NULL 指针
int main() {
	char arr[] = "ruarua\@mail.com";
	char copy[20];
	strcpy(copy, arr);
	char sep[] = "@.";
	char* ret = strtok(copy, sep);//找到str第一个标记,strtok保存在字符串中的位置
	printf("%s\n", ret);
	ret = strtok(NULL, sep);//函数将在被保存的位置开始,查找下一个标记
	printf("%s\n", ret);
	ret = strtok(NULL, sep);
	printf("%s\n", ret);
	return 0;
}
int main() {
	char arr[] = "ruarua\@mail.com";
	char copy[20];
	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;
}
ruarua
mail
com

11.5错误信息报告

strerror

Get a system error message (strerror) or prints a user-supplied error message (_strerror).
char *strerror( int errnum );

库函数执行发生错误,将错误码存放在errno中,errno是C语言提供的一个全局变量
strerror返回errnum所对应的错误信息

int main() {
	int i = 0;
	for (i = 0; i < 10; i++) {
		printf("%d: %s\n",i, strerror(i));
	}
	return 0;
}
0: No error
1: Operation not permitted
2: No such file or directory
3: No such process
4: Interrupted function call
5: Input/output error
6: No such device or address
7: Arg list too long
8: Exec format error
9: Bad file descriptor
int main() {
	//操作文件
	//1.打开文件
	//2.读/写
	//3.关闭文件
	FILE* pf = fopen("c.txt", "r");
	if (pf == NULL) {
		printf("%s\n", strerror(errno));
		return 1;
	}
	fclose(pf);//关闭文件
	return 0;
}

No such file or directory

int main() {
	FILE* pf = fopen("c.txt", "r");
	if (pf == NULL) {
		perror("fopen");//打印 自定义信息+错误信息
		return 1;
	}
	fclose(pf);//关闭文件
	return 0;
}

fopen: No such file or directory

11.6字符操作

字符分类函数

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

字符转换

int tolower ( int c );//转小写
int toupper ( int c );//转大写
#include <ctype.h>
int main() {
	printf("%c\n", tolower('A'));//-->a
	printf("%c\n", toupper('a'));//-->A
	return 0;
}
int main() {
	char arr[20] = { 0 };
	gets(arr);//遇到空格继续读
	printf("%s\n", arr);
	char* p = arr;
	while (*p) {
		if (isupper(*p)) {
			*p = tolower(*p);
		}
		p++;
	}
	printf("%s\n", arr);
	return 0;
}
RUA RUA IS GOOD
RUA RUA IS GOOD
rua rua is good

11.7内存操作函数

memcpy

Copies characters between buffers.
void *memcpy( void *dest, const void *src, size_t count );

memcpy从source位置向后复制count个字节到destination内存位置
在遇到 ‘\0’ 时不会停下
source和destination有任何的重叠,复制的结果都是未定义的
拷贝完后返回目标空间其实地址

int main() {
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	//将arr1拷贝到arr2
	memcpy(arr2,arr1,40);
	int i = 0;
	for (i = 0; i < 20; i++) {
		printf("%d ", arr2[i]);
	}
	return 0;
}

1 2 3 4 5 6 7 8 9 10 0 0 0 0 0 0 0 0 0 0

int main() {
	float arr1[] = { 1.0,2.0,3.0 };
	float arr2[5] = { 0 };
	//将arr1拷贝到arr2
	memcpy(arr2, arr1, 8);
	int i = 0;
	for (i = 0; i < 5; i++) {
		printf("%f ", arr2[i]);
	}
	return 0;
}

1.000000 2.000000 0.000000 0.000000 0.000000

memcpy simulation

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


int main() {
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	//将arr1拷贝到arr2
	my_memcpy(arr2,arr1,20);
	int i = 0;
	for (i = 0; i < 20; i++) {
		printf("%d ", arr2[i]);
	}
	return 0;
}

1 2 3 4 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

memmove

Moves one buffer to another.
void *memmove( void *dest, const void *src, size_t count );

和memcpy的差别:memmove函数处理的源内存块和目标内存块是可以重叠的
src和dest出现重叠,使用memmove函数

int main() {
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//将arr1拷贝到arr1 + 3
	memmove(arr1 + 3, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++) {
		printf("%d ", arr1[i]);
	}
	return 0;
}

1 2 3 1 2 3 4 5 9 10

memmove simulation

my_memmove(arr1 + 3, arr1, 20);

正序会覆盖重叠部分,逆序即可
请添加图片描述

my_memmove(arr1, arr1 + 3, 20);

但此情况逆序会覆盖掉src
请添加图片描述

故分两种情况
dest < src -->
src < dest <–

void* my_memmove(void* dest, const void* src, size_t num) {
	void* ret = dest;
	assert(src && dest);
	if (dest < src) {//-->
		while (num--) {
			*(char*)dest = *(char*)src;//char* --> 1byte
			dest = (char*)dest + 1;//dest is void*
			src = (char*)src + 1;
		}
	}
	else {//<--
		while (num--) {
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}

int main() {
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//将arr1拷贝到arr1 + 3
	my_memmove(arr1 + 3, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++) {
		printf("%d ", arr1[i]);
	}
	return 0;
}

1 2 3 1 2 3 4 5 9 10

int main() {
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//将arr1+ 3 拷贝到arr1
	my_memmove(arr1, arr1 + 3, 20);
	int i = 0;
	for (i = 0; i < 10; i++) {
		printf("%d ", arr1[i]);
	}
	return 0;
}

4 5 6 7 8 6 7 8 9 10

memset

Sets buffers to a specified character.
void *memset( void *dest, int c, size_t count );

内存设置:将dest前count个字节设置成指定的character

int main() {
	char arr[] = "ruarua";
	memset(arr, 'x', 3);//3 byte
	printf("%s\n", arr);
	return 0;
}

xxxrua

int main() {
	int arr[10] = { 0 };
	memset(arr, 1, 10);//10 byte --> 1,以字节为单位,将前10个字节变成1
	int  i = 0;
	for (i = 0; i < 10; i++) {
		printf("%d ", arr[i]);
	}
	return 0;
}

16843009 16843009 257 0 0 0 0 0 0 0

memcmp

Compare characters in two buffers.
int memcmp( const void *buf1, const void *buf2, size_t count );

比较从buf1和buf2指针开始的count个字节

int main() {
	int arr1[] = { 1,2,3,4,5,6 };
	int arr2[] = { 1,2,3,4,100 };
	int ret = memcmp(arr1, arr2, 20);
	printf("%d\n", ret);
	return 0;
}

-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WangRuaRua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值