目录
1.strcpy(strncpy)—— 字符串拷贝函数
2.strcat (strncat)—— 字符串追加函数
3.strcmp —— 字符串比较函数
4.strstr —— 字符串查找函数
5.strtok —— 字符串分割函数
6.strerror —— 分错误析原因函数
1.strcpy(strncpy)
strcpy:字符串拷贝函数,创建两个字符串,将源字符串拷贝至目标字符串。
strncpy:相对于strcpy,该函数相对安全,因为该函数考虑到目标字符串的长度,在一定程度上,有效减少了缓冲区溢出的风险以及可能导致的程序崩溃或被攻击者利用。
当然,值得注意的是,strncpy
会在目标字符串大小等于或超过源字符串长度时,不会自动添加字符串的终结符 \0
,因此在使用 strncpy
函数时,需要手动添加终止符以确保字符串的正确性。
首先,我们对比strcpy与strncpy的参数区别:
//strcpychar* strcpy(char* destination, const char* source); 目标字符串 待拷贝字符串 //strncpychar *strncpy(char *dest, const char *src, size_t n); 目标字符串 待拷贝字符串 需拷贝个数
strncpy
函数多了一个参数 n
,用于指定最多要拷贝的字符数。 在任何情况下,都要确保目标字符串有足够的空间来存放复制后的字符串内容,以避免缓冲区溢出问题。
接下来,我们对比观察strcpy与strncpy函数的模拟实现:
//strcpy#include<stdio.h>#include<assert.h>assert(dest != NULL);assert(src != NULL);char* ret = dest;while (src != '\0') {*dest = *src;src++;dest++;}*dest = *src;//拷贝最后一位‘\0’return ret; }int main() {char arr1[] = "abcdef";char arr2[] = "bcdefhijk";char* ptr = arr2;printf("%s\n",ptr);my_strcpy(arr2, arr1);//arr1的‘\o’也会被拷贝到arr2中printf("%s, %s",arr1,arr2);return 0;}
//strncpyvoid Strncpy(char* dest, const char* ptr, size_t num) {assert(dest && ptr);while (num) {*dest = *ptr;dest++;ptr++;num--;}}int main() {char arr[25] = "Fancy a boy!"; char src[] = "Lucky girl.";Strncpy(arr, src, 5);printf("%s\n", arr);return 0;}
2.strcat (strncat)
strcat:字符串追加函数,在于两个字符串之间,将源字符串追加至目标字符串之后。
strncat:与strcpy函数一样,使用方式更加安全,函数在将源字符串连接到目标字符串末尾时,需要额外指定最大要复制的字符数,可以避免缓冲区溢出的风险。
首先,我们对比strcat与strncat的参数区别:
//strcat char *strcat(char *dest, const char *src); 目标字符串 源字符串//strncat char *strncat(char *dest, const char *src, size_t n); 目标字符串 源字符串 需连接的字符数
接下来,我们对比观察strcat与strncat函数的模拟实现:
#include<stdio.h>#include<string.h>#include<assert.h>char* my_strcat(char* dest, const char* src) {assert(dest && src);char* ret = dest;//打印目标位置的‘\0’while (*dest != '\0') {dest++;}//拷贝while (*dest++ = *src++);//空语句return ret;}int main() {char arr1[15] = "Hello ";char arr2[] = "World!";my_strcat(arr1, arr2);//strcat(arr1, arr2);//strcat:用于连接字符串printf("%s\n", arr1);return 0;}
//strncat#include<stdio.h>#include<assert.h>char* Strncat(char* dest, const char* ptr, size_t num) {assert(dest && ptr);char* ret = dest;dest += num;while (*ptr!='\0') {*dest = *ptr;dest++;ptr++;}*dest = '\0';return ret;}int main() {char arr[] = "see you again";char src[] = "excuse";Strncat(arr, src, 4);printf("%s\n", arr);return 0;}
如果要进行字符串连接并且希望更加安全地控制连接字符数,建议使用 strncat
函数。如果确定目标字符串有足够的空间,并且不需要控制连接的字符数,可使用 strcat
函数。但在任何情况下,都要确保目标字符串的长度足够存放源字符串的内容,以避免缓冲区溢出问题。
3.strcmp
strcmp:字符串比较函数,用于比较两个字符串的大小关系。
int strcmp(const char *str1, const char *str2); 字符串1 字符串2
strcmp
函数会按字典顺序比较两个字符串 str1
和 str2
。返回值为整数,具体含义如下:
str1
小于 str2
,则返回负数;如果 str1
等于 str2
,则返回 0;如果 str1
大于 str2
,则返回正数。 接下来,我们对比观察strcmp函数的模拟实现:
#include <stdio.h>int my_strcmp(const char *str1, const char *str2) { while (*str1 && *str2 && *str1 == *str2) { str1++; str2++; } return (int)(*str1) - (int)(*str2);}int main() { char str1[] = "Hello"; char str2[] = "World"; int result = my_strcmp(str1, str2); if (result < 0) { printf("'%s' is less than '%s'\n", str1, str2); } else if (result == 0) { printf("'%s' is equal to '%s'\n", str1, str2); } else { printf("'%s' is greater than '%s'\n", str1, str2); } return 0;}
比较时,strcmp
会逐个比较两个字符串中的字符,直到找到不同的字符或者其中一个字符串结束。比较时,会按照每个字符的 ASCII 码值来进行比较。需要注意的是,strcmp
是区分大小写的,如果需要进行不区分大小写的字符串比较,可以使用 strcasecmp
或者一些其他库函数。
4.strstr
strstr:字符串查找函数,用于在一个字符串中查找指定子字符串的第一次出现位置。
char *strstr(const char *haystack, const char *needle); 源字符串 待查找字符串
strstr
函数会在 haystack
字符串中查找第一次出现 needle
字符串的位置,并返回指向该位置的指针。如果未找到 needle
字符串,则返回 NULL
。需要注意的是,strstr
函数是区分大小写的,即在匹配时会严格区分字符的大小写。
接下来,我们对比观察strstr函数:
#include <stdio.h>#include <string.h>int main() { const char *haystack = "Hello, this is a sample string"; const char *needle = "sample"; char *result = strstr(haystack, needle); if (result != NULL) { printf("'%s' found at position: %ld\n", needle, result - haystack); } else { printf("'%s' not found\n", needle); } return 0;}
5.strtok
strtok:字符串分割函数,可以在一个字符串中,按照指定的分隔符将字符串分割成多个字符串。
char *strtok(char *str, const char *delim); 字符串 分割符
接下来,我们对比观察strtok函数:
#include <stdio.h>#include <string.h>int main() { char str[] = "Hello,World,How,Are,You"; const char delim[2] = ","; char *token = strtok(str, delim); while (token != NULL) { printf("Token: %s\n", token); token = strtok(NULL, delim); } return 0;}
strtok
函数会在原始字符串上做改动,将分隔符替换为字符串结束符\0
。因此,在遍历分割后的字符串时,原始字符串可能已经被修改,需要谨慎处理。
6.strerror
strerror:分析错误原因函数,返回错误码的字符串的原因。
char *strerror(int errnum);
接下来,我们对比观察strtok函数:
#include <stdio.h>#include <string.h>#include <errno.h>int main() { for (int i = 0; i < 10; i++) { printf("Error code %d: %s\n", i, strerror(i)); } return 0;}
结果:
在这个示例中,我们通过循环打印了错误码 0 到 9 对应的错误描述字符串。strerror
函数会根据传入的错误码返回相应的错误描述。
需要注意的是,strerror
函数使用全局变量 errno
中存储的错误码来查找对应的错误描述,因此在调用 strerror
函数之前,需要发生过错误,以便 errno
中包含有效的错误码。