所有的预处理命令在程序中都是以 “ # ” 开头,每一条预处理命令单独占一行,不用分号结束。预处理命令可以出现在程序中任何位置。
宏定义命令
C语言中用#define命令将一个指定的标识符(宏名)来代表一个字符串
#define 标识符 命令串 比如:#define PI 3.14
C++中,增加了const语句来定义符号常量
const 数据类型 变量名 = 常量; const double PI = 3.14;
C++中,一般推荐用const语句来定义。
define除了可以定义常量之外,还可以用来定义语句,其格式如下:
#define ADD(a,b) ((a) + (b))
计算a+b
#include<cstdio> #define ADD(a,b) ((a) + (b)) int main() { int num1 = 3; int num2 = 4; printf("%d",ADD(num1,num2)); return 0; } 输出结果:7
参考于: const和符号常量define的区别
表达式语句
空语句
仅由一个分号(;)的语句,是一种不做任何操作的语句。
作用:程序中,语法上需要一个语句,但逻辑上并不需要,此时就可以用空语句。
例如,
for(i=1,s=0;i<=10;s+=i,i++); //求1+2+...+10
最后的分号代表一条空语句,表示循环体不需要执行任何操作。
① if( )else (条件语句)
② for( )~ (循环语句)
③ while( )~ (循环语句)
④ do~while( ) (循环语句)
⑤ continue (结束本次循环语句)
⑥ break(中止执行switch或循环语句)
⑦ switch (多分支选择语句)
⑧ goto (转向语句)
⑨ return (从函数返回语句)
C语言讲过,简单看看就行。
C++与C语言在数组上,无太大区别。因此就简单复习一下冒泡排序和选择排序算法。
冒泡排序 #include <iostream> using namespace std; int main() { const int N = 5; int a[N]={5,6,8,1,4}; int i,j,k,temp; for(i=0;i<N-1;i++) //N个数字比较N-1次 { for(j=0;j<N-i-1;j++) //相邻的数字相比较 { if(a[j]>a[j+1]) { temp=a[j]; a[j]=a[j+1]; a[j+1]=temp; } } } for(i=0;i<N;i++) { cout<<a[i]<<" "<<endl; } }
选择排序 #include <iostream> using namespace std; int main() { const int N=5; int a[N]={2,6,1,8,4}; int i,j,k,temp; for(i=0;i<N-1;i++) { k=i; for(j=i+1;j<N;j++) { if(a[k]>a[j]) { k=j; } } temp=a[k];a[k]=a[i];a[i]=temp; } for(i=0;i<N;i++) { cout<<a[i]<<" "<<endl; } return 0; }
函数定义的一般形式
[static] 返回值类型 函数名(形参表) [extern] { 函数体 }
关键字
关键字“static”表明该函数为静态函数,这类函数仅限文件内使用。
关键字“extern”表明该函数为外部函数,这类函数也可以提供给程序内其他文件的函数进行调用。
返回值类型
"返回类型“可以是char、int、double等,在这些情况下,函数体内必须有return语句;如果函数没有返回值,返回类型应为void,此时,函数体内可以无return语句,或者return语句后什么也不写。
函数名
定义函数名与定义变量名规则一样,尽量避免用下划线开头,因为编译器常常定义一些下划线开头的变量或函数名。尽量做到”望文生义“,
例如:StudentNum(学生学号)采用驼峰式命名
主函数的函数名必须是main()。
形参表
形参(函数形式参数)
对应着,还有无参函数,形参表没有参数。
函数体
花括号里的语句称为函数体。
//设计一个函数,可以计算任意数的阶乘 long fac(int n) //任意数n { long f=1; for(int i=1;i<=n;i++) f*=i; retutn f; }
函数定义和声明不是同一件事情
函数定义是指对函数功能的确立,包括指定函数名、函数类型、形参及其类型、函数体等,它是一个完整的、独立的函数单位。
函数声明的作用则是把函数的名字、函数类型以及形参的个数、类型和顺序(注意,不包括函数体)通知编译系统,以便在对包含函数调用的语句进行编译时,据此对其进行对照检查(例如函数名是否正确,实参与形参的类型和个数是否一致)。
常用的函数调用有两种方式:
对于有返回值的函数 变量名 = 函数名(实参表);
对于无返回值的函数 函数名(实参表);
//计算1到10阶乘倒数的和
#include <iostream> using namespace std; long fac(int n); int main() { double sum=0.0; for(int i=1;i<=10;i++) sum=sum + 1.0/fac(i); cout<<"sum="<<sum; return 0; } //阶乘函数 long fac(int n) { long f=1; for(int i=1;i<=n;i++) f*=i; return f; }
编写时可以发现,函数可以在后面,但是前面使用时需要先声明。比如long fac(int n)对应着主函数中的sum=sum+1.0/fac(i)。
也可以发现,函数其实挺好用的,写一个函数,调用10次。
函数形参:在函数未被调用的时候形参不占内存单元。
函数实参:实参必须要有类型,可以是常量,也可以是变量或表达式。
C++要求:函数调用时,函数的实参和形参个数相等,对应类型一致。
①函数调用前,形参不占用内存单元,函数调用启动时,才临时给形参分配内存单元。
②将实参的值一一对应地传递给形参后,执行被调函数的函数体。
③系统释放形参所占内存单元。
④返回主调函数的调用点。
C++中,函数调用方式有两种,一是传值调用,二是引用调用。
传值调用
(实参传数给形参,形参获得实参的数值),改变形参不改变原先的实参,因为两者在获得值之后没有任何关系。
引用调用
(实参传地址给形参,形参获得实参的地址),改变形参会反映在存储单元中,实参会被改变。
注意:
只有实参传值或者地址给形参!没有形参穿值或者地址给实参的说法!
形参没有确定的值,只能是变量。实参可以是常量、变量、表达式、函数。实参可以是表达式, 但不是“任意”,表达式计算结果的 类型 必须与 形参一致。当然数值不能超界溢出。
一般变量作为函数参数
例题:已知x=3,y=4,用公式d=根号(x^2 + y^2),求d的值。
#include <iostream> #include <Cmath> using namespace std; double f(double x,double y) { double z; x=x*x; y=y*y; z=sqrt(x+y); return z; } int main() { double f(double x,double y); double a,b,d; a=3.0; b=4.0; d=f(a,b); cout<<"a="<<a<<endl; cout<<"b="<<b<<endl; cout<<"d="<<d<<endl; } 运行结果: a=3 b=4 d=5
可以看出,传值调用的特点是形参值的改变不影响实参。
指针用作参数
指针用作函数有两个特点:
①对于复杂类型,节省时间和空间,提高运行效率。
②方便实现函数之间的效率。
示例:
#include <iostream> using namespace std; int fun(int,int*); int main() { int x=5,y=9; cout<<x<<'\t'<<y<<endl; fun(x,&y); //注意此处&y取址 cout<<x<<'\t'<<y<<endl; } int fun(int a,int *p) { a=a*a; *p/=*p; cout<<a<<'\t'<<*p<<endl; }
运行结果: 5 9 //输出x,y的值 25 1 //将x,y的值代入fun()函数中 5 1 //在主函数中输出x,y,可以发现y已经被改变。
在fun()函数中,形参p为指针,调用时,获得将实参y的地址值&y,使得形参指针指向实参变量y,这样,可以通过改变形参指针所指向的实参变量值间接改变实参值,从而实现函数之间的信息传递。
引用作为函数参数
引用定义的语法形式:
类型&引用名(变量名); 或 类型&引用名=变量名;
一般情况下,定义引用时必须初始化,同时引用的类型与变量的类型一致,例如:
int a=3; int &m=a; //或int &m(a) 此时,m是一个引用,m是变量a的别名。 m就像我们自己都有一个小名,代表的也是我们自己。 例如:m=m+1; //此命令实质上就是a+1
所有在引用上进行的操作,实质上就是在被引用者上的操作。
指向函数的指针和指针函数
main()函数带参数
默认函数值
C++中,允许在函数说明或定义时给一个或多个参数指定默认值。
设定规则如下:
①默认参数值的设置是在“函数说明”时进行的。
②默认参数值的设置遵循“靠后有值”原则。即当某个参数有默认值时,其后的参数必有默认值。
例如:
int fun(int a,int b=2,int c=5) int fun(int a,int b=2,int c) 第二行就是错的,没有遵循靠后有值的原则。
感觉没啥意思,代码写规范点可以避免的,就做做考题吧。
函数设置默认的参数值示例:
#include <iostream> using namespace std; int fun(int a=1,int b=3,int c=5) { cout<<a<<'\t'<<b<<'\t'<<c<<endl; } int main() { fun(); fun(4); fun(4,6); fun(4,6,8); } 输出结果: 1 3 5 4 3 5 4 6 5 4 6 8
编译器按照从左到右的顺序将实参和形参结合,当实参的数目不足时,编译器将按同样顺序使用定义中的默认值来补足所缺少的实参。
一句话总结就是:从左至右,有就改,没就默认值。
内联函数
函数重复调用有利于提升开发效率,但是一旦函数调用频率过高,或者对于一些函数体比较小、比较简单的,多次调用,明显开销变大,效率就会降低。
因此为了节省这些开销,就引入了内联函数,在编译时将函数体嵌入调用处。
语法格式
inline 返回值类型 函数名(形参表) { 函数体 }
使用时注意的问题
①内联函数体不宜过大(5行左右),且要结构简单。不允许出现循环语句和开关语句,也不能出现递归。
②内联函数的定义必须出现在第一次被调用之前。(这个和函数不太一样)
③对内联函数不能进行异常接口声明。
④内联函数适合被频繁调用的小函数。
示例:
求5个数的最大值。要求编写并调用一函数实现2个数的较大值。
#include <iostream> using namespace std; inline int max(int x,int y) { if(x>y) return x; else return y; } int main() { int a=34,b=56,c=22,d=100,e=88,m; m=max(a,b); m=max(m,c); m=max(m,d); m=max(m,e); cout<<"max="<<m<<endl; } 运行结果: max=100
函数重载
赋予同一函数名称多个含义
最常见但是又不容易发现的,可能思维定势吧
例如:<<和>>,C语言学的时候明明就是按位与和按位或的符号,一个移位符号;而在C++中,它们却代表着输出和输入的符号。这就是运算符的重载,这里暂时不多说,有兴趣自行百度学习。
定义重载函数时,要求同名函数的参数表必须有差异,而对返回值的类型没有要求。重载函数的参数表差异有:参数的个数不同,或者至少有一个参数的类型不同。调用函数时,系统会根据实参与形参的个数和类型进行匹配,自动确定调用哪个函数。
函数的重载也称为多态函数。函数的重载一般出现在功能相近的函数之间。
递归函数
递归函数又叫自调用函数,其特点就是在函数内部直接或间接地自己调用自己。
递归调用分为直接调用和间接调用两种方式。
直接递归调用是指在一个函数中实现调用自身的过程。
间接递归调用则是指在一个函数中调用其他函数,而在其他函数中又调用了本函数。
利用函数的递归调用,可以实现将复杂问题简单划,让计算机去执行简单问题的多次调用。
示例:用递归来算算这个
斐波那契数列:前两项数据均为1,以后的每项都是前两项之和。
#include <iostream> using namespace std; long F(unsigned n) { if(n==0||n==1) return 1; else return F(n-1)+F(n-2); } int main() { cout<<F(8)<<endl; } 运行结果: 34
ps:还有点东西没时间写,赶着6级。为复习而用,比较粗糙。如有错误,欢迎指正!