01.从C走进C++
函数指针
-
定义形式:
类型名 (*指针变量名)(参数类型1, 参数类型2, ...);
-
使用方法:
函数指针名(实参表);
1
2
3
4
5
6
7
8
9
10
11
12
13
void PrintMin(int a, int b) {
if (a < b)
printf("%d", a);
else
printf("%d", b);
}
int main() {
void (*pf)(int, int);
int x = 4, y = 5;
pf = PrintMin;
pf(x, y);
} -
qsort库函数
-
void qsort(void *base, int nelem, unsigned int width,int (*pfCompare)(const void *, const void *));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int MyCompare(const void *elem1, const void *elem2) {
unsigned int *p1, *p2;
p1 = (unsigned int *)elem1; // *elem1 非法
p2 = (unsigned int *)elem2; // *elem2 非法
return (*p1 % 10) - (%p2 % 10); // 负数升序, 正数降序
}
int main() {
unsigned int an[NUM] = {8, 123, 11, 10, 4};
qsort(an, NUM, sizeof(unsigned int), MyCompare);
for (int i = 0; i < NUM; i++)
printf("%d ", an[i]); // 10 11 123 4 8
return 0;
}
-
命令行参数
-
int main(int argc, char *argv[]) {}
-
argc
: 启动程序时, 命令行参数的个数 (至少为1, 第一个表示可执行程序本身的文件名) -
argv
: 存放命令行参数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main(int argc, char *argv[]) {
for (int i = 0; i < argc; i++)
printf("%s\n", argv[i]);
return0;
}
/*
将上面的程序编译成sample.exe, 然后在控制台窗口敲:
sample para1 para2 s.txt "hello world"
输出结果为:
sample
para1
para2
s.txt
hello world
*/
-
位运算
-
&
: 将某变量中的某些位清0且同时保留其他位不变 或 用来获取某变量中的某一位 -
|
: 将某变量中的某些位置1且保留其他位不变 -
^
: 将某变量中的某些位取反且保留其他位不变-
如果 a ^ b = c, 则 c ^ b = a 或 c ^ a = b (可用于加密)
-
不通过临时变量交换两个变量的值
1
2
3
4int a = 5, b = 7;
a = a ^ b;
b = b ^ a;
a = b ^ a;
-
-
~
-
<<
: 左移n位, 即乘2n (比乘法快很多) -
>>
: 右移n位, 即除以2n, 且将结果往小取整
引用
-
类型名 & 引用名 = 某变量名;
-
某个变量的引用, 等价于这个变量, 相当于该变量的一个别名
1
2
3
4
5
6void swap(int &a, int &b) {
int tmp;
tmp = a; a = b; b = tmp;
}
int n1, n2;
swap(n1, n2); // n1, n2的值被交换 -
函数返回类型为引用, 则可以让该函数为表达式的左值
-
常引用:
const T &
- 不能通过常引用去修改其引用的内容
T &
类型的引用或T
类型的变量可以用来初始化const T &
类型的引用const T
类型的常变量和const T &
类型的引用不能用来初始化T &
类型的引用, 除非进行强制类型转换
const关键字和常量
-
常量指针
-
不可通过常量指针修改其指向的内容
1
2
3
4
5int n, m;
const int *p = &n;
*p = 5; //编译出错
n = 4; //ok
p = &m; //ok, 常量指针的指向可以变化 -
不能把常量指针赋值给非常量指针, 反过来可以
1
2
3
4
5const int *p1;
int *p2;
p1 = p2; //ok
p2 = p1; //error
p2 = (int *) p1; //ok
-
-
函数参数为常量指针时, 可避免函数内部不小心改变参数指针所指地方的内容
-
不能通过常引用修改其引用的变量
1
2
3
4int n;
const int &r = n;
r = 5; //error
n = 4; //ok
动态内存分配
-
用
new
运算符实现动态内存分配-
分配一个变量
P = new T;
1
2
3int *pn;
pn = new int;
*pn = 5; -
分配一个数组
P = new T[N];
-
-
用
delete
运算符释放动态分配的内存- delete指针必须指向new出来的空间
- 一片空间不能被delete多次
- 释放数组空间:
delete []p;
内联函数和重载函数
-
内联函数
-
函数调用是有时间开销的, 如果函数本身只有几条语句, 执行非常快, 而且函数被反复执行很多次, 相比之下调用函数所产生的这个开销就会显得比较大
-
内联函数机制: 编译器处理对内联函数的调用语句时, 是将整个函数的代码插入到调用语句处, 而不会产生调用函数的语句
-
定义内联函数: 再函数定义前加
inline
-
弊端: 可执行文件体积增大
-
-
函数重载
- 函数名相同, 参数表不同
- 使函数命名简单
函数缺省参数
-
定义函数时, 可以让最右边的连续若干个参数有缺省值
1
2
3
4void func(int x1, int x2 = 2, int x3 = 3) {}
func(10); // == func(10, 2, 3)
func(10, 8); // == func(10, 8, 3)
func(10, ,8); // error, 只能最右边的连续若干个参数缺省 -
提高程序的可扩充性, 如果某个写好的函数要添加新的参数, 而原先那些调用该函数的语句, 未必需要使用新增的参数, 那么为了避免对原先那些函数调用语句的修改, 就可以使用缺省参数
面向对象程序设计
-
对象的内存分配
- 对象的大小 = 所有成员变量的大小之和
-
在类外定义成员函数
T 类名::函数名() {};