c语言01
来源:互联网 发布:ip变换软件 编辑:程序博客网 时间:2024/05/01 12:30
C语言01
编写c语言的目的:
根本————代码正确、可执行
提升————代码可读性高(易读、易懂、注释明确、符合规范)、高效
完美————健壮、可移植
第一步的根本自然不必多说;代码写完之后,在测试的时候难免要修改,而且大项目的开发一般需要多人协作,因此除了个人要保证自己代码可以被他人看懂之外,还要保证自己代码规范可以与他人完美组合,没有冲突,这就需要有统一的规范——一般把一些默认的规范作为标准。在这个基础上,代码可以协作执行了,考虑代码效率问题,完美时间复杂度与空间复杂度的优化;最后,考虑到操作系统平台的差异,需要提升代码移植性,代码健壮性。使代码可以跨平台移植,且代码可以保证长久的健壮,不会被丢弃,少补丁。
现在,来分析一下c中常见的编程错误和优秀编码规范吧
1、注意=与==的区别——前者为赋值,后者为判断
if(100==a[i])与if(a[i]==100)前者较好,可以避免把==写成=造成的错误
2、&&与||的操作
与操作——对于&&操作,例如if((a>1) && (b++)),如果a>1成立,则执行b++;但是如果a>1不成立,后面的不会再执行
或操作——对于||操作,例如if((a>1) || (b++)),如果a>1不成立,则执行b++;但是如果a>1成立,后面的不会再执行
如此使用,第一个条件的判定对于第二个条件是否执行影响巨大,可能会间接影响全局,因此使用时注意
例如:
a=1;b=3; if((a>1) && (b++)) c=5; 结果为 a=1 b=3
a=2;b=3; if((a>1) && (b++)) c=5; 结果为 a=2 b=4
3、这个不是陷阱,是一个在c陷阱与缺陷里面十分恐怖的表达式——(*(void(*)())0)();
看着脑袋就大了,这个表达式是执行0所在地址的程序,现在我们来分析一下(力争逐步分析):
第一步——什么是指向函数的指针,例如int (*pt)();这个函数就是指向函数的指针,pt指向这个函数的入口地址(函数是在内存之中的,pt指向函数的入口);那么如何调用函数呢,(*pt)();表示从pt指向的地址开始执行函数
第二步——代码从0开始执行,使用(*0)()不就ok了吗?不是如此,因为*后面必须跟着一个指针;而且这个指针必须是函数指针;
首先定义一个函数指针 void(*pt)();
然后强制转换赋值,把0强制转换为函数指针 pt =(void(*)()) 0;
最后执行操作 (*point_0_addr)();
将三个操作合并成一个,即为 (*(void(*)())0)();
4、switch操作——注意break在其中的作用。break与continue的区分
5、结构使用时,如果结构为指针,使用”->”;否则使用”.”
6、malloc分配内存,必须及时释放,否则会造成内存泄漏(最好加上限制,保证不越界)
7、数组与指针
数组:
>1、仅支持一维数组,但数组的元素可是任意类型的数据。(数据可以为数组,保证了多维数组的实现)
>2、数组的大小必须在编译初期作为常数指定。(需要分配空间进行初始化)
>3、数组的索引值从0开始。
>4、仅能确定数组大小,以及数组下标为0的元素指针。
指针的特点:
>1、指针本身的大小都是一样的,仅与机器位宽有关(32位系统就是32/8=4字节;64位系统就是64/8=8字节)
>2、任何指针都是指向某种类型的变量(指针是可变的,除非加上const的限制)
>3、一个指针只能指向一个地址,一个地址可以被任意多个指针指向
8、宏定义的使用,避免冲突
#ifndef NUM
#define NUM 100
#endif
9、——尽量不用全局变量,不得已使用的话,一定用g_开头标示出来;
——宏定义 务必全用大写,不要用’_’开头;——'_'开头的是c内部定义的,避免冲突
——枚举务必全用大写;
目的是为了尽快区分,避免代码混乱和造成冲突
10、一个变量只有一个功能,禁止重复使用;
例如:int ret;...;ret = result1();…; ret = result2();…;return0;
int ret1,ret2;...;ret1 = result1();…;ret2 = result2();…;return 0;
即使对操作无任何影响,但是在比较复杂的代码中前者会造成代码可读性下降
在不同的类型变量操作中,特别注意默认类型转换和强制类型转换造成的数据精度丢失
建议所有的常量使用const全局变量,而不是用宏定义——(这个建议是为了反编译,假如代码出错了,而且从机器指令中发现错误的地址,此时需要反编译得到汇编语言,来查询地址操作,定义为const反编译的代码容易理解)
11、函数的参数尽量不要超过四个
因为一个进程的函数执行最多分配4个寄存器来存储参数,多的存到栈中,栈中数据的获取比寄存器慢的多~~~如此要求只是为了提高代码的执行质量
——函数的参数尽量采用整型长度
因为对于32位系统,int为4字节(4*8=32位);对于64位系统,int为8字节(8*8=64位)。指针与int总是保持一致。传递int与指针可以保证寄存器可以完全的存储(不需要做其他的操作),加快处理速度。因此,最好使用int或指针传递。
12、int a=0x12345678;char *p;p=&a; 得到*p = 120
这里定义了一个整型数据a,然后把它的地址给了p,
解析:a是一个整型,有四个字节,低位在前,高位在后存储方式,按顺序——78(字节1)、56(字节2)、34(字节3)、12(字节4)
现在q就是78(字节1))的地址,输出为7*16+8=120。不同的系统可能不同,也可能位高位在前,低位在后存储方式,此时输出的结果为1*16+2=18
13、结构struct的大小
struct point{
char b;
char c;
double d;
int a;};
使用sizeo(point)结果为24; 如果把struct中的int a与double d换个位置,使用sizeo(point)结果为16。
原因:
struct内部以字节最大的数据为基准,进行匹配,就如上面的double最大,为8字节,所以struct就以8字节为最小单位,因为之前定义的不足8字节(两个char为2字节),所以看作8字节,在double之后的int也被看作8字节,结果为24。
调换位置之后,double变为最后一个,之前的三个加起来不足8字节,因此结果为16
14、关于getchar()一类函数的问题
Int a;
a=getchar();
需要注意的是getchar();返回值为int(因为可能为EOF),所以使用int而不是char来接收结果(EOF为-1,char表示不了)
15、在函数中返回指针
理解之后——举例一个函数操作
char* fun1(){
char a[10] =“kkkkkkkk”;
char *p = a;
return p;}
如果执行这个函数 fun1,在栈区分配空间,p为指向栈区的指针。因为函数执行完之后,栈区会被自动回收,因此返回p无法找到“kkkkkkkk”这个字串。
16、<<与>>的注意
按位操作运算符:
<<左移
>>右移
左移就是带着符号位左移,没有区别(高位移出,低位补0)
右移是与unsigned有关的:
1、假如为unsigned的无符号定义,则直接右移,高位补0
2、如果不是unsigned,最高位符号位不动,次高位根据符号位补充。即符号位为1,则补1;符号位为0,则补0
- 【C语言】01-C语言概述
- 【C语言】01-C语言概述
- 【C语言】01-C语言概述
- 【C语言】01-C语言概述
- 【C语言】01-C语言概述
- 01-C语言概述
- C语言01
- 01-C语言概述
- C语言 01
- C语言01 -- 基本概念
- c语言01
- C语言基础01
- 01、C语言-数据类型
- C语言复习-01
- C语言01
- c语言基础01
- C语言-01C语言程序基本知识点
- 通俗易懂学C语言-01-什么是C语言以及用处
- wifi万能钥匙原理猜想
- 【Qt OpenGL教程】12:显示列表
- IOS7 edgesForExtendedLayout
- Fragment的生命周期
- mybatis 增删改查操作
- c语言01
- Android 继承SQLiteOpenHelper自定义DBHelper存取数据与图像
- JavaWeb用户登陆--项目环境的搭建
- GUI编程,单选按钮、复选框、消息框、消息响应函数的使用
- leetcode——Count Complete Tree Nodes
- Xcode的快捷键及代码格式化
- 快速排序分析
- HDU5339——Untitled
- 关于iOS推送中点击通知的几点(备忘)