C语言提高篇(三)

实现字符串拷贝函数: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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值