程序设计笔记(钱能)(一)

程序设计笔记(钱能)(一)

 

1 C++ 与 C 编译器的差别

在linux下,C语言程序(gcc)中某个文件定义了一个函数,包含这个函数声明的头文件不需要被使用的文件所包含,只需要链接在一块就可以了,而C++(g++)则必须包含这个头文件。

 

2 全局变量与局部变量

全局变量处于全局数据区(data area),由编译器产生并赋初值0。
局部变量处于栈区(stack area),如果不显式初始化则内容不可预料,修饰词auto可省略。
动态变量(new malloc)存放在堆区,
函数代码存放在代码区(code area)。(每个函数都有地址,指向函数地址的指针称为函数指针)

 

3 内联函数inline

内联函数必须先于调用声明或定义其为inline函数,如
inline int myFun();
main(){ ... myFun() ...}
int myFun(){……}  //此处无inline也是为inline
但下面就不可
int myFun();
main(){ ... myFun() ...}
inline int myFun(){……}  //不是inline函数了

内联函数不能有复杂的结构控制语句,如switch,while,否则视为普通函数链接调用
递归不能用来做内联函数

宏定义也可以达到内联函数的效果,但是它格式严格而且不能做类型检查及其他麻烦,比如:
#define MAX(a,b) ((a)>(b)?(a):(b))   //所有参数都要放在括号里
int a=1,b=0;
MAX(a,"Hello")   //错误的比较int和字符串,没有参数类型检查
MAX(a++,b)    //a被加了两次,变成了3
MAX(a++,b+10)    //a被加了一次

而内联函数能够避免以上问题
inline int max(int a,int b){
 return a>b?a:b;
}

 

4 函数的重载

函数掉用时首先选严格匹配的一个,如果没有就近类型转换
参数个数,参数类型,参数顺序不同方可,而光返回值不同是不能构成重载函数

 

5 默认参数用法如下

void delay(int loops = 1000);
delay(2500);
delay(1000);
void delay(int loops)
{
for(int i=0;i<loops;i++);
}
默认参数在函数声明中提供,如果又有声明又有定义,则不能在定义中出现默认参数;如果只有函数定义,则默认参数才可以出现在定义中;
默认参数必须从右至左逐渐定义,例如
int func(int a,int b=1, int c=2,int d=3) ...
func(5,5,5,5);
func(5,5)
func()   //error, need a
func(5,5,,5)  //error
注意:如果一组重载函数(可能带有默认参数)允许相同实参个数的调用,那么就会出现二义性,详见『1』P96;
默认值可以是常量,全局变量,甚至是一个函数

 

6 静态变量和静态函数

静态变量和静态函数只作用于本文件。
文件作用域下的inline函数默认为static存储类型。在文件作用域下声明的const的常量默认为static存储类型,他们如果加上extern,则为外部存储类型。


7 头文件

一般可包含
类型声明
函数声明
内联函数定义
常量定义
数据声明
枚举 enum BOOLEAN{false,true};
包含指令(可嵌套)如 #include <iostream.h>
宏定义 #define Case break;case
注释
而不宜包含
一般函数定义
数据定义 int a;int b[5];
常量聚集定义 const int c[]={1,2,3}

 

8 引用

1)将“引用”作为函数参数有哪些特点?

  (1)传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。
  (2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。
  (3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。

2)“常引用”

如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量名;
  例1
  int a ;
  const int &ra=a;
  ra=1; //错误
  a=1; //正确
  例2
  string foo( );
  void bar(string & s);
  那么下面的表达式将是非法的:
  bar(foo( ));
  bar("hello world");
  原因在于foo( )和"hello world"串都会产生一个临时对象,而在C++中,这些临时对象都是const类型的。因此上面的表达式就是试图将一个const类型的对象转换为非const类型,这是非法的。
  引用型参数应该在能被定义为const的情况下,尽量定义为const 。

 

9 数组

C中数组的初始化值可以省略,如
int iArray[5]={1,,3,4,5}
C++中不可以,如果初始值个数少于数组元素个数,那么前面是所赋初始值,后面是0(全局或静态变量)或不确定值(局部变量)

数组的参数传递一般需要两个,一个是数组地址,一个是数组大小

 

10 指针

const int * icp    //常量也有地址,这个表示指向常量的指针,这个地址的内容是不可以修改的;
有时候这个很有用,比如我们定义一个
int i=100;
此时不希望这个i被修改,则可以这样
const int * ip = &i;  或者 
定义:fname(const int * ip) 调用 fname(&i)
如此以后,如果试图修改i的值,编译器就会报错,即使我们的i不是const类型。我看好多库函数都是这样保护实参的

int * const pc = &b //pc是一个指针常量,这个常量是一个地址,这个地址不可修改,但是指向的内容可以修改,定义时需要初始化
 int i=1,j=2;
 const int * icp = &i;
 int * const pc = &i;

// *icp = j;   //error
 *pc = j;
 icp = &j;
// pc = &j; //error

const int * const cpc = &i; //指向常量的指针常量,指针值和指针指向的内容都不可以修改


void指针
不可以运算,指针加减运算离不开指针类型
void指针不可以赋给有类型指针,除非强制类型转换,而类型指针可以赋给void指针,vc下错误,bc下警告

int * iptr1, iptr2;  //这个是定义了一个指针一个整形
int * iptr1, * iptr2;  //要想定义两个指针,这个才对
指针具有类别之分,如果把一个float型的指针赋给一个int型的指针,输出以后就会得到一个奇怪的整数


char * pc 和char pc[]是有区别的,前者可以再赋值,后者就不可以了。
对于字符串常量赋给字符指针的情形 (char *pc="hello"),一般指针不再重新赋值,负责这个字符串已经入内存data区,但是不能再利用了。

数组名是指针常量,区别于指针变量,给数组名赋值是错误的。

函数指针
指向代码区中的某个函数,通过该指针可以调用该函数,定义: int (*func)(char a, char b),int 为返回值,func为函数指针名;
int* func(char a, char b) 则变成了指针函数,所以一定要有那个括号;
这个指针变量也有全局,局部,静态之分;
函数指针赋值还不能在全局区,只能在函数里面。事实上,其他变量也一样的。全局区只能是定义声明代码,不能是操作代码;
用typedef简化函数指针定义
typedef void (* FUNC)(int i);
FUNC  pfunc = myDefinedFunc;
函数指针可以构成指针数组;   FUNC funArr[] = {func1,func2,func3};   funArr[1](100);
函数的返回值可以是函数指针: FUNC foofunc();


11 输入输出

十六进制输出,var是变量
cout<<hex<<var<<endl;

 

12
sum += *iPtr;
iPtr++;   <==>      sum += *(iPtr++)   <==>    sum += *iPtr++
注意啊,一个指针++可不是加1

 

13 分配内存最好带上判断

if((buff = (int *)malloc(buffSize*sizeof(buffItem))) == NULL)
{
 cout<<"Can not allocate memory, terminating!/n"
 exit(1);
}
 if((buff = new char[102400]) == NULL)
 {
  cout<<"Memory Overflow!/n";
  exit(1);
 }

 

14 exit 与 return 的区别

1) return 的返回值要和所在函数的返回值一致,而exit不需要,例如exit(1)仍可返回给一个void f()函数;
2) return 是退出该函数,而exit推出该进程至操作系统

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值