形参与实参
形式参数:定义函数时函数名后括号中的变量名。实际参数:调用函数时函数名后括号中的表达式。
1.形参是变量,未被调用时,不占存储单元,调用过程中占用存储单元。
2.实参可以是常量、变量或者表达式,要与形参类型一致,而且实参要有确定的值,占用储存单元。
3.C++中实参对形参数据传递是单向的值传递,在存储单元中是不同的单元。
比如:
int sum(int a, int b)
{
return a+b;
}
int main()
{
int m=1,n=2;
int c = sum(m,n);
}
a,b是形参,m和n是实参,如果换成1和2就成了常量做实参,如果是m+n就成了表达式做实参。
指针的运算
指针也可以做算术运算
int a[3];
a[0]=0;a[1]=1;a[2]=2;
int *p,*q;
p=a;
q=&a[2];
cout<<q<<" "<<p<<endl;
cout<<"q+1:"<<q+1<<endl; //原来的地址值加上指向对象占用的字节数
cout<<q-p<<endl;
运行结果:
00CFFCD4 00CFFCCC
q+1:00CFFCD8
2
指针q+1不是只加个1,而是加1个指向对象所占字节数。比较诡异的是q-p,分开q和p可以看到二者之差是8,但相减得到的是相差多少个所指对象的字节数,这是由编译器实现的。
内联函数
之前对内联函数的理解不够深,内联函数是在编译阶段将函数展开,而不用将函数地址压入堆栈。如果在类体内定义实现,那么就是内联函数;也可以在类内用inline声明,在体外实现。函数一般比较小,用于大量调用的场合。
其实上面这些还没触及到本质,还有以下几条:
1. inline只是我们对编译器提出的一个申请,是否真按内联函数处理取决于编译器。函数不能有循环和递归,不能太大,否则仍是普通函数。
2. 编译时会展开内联函数,这样增大了可执行程序的体积。
3. 编译器的内联看起来就像是代码的复制与粘贴,这与预处理宏是很不同的:宏是强制的内联展开,可能将会污染所有的命名空间与代码,将为程序的调试带来困难,所以最好用内联函数代替宏。
4. 虚函数不允许内联。
5. 如果一个内联函数会在多个源文件中被用到,那么最好把它定义在头文件中,否则必须在调用该函数的每个文件中定义。
内联函数和宏的区别:
1. 内联函数展开在编译阶段,宏在预处理阶段
2. 内联函数运行时可调试,宏定义不可以
3. 内联函数经编译器安全检查。宏定义的参数没有类型的概念,只有在宏展开以后,才由编译器检查语法,这就存在很多的安全隐患。
详细内容看《Effective C++》条款30
c++生成可执行文件的过程
预处理——编译——汇编——链接
预处理:头文件展开,宏替换,去掉注释,条件编译的选择
编译:词法和语法分析,生成s文件
汇编:编程二进制文件obj
链接:把一个个目标文件链接生成exe文件,可发现函数是否有定义
char*
赋值问题
常用的赋值方法是char* str = “123”;
,但在Qt环境中会报错,无论是Mingw还是MSVC,只能换成以下的方法:
const char* p1="123";
char p1[4]="123";
char *p1 = new char[4]; strcpy(p1,"123"); // 不能直接赋值</