cpp -- W1 从C走进C++

1. 从C走进C++


1.1 函数指针
1). 定义:
程序运行期间,每个函数会占用一段连续的内存空间。而函数名就是该函数所占内存区域的起始地址(入口地址)。可以将函数的入口地址赋给一个指针变量,使该指针变量指向该函数。然后通过指针变量就可以调用这个函数。这种指向函数的指针变量称作“函数指针”。
2). 定义形式:
类型名 (* 指针变量名)(参数表);
例如: int (*pf)(int , char);
3). 使用方法;
#include <stdio.h>
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);
return 0;
}
4). 函数指针和qsort函数
C语言快速排序库函数可以对任意类型的数组进行排序,其声明如下:
void qsort(void *base, int nelem, unsigned int width,
int (* pfCompare)(const void *, const void *));
其各参数的意义依次为:
a. 数组起始地址;
b. 数组元素个数;
c. 每个元素的大小(以字节为单位,由此算出每个元素的地址);
d. 指向函数的指针(比较函数的地址),用于确定排序的顺序(元素谁前谁后的规则),
如果前者排在后者前面,则函数返回负整数;
如果前者排在后者后面,则函数返回正整数;
否则返回0。
实例:调用qsort库函数,将一个unsigned int数组按个位数从小到大进行排序:
#include <stdio.h>
#include <stdlib.h>
int MyCompare(cosnt void * elem1, const void * elem2)
{
unsigned int * p1, * p2;
p1 = (unsigned int *) elem1; // 强制类型转换
p2 = (unsigned int *) elem2;
return (*p1 % 10) - (*p2 % 10);
}

#define NUM (5)
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]);
}
return 0;
}

1.2 命令行参数
1). 定义
将用户在cmd窗口输入可执行文件名的方式启动程序时,跟在可执行文件名后面的那些字符串,称为“命令行参数”,命令行参数可有多个,以空格分隔。
2). 使自己的程序获得命令行参数
int main(int argc, char * argv[])
{
// ......
}
a. argc: 程序启动时,命令行参数的个数,C/C++规定,可执行程序本身的文件名,也是一个命令行参数,因此artc至少是1;
b. argv: 指针数组,其中每个元素都是一个char* 类型的指针,该指针指向一个字符串,这个字符串就是一个命令行参数。
3). 例子
#include <stdio.h>
int main(int argc, char * argv[])
{
for(int i=0; i < argc; i++)
{
printf("%s\n", argv[i]):
}
return 0;
}
4). note
命令行参数以空格进行分隔,所以当某个命令行参数内部有空格时,该命令行参数需要用双引号进行标注。


1.3 位运算(从右向左依次为第0, 1, ...位)
用于对整数类型(int, char, long等)变量中的某一位(bit),或者若干位进行操作。
C/C++语言提供了六种位运算操作符。
1). & 按位与 双目 11为1,否则0 与1与可以维持原值
a.  用于将某变量中的某些位情0,且保持其他位不变。 例如:若需要将int变量n的低8位清零,则进行:
n = n & 0xffffff00; // 或: n &= 0xffffff00;
当n时short类型时,变为:
n &= 0xff00;
b. 也可用于获取某变量的某一位。
例如,判断int变量n的第7位(从右向左)是否为1:
if (0x80 == (n & 0x80)) // 0x80: 1000 0000
2). | 按位或 双目 00为0,否则1 与0或可以维持原值
a. 将某变量中的某些位置1同时保持其他位不变。
例如,将int变量n低8位全置为1,可以执行:
n |= 0xff; // 0xff: 1111 1111
3). ^ 按位异或 双目 同0,否则1 与0异或可以维持原值
a. 进行简单的加密与解密:
若a^b=c, 则c^b=a, c^a=b; // 穷举法可证, a为原文,b为秘钥
b. 不通过临时变量交换两变量的值:
int a = 5, b = 7;
a = a^b;
b = b^a;
a = a^b;
4). ~ 按位非 单目
5). << 左移 双目
a << b的值为将a各二进位全部左移b位后的值,同时a保持不变。规则:高位丢弃,低位补0
a. 实际上,左移n位,等于乘以2^n,且左移比乘法快很多。
6). >> 右移 双目
右移时,低位丢弃,对于有符号数,如long, int, char,右移时符号位将一起移动,且大多数编译器规定,如果符号位为1,则右移时最高位补1,否则补0。
a. 右移n位,相当于除以2^n,并且结果往小里取整。如-25 >> 4 = -2
7). 例子
#include <stdio.h>
int main()
{
int n1 = 15;
short n2 = -15;
unsigned short n3 = 0xffe0;
char c = 15;
n1 = n1 >> 2;
n2 >>= 3;
n3 >>= 4;
c >>= 3;
printf("n1=%d,n2=%x,n3=%x,c=%x", n1, n2, n3, c);
}
// n1=3,n2=fffffffe,n3=ffe,c=1
n1: 0000 0000 0000 0000 0000 0000 0000 1111
n1 >>= 2: 变成3
0000 0000 0000 0000 0000 0000 0000 0011
n2: 1111 1111 1111 0001(补码为反码加1)
n2 >>= 3: 变成 fffffffe, 即-2
1111 1111 1111 1110
n3:1111 1111 1110 0000
n3 >>= 4: 变成ffe
0000 1111 1111 1110
c: 0000 1111
c >> 3: 变成1
0000 0001
8). 思考
有两个int变量a与n(1<=n<=31),要求写一个表达式,使表达式的值和a的第n位相同
答案: (a << n) & 1
当没给出n的限制时,答案为:(a & (1 << n)) >> n

