C语言进阶
第一章:指针、数组与函数
第二章:回调函数
第三章:字符串函数与内存函数
第四章:结构体、枚举、联合
第五章:通讯录
第六章:动态内存管理
第七章:文件操作
第八章:程序环境与预处理
文章目录
前言
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个字节
- 返回值如下:
(4) memset
void * memset ( void * ptr, int value, size_t num );
- 将ptr指向的内存块的前字节数设置为指定值(解释为无符号字符)。
总结
学会C的库函数的定义,试着去模拟实现。