C语言使用注意

C语言学习笔记(规范)

C基本知识

.c/.cpp文件:C/C++程序的定义文件,用于保存程序的实现。
.h: C/C++的头文件,用于保存程序的声明。

头文件

  • 头文件开头的版权和版本声明。
  • 预处理块。
  • 函数和类结构声明等。
// 版权和版本声明
#ifndef GRAPHICS_H // 防止graphics.h 被重复引用
#define GRAPHICS_H
#include <stdio.h> // 引用标准库的头文件#include “opencv2/opencv.hpp” // 引用非标准库的头文件,从用户工作目录开始搜索void Function1(); // 全局函数声明
⋯
class Box // 类结构声明
{};
#endif

定义文件

  • 版权及版本声明
  • 对头文件的引用
  • 程序的实现
// 版权和版本声明
#include “graphics.h” // 引用头文件// 全局函数的实现体
void Function1()
{}
// 类成员函数的实现体
void Box::Draw()
{}

代码规范

  1. 一行代码只做一件事情,如只定义一个变量;
  2. if、for等语句自占一行,执行语句不得紧随其后;
  3. 尽可能在定义变量的同时初始化该变量;
  4. 长表达式要在低优先级操作符处拆成新行,操作符放在新行之首;
  5. 块注释采用“//”,行注释 “//…”;
  6. 汇编使用“ ; ”注释。
