天天看点

『C』字符串/内存函数字符串函数字符分类函数内存函数

C语言中对字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串或字符数组中。

C函数库中提供了一些专门处理字符串的函数,使用方便。几乎所有版本的C语言编译系统都提供这些函数。

字符串函数

strlen

size_t strlen ( const char * str );
参数:
	str:指向的必须是C风格字符串,否则会出错。
返回值:size_t无符号长整型。返回结果为字符串中字符的个数,不包含'\0'。
           

模拟实现

#include <stdio.h>

size_t myStrlen(const char* str){
	if(str == NULL || *str == '\0'){
		return 0;
	}
	return 1 + myStrlen(str + 1);
}

int main(){
	char* str = "hello, world!";

	printf("The length of str is: %lu\n", myStrlen(str));

	return 0;
}
           

运行结果

[[email protected] string]$ gcc my_strlen.c -o my_strlen
[[email protected] string]$ ./my_strlen 
The length of str is: 13
           

strcpy

char * strcpy ( char * destination, const char * source );
参数:
	destination:目标。
	source:源。
返回值:destination。
注意:目标空间必须足够大。会将'\0'拷贝到目标空间。
           

模拟实现

#include <stdio.h>

char* myStrcpy(char* dest, const char* src){
	if(src == NULL || *src == '\0'){
		return dest;
	}

	char* temp = dest;

	while(*src != '\0'){
		*temp++ = *src++;
	}

	*temp = '\0';

	return dest;
}

int main(){
	char str[1024];

	printf("str: %s\n", myStrcpy(str, "hello, world!"));

	return 0;
}
           

运行结果

[[email protected] string]$ !gcc
gcc my_strcpy.c -o my_strcpy
[[email protected] string]$ ./my_strcpy 
str: hello, world!
           

strcat

char * strcat ( char * destination, const char * source );
参数:
	destination:目标。
	source:源。
返回值:destination。
注意:目标空间必须足够大。字符串不能自己追加自己(会把'\0'覆盖掉,陷入死循环)。
           

模拟实现

#include <stdio.h>

char* myStrcat(char* dest, const char* src){
	if(src == NULL || *src == '\0'){
		return dest;
	}

	char* temp = dest;
	while(*temp){
		++temp;
	}

	while(*src){
		*temp++ = *src++;
	}

	*temp = '\0';

	return dest;
}

int main(){
	char str[1024] = "hello, ";

	printf("str: %s\n", myStrcat(str, "world!"));

	return 0;
}
           

运行结果

[[email protected] string]$ gcc my_strcat.c -o my_strcat
[[email protected] string]$ ./my_strcat 
str: hello, world!
           

strcmp

int strcmp ( const char * str1, const char * str2 );
参数:
	str1:字符串1。
	str2:字符串2。
返回值:str1 > str2,返回值大于0。str1 < str2,返回值小于0。str1 == str2,返回值等于0。
           

模拟实现

#include <stdio.h>

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

int main(){
	char str1[] = "hello";
	char str2[] = "hello";

	int flag = myStrcmp(str1, str2);
	if(flag > 0){
		printf("%s > %s\n", str1, str2);
	}
	else if(flag < 0){
		printf("%s < %s\n", str1, str2);
	}
	else{
		printf("%s == %s\n", str1, str2);
	}

	return 0;
}
           

运行结果

[[email protected] string]$ !gcc
gcc my_strcmp.c -o my_strcmp
[[email protected] string]$ ./my_strcmp 
hello == hello
           

strncpy

char * strncpy ( char * destination, const char * source, size_t num );
参数:
	destination:目标。
	source:源。
	num:字符个数。
返回值:destination。
注意:如果源字符串长度小于num,则拷贝完源字符串之后,在目标后面追加'\0',直到num个。
           

模拟实现

#include <stdio.h>

