当前位置:网站首页>C语言提高篇(三)
C语言提高篇(三)
2022-08-02 13:28:00 【Tandy12356_】
实现字符串拷贝函数:myStrcpy
void myStrcpy(char* dst, const char* src) {
int len = strlen(src);
for (int i = 0; i < len; ++i) {
dst[i] = src[i];
}
dst[len] = '\0';
}
void test() {
const char* src = "hello world!";
char buffer[1024] = { 0 };
myStrcpy(buffer, src);
printf("%s\n", buffer);
}
1、初始化的时候最好将buffer置零,即:const char* src = "hello world!";
2、将字符串逐一拷贝之后记得在结尾添加一个'\0'
方法2:
//最终判断如果*dst的值是0的话,程序就退出了
void myStrcpy03(char* dst, const char* src) {
while (*dst++ = *src++);
}
while (*dst++ = *src++);
00C51D65 mov eax,dword ptr [dst]
00C51D68 mov ecx,dword ptr [src]
00C51D6B mov dl,byte ptr [ecx]
00C51D6D mov byte ptr [eax],dl
00C51D6F mov eax,dword ptr [dst]
00C51D72 mov cl,byte ptr [eax]
00C51D74 mov byte ptr [ebp-0C1h],cl
00C51D7A mov edx,dword ptr [dst]
00C51D7D add edx,1
00C51D80 mov dword ptr [dst],edx
00C51D83 mov eax,dword ptr [src]
00C51D86 add eax,1
00C51D89 mov dword ptr [src],eax
00C51D8C movsx ecx,byte ptr [ebp-0C1h]
00C51D93 test ecx,ecx
00C51D95 je std::_Narrow_char_traits<char,int>::eof+19h (0C51D99h)
00C51D97 jmp __$EncStackInitStart+19h (0C51D65h)
Test命令将两个操作数进行逻辑与运算,并根据运算结果设置相关的标志位。但是,Test命令的两个操作数不会被改变。运算结果在设置过相关标记位后会被丢弃。
TEST AX,BX
与AND AX,BX
命令有相同效果,只是Test指令不改变AX和BX的内容,而AND指令会把结果保存到AX中。
1、*dst=*src
2、dst++,src++
3、判断++之前的*dst是否为0,如果为0就跳出循环,如果不为零就跳转到1去执行
前置++和后置++的区别:
y=x++;
00DE1BF1 mov eax,dword ptr [x]
00DE1BF7 mov dword ptr [y],eax
00DE1BFD mov ecx,dword ptr [x]
00DE1C03 add ecx,1
00DE1C06 mov dword ptr [x],ecx
y = ++x;
00DE1C0C mov eax,dword ptr [x]
00DE1C12 add eax,1
00DE1C15 mov dword ptr [x],eax
00DE1C1B mov ecx,dword ptr [x]
00DE1C21 mov dword ptr [y],ecx
但是对于i++/++i这种自加的来说不影响结果
for循环的执行流程:
for (int i = 0; i < 5; ++i) {
00DE1BCD mov dword ptr [ebp-438h],0
00DE1BD7 jmp allocSpace+8h (0DE1BE8h)
00DE1BD9 mov eax,dword ptr [ebp-438h]
00DE1BDF add eax,1
00DE1BE2 mov dword ptr [ebp-438h],eax
00DE1BE8 cmp dword ptr [ebp-438h],5
00DE1BEF jge __vfprintf_l+9h (0DE1C29h)
字符串反转:
写入访问权限冲突:如果是一个较低的地址有可能是使用了空指针,如果是一个其他地址,有可能使用了野指针或者是没有访问权限(比如常量区)
注意:形如char*str=(char*)hello这种字符串常量存储在常量区,他和全局const一样,一经初始化便无法修改了。(通过指针也无法修改)
实现字符串反转——指针型
void myStrReverse(char* src) {
if(NULL==src){
return;
}
int len = strlen(src);
char tmp = 0;
char* pHead = src;
char* pTail = src + (len - 1);
while (pHead < pTail) {
tmp = *pHead;
*pHead= *pTail;
*pTail = tmp;
--pTail;
++pHead;
}
}
实现字符串反转——下标型
void myStrReverse2(char* src) {
if(NULL==src){
return;
}
int len = strlen(src);
char tmp = 0;
int start = 0;
int end = len - 1;
while (start < end) {
tmp = src[start];
src[start] = src[end];
src[end] = tmp;
++start;
--end;
}
}
函数使用形参指针时要先判断一下!!!
格式化字符串——sprintf
我们经常提到的缓冲区就是一块buffer,也就是一块内存
printf是将格式化好的字符串放到显示器里面了,而sprintf是把格式化好的字符串放到buffer里面了
sprintf的三大作用:
1、格式化字符串
2、拼接字符串
3、将数字转化成字符串
void test() {
//1.格式化字符串
char buffer[1024] = { 0 };
sprintf(buffer, "hello %s", "world");
printf("%s\n", buffer);
//2.拼接字符串
const char* str1 = "hello";
const char* str2 = "Obama";
memset(buffer, 0, 1024);
sprintf(buffer, "%s %s", str1, str2);
printf("%s\n", buffer);
//3.数字转化成字符串格式
int num = 666;
memset(buffer, 0, 1024);
sprintf(buffer, "老铁双击%d\n", num);
printf("%s\n", buffer);
}
void test() {
char** p = (char**)malloc(sizeof(char*) * 5);
if (NULL == p) {
return;
}
memset(p, 0, sizeof(char*) * 5);
for (int i = 0; i < 5; ++i) {
p[i] = (char*)malloc(64);
memset(p[i], 0, 64);
sprintf(p[i], "string%d", i + 1);
}
for (int i = 0; i < 5; ++i) {
printf("%s\n", p[i]);
}
for (int i = 0; i < 5; ++i) {
if (p[i] != NULL) {
free(p[i]);
p[i] = NULL;
}
}
if (p != NULL) {
free(p);
p = NULL;
}
}
释放堆内存之前先进行一下判断!!!
calloc和realloc:(仅供了解)
骚操作:按住alt键,拖动鼠标往下选,可以打印多行
查找字符字串:
const char* myStrStr(const char* str, const char* subStr) {
const char* myStr = str;
const char* mySub = subStr;
while (*myStr!='\0')
{
if (*myStr != *subStr) {
++myStr;
continue;
}
const char* tmp = myStr;
while (*mySub != '\0') {
if (*myStr != *mySub) {
mySub = subStr;
break;
}
++mySub;
++myStr;
}
if (*mySub == '\0') {
return tmp;
}
++myStr;
}
return NULL;
}
void test() {
const char* str = "abcdefg";
const char* subStr = "gh";
const char*sub=myStrStr(str, subStr);
printf("%s\n", sub);
}
指针易错点:
移动指向堆空间的指针的值,使得无法free掉这块内存
void test() {
char* p = (char*)malloc(100);
p++;
free(p);
p = NULL;
}
发现调用free函数崩掉的,这种情况是因为我们移动了指向malloc地址的指针!
当你操作某块内存的时候一定要确保他是合法的(自己申请的,同时没有被释放掉的)
所以说一定不要返回局部变量的地址!!!!!!
所以free掉之后一定要将指针置NULL
边栏推荐
猜你喜欢
随机推荐
面试SQL语句,学会这些就够了!!!
Detailed explanation of network flow (what information can the flow network diagram generally reflect)
短视频美食自媒体怎么做?5步教你快速上手
Scala基础语法入门(三)Scala中的各种运算符
永远退出机器学习界!
js数组递归使用
How to connect DBeaver TDengine?
嵌入式系统驱动初级【2】——字符设备驱动基础上_基础框架
图论之Prim,最小生成树该怎么解?
国产 GPU 创业潮 喧嚣下的资本游戏
ttl电平与rs232电平转换电路(232电平定义)
Fabric.js 动态设置字号大小
水平垂直居中方式
k8s之KubeSphere部署有状态数据库中间件服务 mysql、redis、mongo
[C language] Analysis of function recursion (1)
[C language] Analysis of function recursion (2)
SQL函数 TRUNCATE
Oracle update误操作单表回滚
this的绑定指向详细解答
3 ways for OpenFeign to set headers