文章目录
字符串操作函数
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;
}
strerror 与 perror
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