第三章:C语言进阶之字符串函数与内存函数

C语言进阶

第一章:指针、数组与函数
第二章:回调函数
第三章:字符串函数与内存函数
第四章:结构体、枚举、联合
第五章:通讯录
第六章:动态内存管理
第七章:文件操作
第八章:程序环境与预处理


文章目录

  • C语言进阶
  • 前言
  • 一、字符串函数
    • (1) strlen
      • 模拟实现
    • (1) strcpy
      • 模拟实现
    • (2) strcat
      • 模拟实现
    • (3) strcmp
      • 模拟实现
    • (4) strncpy
    • (5) strncat
    • (6) strncmp
    • (1) strstr
      • 模拟实现
    • (2) strtok
    • (1) strerror
    • (2) perror
    • (1) tolower
    • (2) toupper
  • 二、内存函数
    • (1) memcpy
      • 模拟实现
    • (2) memmove
      • 模拟实现
    • (3) memcmp
    • (4) memset
  • 总结


前言

C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。
字符串常量适用于那些对它不做修改的字符串函数.


一、字符串函数

(1) strlen

size_t strlen ( const char * str );
  • 字符串已经’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现的字符个数(不包含’\0’)。
  • 参数指向的字符串必须要以’\0’结束。
  • 注意函数的返回值为size_t,是无符号的(易错)

模拟实现

size_t my_strlen(const char* str)
{
	char* start = str;
	char* end = str;
	while(*end != '\0')
	{
		end++;
	}
	return end - start;
}

长度不受限制的字符串函数(‘\0’)

(1) strcpy

char* strcpy(char * destination, const char * source );
  • Copies the C string pointed by source into the array pointed by
    destination, including the terminating null character (and stopping
    at that point).
  • 源字符串必须以’\0’结束。
  • 会将源字符串中的’\0’拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可变。

模拟实现

char* mystrcpy(char* dest, const char* src) {
	assert(dest);
	assert(src);
	char* ret = dest;
	while (*dest++ = *src++) {
		;
	}
	return ret;
} 

(2) strcat

char * strcat ( char * destination, const char * source );
  • Appends a copy of the source string to the destination string. The
    terminating null character in destination is overwritten by the first
    character of source, and a null-character is included at the end of
    the new string formed by the concatenation of both in destination.
  • 源字符串必须以’\0’结束。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。

模拟实现

char* mystrcat(char* dest, const char* src) {
	assert(dest);
	assert(src);
	char* ret = dest;
	while (*dest != '\0') {
		dest++;
	}
	while (*dest++ = *src++) {
		;
	}
	return ret;
}

(3) strcmp

int strcmp ( const char * str1, const char * str2 );
  • This function starts comparing the first character of each string. If
    they are equal to each other, it continues with the following pairs
    until the characters differ or until a terminating null-character is
    reached.

  • 标准规定:

    • 第一个字符串大于第二个字符串,则返回大于0的数字
    • 第一个字符串等于第二个字符串,则返回0
    • 第一个字符串小于第二个字符串,则返回小于0的数字

模拟实现

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

长度受限制的字符串函数

(4) strncpy

char * strncpy ( char * destination, const char * source, size_t num );
  • Copies the first num characters of source to destination. If the end
    of the source C string (which is signaled by a null-character) is
    found before num characters have been copied, destination is padded
    with zeros until a total of num characters have been written to it.
  • 拷贝num个字符从源字符串到目标空间。
  • 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

(5) strncat

char * strncat ( char * destination, const char * source, size_t num );
  • Appends the first num characters of source to destination, plus a
    terminating null-character.
  • If the length of the C string in source is less than num, only the
    content up to the terminating null-character is copied.

(6) strncmp

int strncmp ( const char * str1, const char * str2, size_t num );
  • 比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。

字符串查找函数

(1) strstr

char * strstr ( const char *str1, const char * str2);
  • Returns a pointer to the first occurrence of str2 in str1, or a null
    pointer if str2 is not part of str1.

  • 在一个字符串中找另一个字符串是否存在 存在:返回第一个子字符串首地址 不存在:NULL

模拟实现

char* strstr(const char* str1, const char* str2){
	assert(str1 && str2);
	while (*str1 != '\0') {
		if (*str1 == *str2) {
			char* ret1 = str1;
			char* ret2 = str2;
			while (*str1++ == *str2++) {
				if (*str2 == '\0') {
					return ret1;
				} 
			}
			str2 = ret2;
			str1 =++ret1;
		}
		else {
			str1++;
		}
	}
	return NULL;
}

(2) strtok

char * strtok ( char * str, const char * sep );
  • sep参数是个字符串,定义了用作分隔符的字符集合
  • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
  • strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容 并且可修改。)
  • strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串 中的位置。
  • strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找下一个标 记。
  • 如果字符串中不存在更多的标记,则返回NULL指针。

错误信息报告函数

(1) strerror

char * strerror ( int errnum );

返回错误码,所对应的错误信息。

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

}

结果如下:

No error
Operation not permitted
No such file or directory
No such process
Interrupted function call

0、1、2等是错误码,是C语言中库函数报错的时候的错误码。
库函数会产生错误码并返回到错误码变量(全局变量)中:errno

printf("%s",strerror(errno));

(2) perror

void perror ( const char * str );
  • 将errno的值解释为错误消息,并将其打印到stderr(标准错误输出流,通常是控制台),可以选择在其前面加上str 中指定的自定义消息。

字符分类函数

函数 如果他的参数符合下列条件就返回真
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 任何可打印字符,包括图形字符和空白字符

字符转换函数

(1) tolower

int tolower ( int c );

(2) toupper

int toupper ( int c );

二、内存函数


内存操作函数

(1) memcpy

void * memcpy ( void * destination, const void * source, size_t num );
  • 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
  • 这个函数在遇到’\0’的时候并不会停下来。
  • 如果source和destination有任何的重叠,复制的结果都是未定义的。
  • memcpy只需要实现不重叠的拷贝就可以了

模拟实现

void* my_memcpy(void* dest, const void* src, size_t num) {
	int i = 0;
	assert(dest && src);
	void* ret = dest;
	for (i = 0; i < num; i++) {
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

(2) memmove

void * memmove ( void * destination, const void * source, size_t num );
  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
  • memmove是需要实现重叠内存的拷贝的

模拟实现

void* my_memcpy(void* dest, const void* src, size_t num) {
	int i = 0;
	assert(dest && src);
	void* ret = dest;
	if (dest < src) {
		for (i = 0; i < num; i++) {
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}//前—>后
	else {
		for (i = num; i > 0; i--) {
			*((char*)dest + i) = *((char*)src + i);
		}
	}//后—>前
	return ret;
}

(3) memcmp

int memcmp ( const void * ptr1, 
             const void * ptr2, 
             size_t num );
  • 比较从ptr1和ptr2指针开始的num个字节
  • 返回值如下:第三章:C语言进阶之字符串函数与内存函数_第1张图片

(4) memset

void * memset ( void * ptr, int value, size_t num );
  • 将ptr指向的内存块的前字节数设置为指定值(解释为无符号字符)。

总结

学会C的库函数的定义,试着去模拟实现。

你可能感兴趣的:(#,C语言进阶,c语言)