小计良好的编程习惯(1)
本文记录了最近学习过程中,以及在编码过程中,感受到的比较好的编程习惯。如果有什么地方您觉得不妥,还请留言指出。
- 变量(普通变量和指针)的初始化。
解释:对于C/C++来说,声明的变量没有初始化,那么里面的值是有的(以前该内存的数值),所以对于自加自减的运算,在这里容易出错。而指针更是危险,声明的指针没有赋值的话,里面也是有值的,此时你不知道声明的指针指向哪里,等到你使用的时候,才会给指针赋值,那么在这期间,如果你使用了指针,修改了里面的东西,那就是无知的修改,是最可怕的。代码理解如下:
#include <QCoreApplication> #include <QDebug> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); int i; qDebug()<<++i;//4203055 int *p; qDebug()<<p;//0x22ff88 p = (int *)malloc(sizeof(int)*1); qDebug()<<p;//0x847b38 //下面是良好的习惯 int j=0; qDebug()<<++j;//1 int *pointer=NULL;
qDebug()<<pointer;//0x0 pointer = (int *)malloc(sizeof(int)*1); qDebug()<<pointer;//0x847b48 qDebug()<<"Hello word!"; return a.exec(); }
- 指针的释放与置空
程序中为指针动态分配的内存,在程序结尾的时候,不仅养成释放内存的习惯,还要养成为指针置空的习惯。也就说,结尾你把指针的内存释放了,但是该指针还是指向这里的,这样就存在了一个安全隐患,所以要置空。代码展示如下:
#include <stdlib.h> #include <iostream> using namespace std; int main() { int *pointer=NULL;//指针初始要为NULL pointer = (int *)malloc(sizeof(int)*1); cout << "Hello World! I am over!" << endl; //以下为良好的指针结束方式(来也空空去也空空) free(pointer); pointer = NULL; return 0; }
- malloc申请的动态内存,坑多多,不要用strlen测量
解释:这个错误曾经导致了整个QQ群的轰动,其实当你查看一下你动态开辟的内存的里面的内容的时候,你就会恍然大悟。先简单解释一下,主要是C语言的strlen函数没有搞清楚。我们所使用的所有内存,如果没有初始化,那么里面肯定会有内容的(计算机原理),包括了我们动态开辟的内存,而strlen函数的作用,测量字符串的长度(以'\0'结束).未知的世界中永远存在着未知的可能,未知的内存中,也许中间部分就包括了'\0'奥。那么使用strlen测量,就会有让人意外的结果了。代码展示如下:
#include <string.h> #include <stdlib.h> #include <iostream> using namespace std; int main() { char *pointer=NULL;//指针初始要为NULL pointer = (char *)malloc(sizeof(char)*15); cout<<"string:"<<strlen(pointer);//我的输出3 cout<<"value:"<<pointer; cout<<endl; char *pointer1="You Love Me.";//12 cout<<"string1:"<<strlen(pointer1); cout<<endl; return 0; }
while(NULL != p && item->data > p->data )
小心判断条件中的断路现象,这2个子条件是不能调换的。解释:在C/C++中判定语句有一种特性,叫做“断路”。比如:
if(条件1&&条件2)
这个判定,如果要想为真,则2个条件都必须为真。判定如果为假,在实际中,如果条件1为假的话,那么程序就不会去判定条件2的真假了。这就是断路现象。同理,if(条件1&&条件2)
只要条件1为真,就不会判定第二个条件了。那么我们的实例会产生怎样的错误呢?首先我们这句while(NULL != p && item->data > p->data )
是正确的,但是如果你把2个条件前后交换,那么就制造了一个bug.我的思路是,首先判断p的指向是否存在,存在的话,然后p->data
是否为真,如果前后2个条件调换的话,那么当p=NULL
的话,p->data
会在哪里呢?你去哪里读数据?程序就这样被你玩儿死了。- 判断条件句中的变量比较
#include <iostream> using namespace std; //下面每个变量都与零值比较,选择最优的方法 int main() { bool flag; if(flag == true){} if(flag == false){} //bool类型的变量应该选择下面的规范 if(flag){}//这种方法最优,因为true的值不确定 if(!flag){} int value; if(value == 0){}//这种方法好,下面的会让人误解是布尔类型 if(value != 0){} if(value){} if(!value){} float x; if(x == 0){} if(x != 0){} //下面的方法好,因为所有的float和double类型都有精度的,所以转化为下面的形式比较 if((x >= -EPSINON)&&(x <= EPSINON)){} if((X < -EPSINON) || (x > EPSINON)){} int *p; if(p == NULL){}//这种好 if(p != NULL){} if(p == 0){} if(p != 0){} //有的时候,还会这样写(想一想这种方法的好处) if(0 == value){} if(NULL == p){} cout << "Hello World!" << endl; return 0; }
- 判断条件中不要使用含有副作用的语句
解释:首先,何为副作用,就是会改变程序状态的语句。看代码实例:
if('Y'==getchar() || 'y' == getchar())//getchar()从缓冲区中,读一个少一个,那么读的过程中,程序的状态是不是改变了,那么这就容易发生错误。 {} //规范的如下: char ch=toupper(getchar());//自己体会一下 if('Y'==ch) {}
- 在定义函数或者变量名的时候,小心和关键字冲突或者标准函数冲突。
- 函数中的形参,在函数体中不改变的话,设置为const常量
- 对于函数中传递过来的参数,要进行安全检查
- 变量的定义应该“何时使用,何时定义,何地使用,何时定义”,变量定义的位置,应该和使用的地方紧凑一点。
结语:
良好的编程习惯只有在你写程序的时候才能完全的体会到。同时,如果您有更好的理解,可以在下面留言,一起学习进步。
版权声明:本博文属于作者原创或从其他地方学习而来的博文,未经许可不得转载.