//长行拆分
if ((very_longer_variable1 >= very_longer_variable12)
&& (very_longer_variable3 <= very_longer_variable14)
&& (very_longer_variable5 <= very_longer_variable16))
{
dosomething();
}
virtual CMatrix CMultiplyMatrix (CMatrix leftMatrix,
CMatrix rightMatrix);
for (very_longer_initialization;
very_longer_condition;
very_longer_update)
{
dosomething();
}
//注释
/*
* 函数介绍:
* 输入参数:
* 输出参数:
* 返回值:
*/
void Function(float x, float y, float z)
{}
if ()
{while ()
   {} // end of while} // end of if

表达式

优先级运算符结合律
从高到低( )  [ ]  ->  .从左到右
!  ~  ++  – (类型) sizeof +  -  *  &从右到左
*  /  %从左到右
+ -从左到右
<<  >>从左到右
<  <=  >  >=从左到右
==  !=从左到右
&从左到右
^从左到右
I从左到右
&&从左到右
II从左到右
?:从右到左
I=  +=  -=  *=  /=  %=  &=  ^==  <<=  >>=

零值比较

  1. 不可将布尔变量直接与TRUE,FALSE或1,0进行比较;
  2. 整形变量用“==”或“!=”直接与0比较;
  3. 不可将浮点变量用“==”或“!=”与任何数字比较,应设法转化为“>=”或“<=”形式;
  4. 指针变量用“==”或“!=”与NULL比较。
if(flag)
if(!flag)  //布尔变量
if(value==0) //整形变量
if((x>=-EPSINON)&&(x<EPSINON)) //浮点型变量,EPSINON为允许的误差
if(p==NULL//指针变量

循环

  1. 多重循环中,应将最长的循环放在最内层,最短的放在最外层,以减少CPU跨切循环的次数;
  2. 如循环体内存在逻辑判断,且循环次数很大,宜将逻辑判断放到循环体外部;
  3. 推荐循环控制采用半开半闭区间写法:0<=x<N(半开半闭),0<x<=N-1(闭区间);switch

switch

  1. case结尾不要忘了加break;
  2. 不要忘记最后default分支。

常量
不使用常量,程序会遇到麻烦:

  1. 程序的可读性差
  2. 程序很多地方输入同样的数字或字符串,难以保证不出错;
  3. 修改数字或字符串,修改地方过多。
#define MAX 100
const int MAX =100;
const float PI =3.14159

const 和define 的比较:

  • const常量有数据类型,而宏常量没有数据类型。可能有边际效应。
  • 有些继承化调试工具可以对const常量进行调试,但不能对宏常量进行调试。

需要对外公开的常量放在头文件中,不需要对外公开的常量放在定义文件的头部。
如果某一常量与其他常量密切相关,应在定义中包含这种关系。

const float RADIUS = 100;
const float DIAMETER = RADIUS*2;
//类中的常量
class A
{const int SIZE = 100; // 错误,企图在类声明中初始化const 数据成员
int array[SIZE]; // 错误,未知的SIZE
};

class A
{A(int size); // 构造函数
const int SIZE ;
};
A::A(int size) : SIZE(size) // 构造函数的初始化表
{}
A a(100); // 对象 a 的SIZE 值为100
A b(200); // 对象 b 的SIZE 值为200

class A
{enum { SIZE1 = 100, SIZE2 = 200}; // 枚举常量
int array1[SIZE1];//枚举常量缺点是隐含的数据类型是整数,最大值有限
int array2[SIZE2];

函数设计
参数的书写要完整,若函数没有参数,则用void填充

void SetValue(int width, int height); // 良好的风格
void SetValue(int, int); // 不良的风格
float GetValue(void); // 良好的风格
float GetValue(); // 不良的风格

参数命名要恰当,顺序要合理

void StringCopy(char *strSource, char *strDestination); // 良好的风格
void StringCopy(char *str1, char *str2);; // 不良的风格
StringCopy(str, “Hello World”); // 参数顺序颠倒

参数如果是指针,且仅作输入用,则应在类型前加const,以防该指针在函数体内被意外修改。

void StringCopy(char *strDestination,const char *strSource);

如果输入参数以值传递的方式传递对象,则宜用“const &”方式,提高效率。
避免使用过多的参数。

返回值规则:
不要省略返回值的类型。
函数名字与返回值类型在语义上不可冲突。

值传递、指针传递、引用传递

//值传递
void swap(int a,int b)
{
     int temp;
     temp=a;
     a=b;
     b=temp;
     cout<<a<<" "<<b<<endl;
}

int main(){
     int x=1;
    int y=2;
    swap(x,y);
    cout<<x<<" "<<y<<endl;
    
    return 0;
}
//指针传递
void swap(int *a,int *b)
{
     int temp;
     temp=*a;
     *a=*b;
     *b=temp;
     cout<<*a<<" "<<*b<<endl;
}

int main(){

   int x=1;
    int y=2;
    swap(&x,&y);
    cout<<x<<" "<<y<<endl;
}
//引用传递
void swap(int &a,int &b)
{
     int temp;
     temp=a;
     a=b;
     b=temp;
     cout<<a<<" "<<b<<endl;
}

int main(){
    
    int x=1;
    int y=2;
    swap(x,y);
    cout<<x<<" "<<y<<endl;
    return 0;
}
int x=1;

int *y=&x; //用于指针传递,y有自己独立的内存地址,存储的内容是x的地址,*y是x的值

int &z=x; //用于引用传递,可以理解为z就是x,x就是z,只不过名字不一样

内存管理
内存分配方式:

  • 从静态存储区分配。如 全局变量,static变量。
  • 在栈上创建。函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。
  • 从堆上分配,即动态内存分配。程序运行时用malloc或new申请任意内存,使用free或delete释放内存。

常见内存错误

  • 内存分配未成功
    在内存使用前检查指针是否位NULL。如指针p是函数的参数,在函数入口处用assert(p!=NULL)进行检查;如果用malloc或new申请内存,用if(p==NULL)或if(p!=NULL)进行防错处理。

  • 内存分配成功,但未初始化就引用

  • 内存分配成功且已经初始化,但操作越过了内存的边界

  • 没有释放内存,导致内存泄漏

  • 释放了内存却继续使用它

指针与数组

//数组
char a[]="hello";
char b[10];
strcpy(b,a);  //复制不能用 b=a;
if(strcmp(b,a)==0) //不能用if(b==a)
...

//指针
int len =strlen(a);
char *p=(char*)malloc(sizeof(char)*(len+1));
strcpy(p,a);
if(strcmp(p,a)==0)
...
//数组与指针内存容量
char a[] = "hello world";
char *p = a;
cout<< sizeof(a) << endl; // 12 字节
cout<< sizeof(p) << endl; // 4 字节

//数组退化为指针
void Func(char a[100])
{
cout<< sizeof(a) << endl; // 4 字节而不是100 字节
}

const

  • const只能修饰输入参数,如果输入参数采用“指针传递”,加const可以防止意外的改动指针,其保护作用;
  • 对于非内部数据的输入参数,应将“值传递”改为“const 引用传递”,提高效率。如void Func(A a)改为void Func(const A &a)。
  • const修饰的指针函数,返回值不能被修改,只能被赋给加const修饰的同类型指针。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值