char* myStrncpy(char* dest, const char* src, size_t num){
	if(src == NULL || *src == '\0'){
		return dest;
	}

	char* temp = dest;
	while(num && *src != '\0'){
		*temp++ = *src++;
		--num;
	}

	*temp = '\0';

	return dest;
}

int main(){
	char str[1024] = "hello, ";

	printf("str: %s\n", myStrncpy(str, "world!", 6));

	return 0;
}
           

运行结果

[[email protected] string]$ gcc my_strncpy.c -o my_strncpy
[[email protected] string]$ ./my_strncpy 
str: world!
           

strncat

char * strncat ( char * destination, const char * source, size_t num );
参数:
	destination:目标。
	source:源。
	num:字符个数。
返回值:destination被返回。
           

模拟实现

#include <stdio.h>

char* myStrncat(char* dest, const char* src, size_t num){
	if(src == NULL || *src == '\0' || num == 0){
		return dest;
	}

	char* temp = dest;
	while(*temp){
		++temp;
	}

	while(*src && num){
		*temp++ = *src++;
		--num;
	}

	*temp = '\0';

	return dest;
}

int main(){
	char str[1024] = "hello, ";

	printf("str: %s\n", myStrncat(str, "world!", 6));

	return 0;
}
           

运行结果

[[email protected] string]$ !gcc
gcc my_strncat.c -o my_strncat
[[email protected] string]$ ./my_strncat 
str: hello, world!
           

strncmp

int strncmp ( const char * str1, const char * str2, size_t num );
参数:
	str1:字符串1。
	str2:字符串2。
	num:字符个数。
返回值:str1 > str2,返回值大于0;str1 < str2,返回值小于0;str1 == str2,返回值等于0。
           

模拟实现

#include <stdio.h>

int myStrncmp(const char* str1, const char* str2, size_t num){
	while(*str1 == *str2 && *str1 && --num){
		++str1;
		++str2;
	}
	return *str1 - *str2;
}

int main(){
	char str1[] = "hello";
	char str2[] = "hello, world!";

	int flag = myStrncmp(str1, str2, 5);
	if(flag > 0){
		printf("%s > %s\n", str1, str2);
	}
	else if(flag < 0){
		printf("%s < %s\n", str1, str2);
	}
	else{
		printf("%s = %s\n", str1, str2);
	}

	return 0;
}
           

运行结果

[[email protected] string]$ !gcc
gcc my_strncmp.c -o my_strncmp
[[email protected] string]$ ./my_strncmp 
hello = hello, world!
           

strstr

const char * strstr ( const char * str1, const char * str2 );
      char * strstr (       char * str1, const char * str2 );
参数:
	str1:字符串1。
	str2:字符串2。
返回值:str2第一次出现在str1中的位置。
           

模拟实现

#include <stdio.h>

const char* myStrstr(const char* str1, const char* str2){
	while(*str1){
		const char* temp1 = str1;
		const char* temp2 = str2;
		while(*temp1 == *temp2 && *temp1){
			++temp1;
			++temp2;
		}
		if(!*temp2){
			return str1;
		}
		++str1;
	}
	return NULL;
}

int main(){
	char str1[] = "hello, world!";
	char str2[] = "world";

	printf("%s\n", myStrstr(str1, str2));

	return 0;
}
           

运行结果

[[email protected] string]$ !gcc
gcc my_strstr.c -o my_strstr
[[email protected] string]$ ./my_strstr 
world!
           

strtok

char * strtok ( char * str, const char * delimiters );
参数:
	str:字符串。
	delimiters:分隔符集合。
           

用法:

  • strtok函数第一个参数指定一个字符串,它包含了0个或者多个由delimiters字符串中一个或者多个分割符分割的标记。
  • strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)

    strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。

  • strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  • 如果字符串中不存在更多的标记,则返回NULL指针。

代码演示

#include <stdio.h>
#include <string.h>

int main(){
	char str[] = "- This, is .a -sample string.";
	char* pch;

	printf("Splitting string \"%s\" into tokens: \n", str);
	pch = strtok(str, " ,.-");
	while(pch != NULL){
		printf("%s\n", pch);
		pch = strtok(NULL, " ,.-");
	}

	return 0;
}
           

