今天是学习C语言的第16天
时间:2024/9/29 21:25分
使用编译器:vs2019
此贴记录自己的成长
今天学习内容如下
1.strlen及模拟
//strlen 模拟实现
//size_t strlen(const char * str)
int my_strlen(char arr[])
{
int i = 0;
while (arr[i])
{
i++;
}
return i;
}
int my_strlen(char* p)
{
int i = 0;
while (*p)
{
p++;
i++;
}
return i;
}
int my_strlen(char* p)
{
char* q = p;
while (*p++);
p--;
return p - q;
}
int my_strlen(char *p)
{
if (*p)
{
p++;
return my_strlen(p) + 1;
}
else
{
return 0;
}
}
int main()
{
char arr[] = "abcd";
printf("%d", my_strlen(arr));
return 0;
}
2.strcpy及模拟
//strcpy
//char * strcpy(char *dest,const char *source)
1.必须\0
2.目标有足够空间放进去
3.目标空间是变量,不是常量
模拟实现
#include <assert.h>
char* my_strcpy(char* dest, const char* sour)
{
assert(*sour);
char* p = dest;
while (*sour)
{
*dest = *sour;
dest++;
sour++;
}
*dest = *sour;
return p;
}
int main()
{
char name[20] = { 0 };
//name = "zhangsan" 不可以,name是数组名是地址,地址是一个常量值,不能被赋值
//strcpy(name, "zhangsan");
//strcpy是找\0以前的复制进去, \0以后的不管
//strcpy(name, 'a', 'b', 'c');这种不行,必须放一个\0进去,找的就是\0
my_strcpy(name, "zhangsan");
printf("%s", name);
return 0;
}
3.strcat及模拟
//strcat 字符串追加
1.目标空间足够追加进去
2.目标空间可变,不是常量
3.有\0
4.不能自己追加自己,死循环,因为地址相同
模拟实现
#include<assert.h>
char* my_strcat(char* dest, const char* sour)
{
assert(sour != NULL);
char* p = dest;
while (*p++); p--;
while (*p++ = *sour++);
return dest;
}
int main()
{
char name[20] = { "zhangsan" };
my_strcat(name, "lisi");
printf("%s", name);
printf("\n%s", my_strcat(name,"haha"));
return 0;
}
4.strcmp及模拟
//strcmp 字符串比较
// 模拟实现
int my_strcmp(const char* str1, const char* str2)
{
while (*str1&& *str2)
{
if (*str1 == *str2)
{
str1++;
str2++;
}
else
{
return *str1 - *str2;
}
}
return *str1 - *str2;
}
int main()
{
char str1[20] = "abcdaa";
char str2[20] = "abcdaaa";
int cmp = my_strcmp(str1, str2);
printf("%d", cmp);
return 0;
}
5.长度限制函数
使用strcpy时, 如果dest空间不够, 还是能复制进去, 只是会有警告, 直接越界访问了
可以在第一行写上#define _CRT scanf那个东西, 就可以不越界访问, 直接编译拦截了
所以这些函数有些安全隐患, 会越界可能
所以c语言又提供了长度受限的字符串函数 strncpy strncmp strncat
这些函数相对安全
6.strncpy,strncat,strncmp
//strncpy
strcpy(dest, source); strncpy(dest source, 5) 多了一个参数, 只拷贝前5个进去, 最后如果没字符自动补\0, 有字符还是原字符, 第6个还是dest字符串的第6个字符 不是\0
strncpy("abcdef", "hellolll", 5); abcdef-- > hellof
如果sour只能3位, 而你参数写了5位, 那么后两位默认\0拷贝进去
//strncat
strncat(det, source, 5); 末尾自动补\0 如果dest里面有\0, source从\0开始追加, 后面直接覆盖了 参数多写也没用, 还是追加5个
//strncmp
strncmp(str1, str2, 5);
7.strstr查找函数
//strstr查找函数
//模拟实现
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
if (str2 == '\0')
{
return str2;
}
const char* str11 = NULL;
const char* str22 = NULL;
while (*str1)
{
str11 = str1;
str22 = str2;
while (*str11 == *str22&&*str11!='\0&&*str22!='\0)
{
str11++;
str22++;
}
if (*str22 == '\0')
{
return str1;
}
str1++;
}
return NULL;
}
int main()
{
char str1[] = "htttp//www.baidu.com";
char str2[] = "www";
if (my_strstr(str1, str2) == NULL)
{
printf("查找失败");
}
else
{
printf("%s", my_strstr(str1, str2));
}
return 0;
}
还有一种kmp算法,也是用来字符串查找的,效率比这个高,但是难度高
//自己写的模拟代码测试用的
#include <string.h>
int my_strstr(const char* str1, const char* str2)
{
int len = 0;
char* str22 = str2;
while (*str22) { str22++; len++; }
while (*str1)
{
char* str11 = str1;
str22 = str2;
int count = 0;
for (int i = 0; i < len; i++)
{
if (*str11 == *str22) { count++; }
str11++;
str22++;
}
if (count == len) return 1;
str1++;
}
return 0;
}
8.strtok 切割字符串函数
//strtok 切割字符串
http//www.baidu.com
char* strtok(char* str, const char* sep) 第二个参数是分割符, @. / 类似的符号
zhangsan@lisi 会将@变成\0 然后返回z的地址
由于会改变字符串内容, 所以建议提前拷贝一份
9.strerror 返回错误信息函数
//strerror
//返回错误码
//c语言的库函数,在执行失败时都会自动设置错误码
头文件#include <errno.h>
char* (int errnum) errnum: 0, 1, 2, 3, 4,5等等
printf("%s", strerror(0));
printf("%s", strerror(1));
等等
FILE* pf = fopen("test.txt", "r");
printf("%s"strerror(errno)); 错误码是全局变量,errno
10.字符分类函数及其大小写转换
//字符分类函数
iscntrl isspace isdigit islower isupper isalpha isalnum ispunct isgraph isprint
符合条件就为真
int tolower(int c) 字符转换大小写
11.memcpy跟memmove 内存拷贝函数
memcpy memmove
strcpy只能字符串, memcpy可以其他类型数组
void* memcpy(void* dest, const void* source, size_t num) num表示拷贝几个字节
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 0 };
memcpy(arr2, arr1, 20); 5个数 20个字节
memcpy不能用于处理重叠的数组或内存之间拷贝的, 例如不能memcpy(arr1, arr1, 20);
使用memmove可以
memmove
跟memcpy相同
12.memcmp 内存比较函数
//memcmp
内存比较
memcpy是一个字节一个字节比较, 不是一整个数比较
01 00 00 00 02 00 00 00
01 00 00 00 03 00 00 00 02 < 03
13.memset 内存设置函数
//memset 内存设置
char arr[] = "hello,bit";
memset(arr, 'x', 5);
然后arr里面全变x了 xxxxx, bit
memset(arr + 6, 'x', 3);
然后 hello, xxx
不适合给整型数组初始化,因为单位是1个字节,不是4个字节
int arr[10] = {0};
memset(arr,1,40) 40个字节 但是这样的话每个字节都变01了,不是数是1
14. 输入一个数字,数字的每一位如果偶数变0,奇数变1
int main()
{
int a = 222222;
int sum = 0;
while (a)
{
int i = a % 10;
if (i % 2 == 0)
{
i = 0;
}
else
{
i = 1;
}
a = a / 10;
sum = sum * 10 + i;
}
printf("%d", sum);
return 0;
}
15.4个凶手a说不是我, b说是cc, 说是d, d说c胡说,
3个真话,1个假话,求凶手
int main()
{
int killer = 'a';
for (; killer <= 'd'; killer++)
{
if ((killer != 'a') + (killer == 'c') + (killer == 'd') +( killer != 'd')==3)
{
printf("%c", killer);
}
}
}
16.字符串ABCD 左旋一个字符得到BCDA 左旋两个字符得到CDAB
void fun(char* arr,int num)
{
if (num > strlen(arr))
{
printf("错误");
}
else
{
int i = 0;
int tmp;
for (int i = 1; i <= num; i++)
{
int k = 0;
while (k < strlen(arr) - i)
{
tmp = arr[k];
arr[k] = arr[k + 1];
arr[k + 1] = tmp;
k++;
}
}
}
}
int main()
{
char arr[] = "ABCD";
int num = 2;
fun(arr, num);
printf("%s", arr);
return 0;
}
C语言学习日志
时间:2024/9/29 21:25分
目标:一个月学完c语言
每天更新,不断更
倒计时:14天