C语言--代码优化(const+assert详解)

   1.优秀的代码具有的条件

  • 代码运行正常
  •  bug很少
  •  效率高
  •  可读性高
  •  可维护性高
  •  注释清晰
  •  文档齐全

 2.常见的编码技巧

  1.  使用assert
  2.  尽量使用const
  3.  养成良好的编码风格
  4.  添加必要的注释
  5.  避免编码的陷阱
  • 代码的优化 

示例:模拟实现strcpy函数

方法一:

void my_strcpy(char* dest, char* src)
{
	while (*src != '\0')
	{
		*dest = *src;
		dest++;
		src++;
	}//到这里src所指的字符串还剩下\0没有拷贝过去
	*dest = *src;//这样就可以拷贝过去了
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxx";
	char arr2[] = "hello bit";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

将上方代码进行优化:

void my_strcpy(char* dest, char* src)
{
	while (*dest++=*src++)//利用\0的ASCII码值是0
	{
		;
	}
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxx";
	char arr2[] = "hello bit";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

 思考:如果误将空指针传入函数,怎么办?

接下来我们引入assert相关知识来解决这个问题。

  • assert

void assert( int expression );

 

assert的原型定义在<assert.h>中,其作用是先计算表达式 expression ,如果expression的值为假(即为0),那么它先向stderr(标准错误输出)打印一条出错信息,然后通过调用abort(异常终止一个进程) 来终止程序运行。

下面进行代码优化:

include <assert.h>
void my_strcpy(char* dest, char* src)
{
    //断言
	assert(dest != NULL);
	assert(src != NULL);
	while (*dest++ = *src++)//利用\0的ASCII码值是0
	{
		;
	}
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxx";
	char arr2[] = "hello bit";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

 到这里,我们在和标准库函数对比一下:

6780a0890fae401482f7c038108df3b2.png

 这里发现库函数strcpy的返回类型是char*(函数返回的是目标空间的起始地址)

接下来我们继续优化代码:

#include <assert.h>
char* my_strcpy(char* dest, char* src)
{
	char* ret= dest;//保留好dest的起始地址
	assert(dest != NULL);
	assert(src != NULL);
	while (*dest++ = *src++)//利用\0的ASCII码值是0
	{
		;
	}
	return ret;
	
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxx";
	char arr2[] = "hello bit";
	printf("%s\n", my_strcpy(arr1, arr2));
	return 0;
}

 结果:hello bit

 

  • const修饰

   1.const修饰变量 

11f409e645e64c80a5aa58118a7c0f7e.png 

 const修饰变量时,只是在语法层面限制了变量修改,但是本质上,num还是变量,是一种不能被修改的变量(可称 常变量)

 

   2.const修饰指针 

先看一个例子:

int main()
{
	const int num = 10;
	printf("num=%d\n", num);
	int* p = &num;
	*p = 20;
	printf("num=%d\n", num);
	return 0;
}

13f6710d455c4060a5d2d2ecefed057a.png

 这里代码虽然能运行,点这是一种违规行为。

 下面我们通过const修饰指针的方式来改善代码:

const修饰指针变量需要关注的五个方面:

  1. 指针变量p本身能不能更改
  2. 指针变量指向的对象能不能改(*p)
  3. const放在*的左边
  4. contst放在*的右边
  5. const在*左右都存在
  • const放在*左边 

int main()
{
	const int num = 10;
	printf("num=%d\n", num);

	const int* p = &num;
	*p = 20;

	printf("num=%d\n", num);
	return 0;
}

8abfac80a7d343bdae8a54503ae5fb80.png

const放在*左侧,限制的是指针变量所指向的内容(即不能通过指针来修改指针所指向的内容);但是指针变量本身可以修改(即指针变量可以指向其他对象)

  • const放在*右边

int main()
{
	const int num = 10;
	printf("num=%d\n", num);

     int* const p = &num;
	*p = 20;

	int n = 100;
	p = &n;

	printf("num=%d\n", num);
	return 0;
}

 2159e2ea68864d8487c63a44eeb34663.png

const放在*右侧,限制的是指针变量本身(即指针变量不能再指向其他对象);但是可以通过指针变量来修改其指向的内容

  •  const存在于*左右两侧 

int main()
{
	const int num = 10;
	printf("num=%d\n", num);

    const int*const  p = &num;
	*p = 20;

	int n = 100;
	p = &n;

	printf("num=%d\n", num);
	return 0;
}

5228c50af7e34370b00ad0663059ec46.png

 const存在于左右两侧时,则指针变量本身及其所指向的内容(*p)都不能更改。

 3.检测小妙招

了解完上述知识后,我们来学习一个小技巧来检测上方模拟strcpy函数是否出错的情况,可以帮我们提高效率,节省时间。

下面看:

#include <assert.h>
char* my_strcpy(char* dest, char* src)
{
	char* ret= dest;//保留好dest的起始地址
	assert(dest != NULL);
	assert(src != NULL);
	while (*src++ = *dest++)  假设这里我们写反了,运行时并没有报错,但结果是错的
	{
		;
	}
	return ret;
	
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxx";
	char arr2[] = "hello bit";
	printf("%s\n", my_strcpy(arr1, arr2));
	return 0;
}

 如果按正常步骤走的话,我们就要进行调试一步一步查找错误,但我们可以添加const修饰,让我们直接定位到这个错误:

#include <assert.h>
char* my_strcpy(char* dest, const char* src)   //这里添加const修饰
{
	char* ret= dest;
	assert(dest != NULL);
	assert(src != NULL);
	while (*src++ = *dest++)0
	{
		;
	}
	return ret;
	
}
int main()
{
	char arr1[20] = "xxxxxxxxxxxxx";
	char arr2[] = "hello bit";
	printf("%s\n", my_strcpy(arr1, arr2));
	return 0;
}

3822806bba744c03a9d941d69ce7c604.png

 这样代码在运行时问题就直接暴露出来了,可以直接进行更正了。

 

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
1、选择合适的算法和数据结构 2、使用尽量小的数据类型 3、减少运算的强度 (1)查表 (2)求余运算 (3)平方运算 (4)用移位实现乘除法运算 (5)避免不必要的整数除法 (6)使用增量和减量操作符 (7)使用复合赋值表达式 (8)提取公共的子表达式 4、结构体成员的布局 (1)按数据类型的长度排序 (2)把结构体填充成最长类型长度的整倍数 (3)按数据类型的长度排序本地变量 (4)把频繁使用的指针型参数拷贝到本地变量 5、循环优化 (1)充分分解小的循环 (2)提取公共部分 (3)延时函数 (4)while循环和do…while循环 (5)循环展开 (6)循环嵌套 (7)Switch语句中根据发生频率来进行case排序 (8)将大的switch语句转为嵌套switch语句 (9)循环转置 (10)公用代码块 (11)提升循环的性能 (12)选择好的无限循环 6、提高CPU的并行性 (1)使用并行代码 (2)避免没有必要的读写依赖 7、循环不变计算 8、函数 (1)Inline函数 (2)不定义不使用的返回值 (3)减少函数调用参数 (4)所有函数都应该有原型定义 (5)尽可能使用常量(const) (6)把本地函数声明为静态的(static) 9、采用递归 10、变量 (1)register变量 (2)同时声明多个变量优于单独声明变量 (3)短变量名优于长变量名,应尽量使变量名短一点 (4)在循环开始前声明变量 11、使用嵌套的if结构
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胡闹的猫.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值