运行结果

[[email protected] string]$ gcc strtok.c -o strtok
[[email protected] string]$ ./strtok 
Splitting string "- This, is .a -sample string." into tokens: 
This
is
a
sample
string
           

strerror

char * strerror ( int errnum );
参数:
	errnum:错误码。
返回值:错误码所对应的错误信息。
           

代码演示

#include <stdio.h>
#include <errno.h>
#include <string.h>

int main(){
	FILE* fp = fopen("unexist.txt", "r");
	if(fp == NULL){
		printf("fopen error: %s\n", strerror(errno));
	}

	return 0;
}
           

运行结果

[[email protected] string]$ gcc strerror.c -o strerror
[[email protected] string]$ ./strerror 
fopen error: No such file or directory
           

字符分类函数

函数 参数符合下列条件返回真
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 c );
int toupper ( int c );
           

代码演示

#include <stdio.h>
#include <ctype.h>

int main(){
	char low, up;

	printf("Please input the lower and upper character: \n");
	scanf("%c %c", &low, &up);
	printf("toupper: %c\n", toupper(low));
	printf("tolower: %c\n", tolower(up));

	return 0;
}
           

运行结果

[[email protected] string]$ !gcc
gcc low_up.c -o low_up
[[email protected] string]$ ./low_up 
Please input the lower and upper character: 
c A
toupper: C
tolower: a
           

内存函数

memcpy

void * memcpy ( void * destination, const void * source, size_t num );
参数:
	destination:目标。
	source:源。
	num:字节数。
返回值:destination。
注意:遇到'\0'不会停下来。如果source和destination右任何的重叠,复制的结果是未定义的。
           

模拟实现

#include <stdio.h>

#define N 5

void* myMemcpy(void* dest, void* src, size_t num){
	char* temp_dest = (char*)dest;
	char* temp_src = (char*)src;

	while(num){
		*temp_dest++ = *temp_src++;
		--num;
	}

	return dest;
}

int main(){
	int arr[N] = {
		0, 1, 2, 3, 4
	};
	int dest[N] = {0};

	myMemcpy(dest, arr, N * sizeof(int));

	int i;
	for(i = 0; i < N; ++i){
		printf("%d ", dest[i]);
	}
	printf("\n");

	return 0;
}
           

运行结果

[[email protected] string]$ !gcc
gcc memcpy.c -o memcpy
[[email protected] string]$ ./memcpy 
0 1 2 3 4 
           

memmove

void * memmove ( void * destination, const void * source, size_t num );
参数:
	destination:目标。
	source:源。
	num:字节数。
返回值:destination。
注意:destination和source空间可以出现重叠。
           

模拟实现

#include <stdio.h>

#define N 5

void* myMemcpy(void* dest, void* src, size_t num){
	char* temp_dest = (char*)dest;
	char* temp_src = (char*)src;

	while(num){
		*temp_dest++ = *temp_src++;
		--num;
	}

	return dest;
}

void* myMemmove(void* dest, void* src, size_t num){
	if(dest >= src && dest <= src + num){
		char* temp_dest = (char*)dest;
		char* temp_src = (char*)src;
		int i = num - 1;
		for(i = num; i >= 0; --i){
			temp_dest[i] = temp_src[i];
		}
	}
	else{
		myMemcpy(dest, src, num);
	}

	return dest;
}

int main(){
	int arr[N] = {
		0, 1, 2, 3, 4
	};
	int dest[N] = {0};

	myMemmove(dest, arr, N * sizeof(int));

	int i = 0;
	for(; i < N; ++i){
		printf("%d ", dest[i]);
	}
	printf("\n");

	return 0;
}
           

运行结果

[[email protected] string]$ gcc memmove.c -o memmove
[[email protected] string]$ ./memmove 
0 1 2 3 4