1.4 引用
1). note
a. 定义引用时一定要将其初始化成引用某一变量;
b. 初始化后,他就一直引用该变量,不会再引用其他变量;
c. 只能引用变量,不能引用变量和表达式。
d. 当函数形参为引用类型时,由于引用是其引用变量的别名,因此无须额外进行内存的分配。
2). 引用作为函数的返回值
int n = 4;
int & SetValue() { return n; } // 函数返回了n的引用
int main()
{
SetValue() = 40; // 返回值为引用,即这是对n进行赋值,因此n变为40了
cout << n;
return 0;
} // 输出: 40
3). 常引用
不能通过常引用去修改其引用的内容。如:
int n = 100;
const int & r = n;
r = 200; // 编译错
n = 300; // no error
4). 常引用和非常引用的转换
T& 类型的引用或T类型的变量可以用来初始化const T&类型的引用:
T a;
T& b = a;
cosnt T& c = a; // 或 cosnt T& c = b;
const T类型的长变量和const T&类型的常引用不能用来初始化T&类型的引用,除非进行强制类型转换:
T a = 10;
const T b =10;
const T& c = a;
T& d = b; // error
T& e = c; // error

1.5 const关键字和常量
1). 定义常量
相比#define,有类型检查。 // 例如 const string SCHOOL_NAME = "Peking University";
2). 定义常量指针
a. 不可通过常量指针修改其指向的内容:
int n, m;
const int *p = &n;
*p = 5; // error
n = 4; // ok
p = &m; // ok
b. 不可把常量指针赋给非常量指针,反过来可以
const int *p1;
int *p2;
p1 = p2; // ok
p2 = p1; // error
p2 = (int *)p1; // ok, 强制类型转换
c. 函数参数为常量指针时,可避免函数内部不小心修改参数指针所指地方的内容:
void MyPrintf(const char *p)
{
strcpy(p, "this"); // error, strcpy第一个参数为char*,考虑到不能把常量指针赋给非常量指针,编译就不会通过了
printf("%s", p); // ok
}
3). 定义常引用
不能通过常引用修改其引用的变量:
int n;
const int& r = n;
r = 5; // error
n = 4; // ok

1.6 动态内存分配
例: T& p = new T; delete p;
T* p = new T[N]; delete []p;
// 动态分配一片大小为N*sizeof(T)字节的内存空间,并将该内存空间的首地址复制给p。
new T; new T[n]的返回类型都是T*。

1.7 内联函数和重载函数
1). 内联函数(在函数定义前面加inline)
编译器处理对内联函数的调用语句时,是将整个函数的代码插入到调用语句处,而不会产生调用函数的语句。
2). 函数重载
两个函数:
int Max(double f1, double f2); int Max(int n1, int n2);
调用Max(3, 2.4)时会产生二义性,需要注意。

1.8 函数缺省参数(提高程序的可扩充性)
如果某个写好的函数要添加新的参数,而原来调用该函数的语句未必需要使用这些参数,为了避免影响原来的调用语句,可使用缺省参数。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值