C 字符串、字符操作函数与内存操作函数

字符串操作函数

1.strcpy

char *strcpy( char *string1, const char *string2 );
将字符串string2复制到string1

//模拟实现:
#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* sour) {
	assert(dest && sour);
	char* ret = dest;
	while (*dest++ = *sour++) {
		;
	}
	return ret;
}
int main() {
	char str1[20] = "qwer";
	char str2[] = "asdfghjkl";
	printf("%s\n", my_strcpy(str1, str2));
	return 0;
}

2.strcmp

int strcmp( const char *string1, const char *string2 );
比较string1和string2,string1大返回>0的数,相等返回0,string2大返回<0的数
——不过这个函数是依次比较两字符串的每一个字符的ASCII码的大小(如下所示)

//虽然s1比s2“要长”,但下标5处s1的ASCII码值小于s2,所以输出-1
int main() {
	char s1[] = "abcdefwerty";
	char s2[] = "abcdegw";
	printf("%d", strcmp(s1, s2));
	return 0;
}
//模拟实现:
int my_strcmp(const char* str1, const char* str2) {
	assert(str1 && str2);
	while (*str1 == *str2++) {
		if (*str1 == 0) return 0;
		str1++; str2++;
	}
	//不相等肯定就大于或小于
	if (*str1 > *str2) return 1;
	else return -1;
}
int main() {
	char str1[20] = "qwer";
	char str2[] = "asdfghjkl";
	printf("%d", my_strcmp(str1, str2));
	return 0;
}

3.strcat

char *strcat( char *string1, const char *string2 );
将string2中的字符串连接到string1上

char* my_strcat(char* dest, const char* src) {
	assert(dest && src);
	char* ret = dest;
	while (*dest) {
		dest++;
	}
	while (*dest++ = *src++) {
		;//但这么写当自己连接自己的时候就会出问题——但管他呢
	}
	return ret;
}
int main() {
	char str1[20] = "qwer";
	char str2[] = "asdfghjkl";
	printf("%s", my_strcat(str1, str2));
	return 0;
}

4.strncpy strncmp strncat(长度受限的函数)

示例(长度受限)

int main() {
	char str1[20] = "qwer";
	char str2[] = "asdfghjkl";
	printf("%s", strncpy(str1,str2,3));//打印出来 asdr	如果str2要拷贝15个字符到str1里,长度不够则会用\0填充
	return 0;
}

5.strstr

char *strstr( const char *string1, const char *string2);
看string2是不是string1的子字符串(看string里有没有string2)
(如果是子字符串的话)返回值为string2在string1中第一次出现的位置,(不是)返回值为空指针

//模拟实现
char* my_strstr(const char* str1, const char* str2) {
	assert(str1 && str2);
	char* ret = NULL;
	char* p = str2;
	while (*str1) {
		if (*str1 == *p) {
			ret = str1;
			while (*str1 == *p) {
				str1++; p++;
				if (*p == '\0') return ret;
			}
			p = str2;//重置p
		}
		else
			str1++;
	}
	return NULL;
}
int main() {
	char str1[20] = "qweqwer";
	char str2[] = "qwer";
	printf("%s", my_strstr(str1,str2));
	return 0;
}

6.strtok(知道怎么用即可)

char *strtok( char *str, const char *sep );
如果我有 hazb@139.com 这样一个邮箱并想要将其中的 hazb 139 com 分离出来,则可以用这个函数
● sep 指定一个字符串,定义了用作分割的字符集合(上方例子的sep为 “@.” )
● strtok找到str中的下一个标记并将其用 \0 结尾,返回一个指向这个标记的指针(strtok会改变被操作的字符串,所以用strtok切分的字符串一般都是临时拷贝的内容并且可修改)
● strtok 函数的第一个参数不为 NULL 时,函数将找到str中的第一个标记,strtok 函数将保存它在字符串中的位置
● strtok 函数的第一个参数为 NULL 时,函数将在同一个字符串中被保存的位置开始,查找下一个标记
●如果字符串中不存在更多的标记,则返回空指针

//示例
int main() {
	char str1[20] = "hazb@139.com";
	const char* str2 = "@.";
	printf("%s\n", strtok(str1,str2));//输出hazb
	printf("%s\n", strtok(NULL, str2));//输出139
	printf("%s\n", strtok(NULL, str2));//输出com
	printf("%s\n", strtok(NULL, str2));//在我的编译器上输出了(null)
	return 0;
}

这个示例过于繁琐,也不可能这样使用,所以我们加以改进

int main() {
	char arr[30] = "hazb@139.com@tyu@789.gbn";
	char tmp[50] = "\0";
	strcpy(tmp, arr);//临时拷贝
	const char* sep = "@.";
	char* str = NULL;
	for (str = strtok(tmp, sep); str != NULL; str = strtok(NULL, sep)) {
		printf("%s\n", str);
	}
	return 0;
}

7.strerror

char* strerror ( int errnum );
传入返回错误码,返回所对应的错误信息(的字符串)地址

int main(){
	printf("%s\n",strerror(0));
	printf("%s\n",strerror(1));
	printf("%s\n",strerror(2));
	return 0;
}

使用示例

int main() {
	//下面malloc理应开辟不了这么大一块空间,错误码errno更新
	int* p = (int*)malloc(INT_MAX);//不知道为什么我没有引用<limits.h>头文件也能用
	if( p == NULL){
		printf("%s\n", strerror(errno));//不知道为什么我没有引用<errno.h>头文件也能用,不过无所谓啦
		return 1;
	}
	return 0;
}

strerrorperror

int main() {
	int* p = (int*)malloc(INT_MAX);
	printf("%s\n", strerror(errno));//strerror需要传入错误码,借助printf这种输出函数才能将错误打印出来
	perror("malloc");//perror直接打印错误,并贴心地在前面加上了一个:
	return 0;
}

字符操作函数

1.字符分类函数 <ctype.h>

诸如:

函数参数符合下列条件则返回真
iscntrl任何控制字符
isspace空白字符 空格’ ’ 换行’\n’ 回车’\r’ 制表符’\t’ 垂直制表符’\v’
isdigit十进制数字 0~9
islower小写字母 a~z
isupper大写字母 A~Z
isalpha字母 a~z 或 A~Z
isalnum字母或数字 a~z A~Z 0~9
ispunct标点符号,任何不属于数字或字母的图形字符(可打印)
…………

以上函数参数和返回值如下:
int isdigit(int c)

使用示例(使代码更加规范化)

#include<ctype.h>
int main() {
	char ch = 'p';
	if (ch >= 'a' && ch <= 'z') {
		printf("这是小写字母\n");
	}
	if (islower(ch)) {
		printf("这是小写字母\n");
	}
	return 0;
}

2.字符转换函数

int tolower ( int c ); 大写转小写
int toupper ( int c ); 小写转大写

内存操作函数

1.memcpy

void *memcpy( void *dest, const void *src, size_t count );
和strncpy不同在于:
strcpy 只能复制 字符串 ,而memcpy可以复制任意内容,例如 字符数组 、整型、 结构体 、类等。

void* my_memcpy(void* dest, const void* src, size_t count) {
	assert(dest && src);
	char* ret = dest;
	while (count) {
		*((char*)dest)++ = *((char*)src)++;
		count--;
	}
	return ret;
}
int main() {
	//char arr1[30] = "hello boy";
	//char arr2[] = "I'm fine,thanks";
	//printf("%s\n", my_memcpy(arr1, arr2, 5));
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memcpy(arr1 + 2, arr1, 20);
	for (int i = 0; i < 10; i++) { printf("%d ", arr1[i]); }
	//如果这里我希望结果为1 2 1 2 3 4 5 8 9,显然memcpy做不到,这种 重叠内存 的拷贝理应交由mommove做
	//不过上面那句话是针对我们自己模拟实现的这个memcpy而言的,随着编译器的发展,拿Visual Stdio为例,其中的memcpy的功能和memmove已经一样了
	return 0;
}

2.memmove

void *memmove( void *dest, const void *src, size_t count );
memcpy函数的升级版,解决了原来memcpy不能处理重叠内存拷贝的问题

//模拟实现
//大体思路:dest在src前则从前向后拷贝,dest在src后则从后向前拷贝
void* my_memmove(void* dest, const void* src, size_t count) {
	//按道理说应该针对覆盖的问题区分从后向前还是从前向后
	//一般说数组内都是从低地址到高地址
	char* _dest = (char*)dest;
	char* _src = (char*)src;
	if (_dest < _src) {//高地址往低地址拷
		while (count--) { 
			*(_dest++) = *(_src++);
		}
	}
	else {//低地址往高地址拷
		_dest = (char*)dest + count - 1;
		_src = (char*)src + count - 1;
		while (count--) {
			*(_dest--) = *(_src--);
		}
	}
	return dest;
}
int main() {
	char str1[] = "123456789";	char str2[] = "123456789";
	my_memmove(str1 + 2, str1, 5);	my_memmove(str2, str2 + 2, 5);
	printf("%s\n%s", str1, str2);
	return 0;
}

3.memcmp

void *memcpy( void *dest, const void *src, size_t count );
与strncmp大同小异,不过不止可以比较字符串

4.memset

void *memset( void *dest, int c, size_t count );
将从dest开始的count个字节的值设置为c

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值