《C++ Primer Plus(中文第6版)》第五至第七章,杂项记录

第五章

        字符串匹配,strcmp(str1,str2)可用于比较两个字符串,str1/2可以是指针类型或者char数组名

需要包含头文件cstring使用

        类型别名:1、C++可以使用 #define BYTE char 来将程序中的BYTE都替换为char(在编译期间替换)。2、C++和C中可以使用关键字typedef来创建别名。例如实现上述相同的别名可以:typedef char BYTE;如此创建别名。他们的区别在于:

#define CHAR_POINTER char *
CHAR_POINTER pa, pb;  
// 预处理器将其转化为
char *pa, pb;    // pa 为一个指针 pb 为一个char类型变量
// typedef不会导致上面的问题
typedef char* CHAR_POINTER;
CHAR_POINTER pa,pb;    // pa pb 都为指针

因此通常使用typedef,注意他们只是创建别名,而不是创建新的类型

使用++或--来进行自增和自减时,注意在单独实现a = a +/- 1功能时,前缀++的效率比后缀++的效率高,因为使用后缀会先创建一个副本,将副本加一后再返回,而前缀不会。同时还有一点需要指出的是,前缀++的优先级和使用指针时的*优先级相同,因此他们同一行时采用从右至左结合,但是后缀++的优先级比前缀和*的优先级高。--同理。

C++新加了一种基于范围的for循环

double prices[5] = {2.1, 4.5, 3.2, 5.6, 1.1};
for (double x : price)
    cout << x << endl;
// 以下的方法同上
for (double x : {2.1, 4.5, 3.2, 5.6, 1.1})
    cout << x << endl;

其中最初表示数组prices的第一个元素。x依次表示为数组中的每个元素。要修改数组中的元素需要时用以下方式:

for (double &x : prices)
    x = x * 1.1;

使用cin读取输入时,cin将忽略空格和换行符;所以为了读取空格可以使用cin.get(input);来将单个字符的输入读取到input(char类型)中,包括换行符也能被读取。

cin.get(ch) 与 cin.get()
属性cin.get(ch)ch = cin.get()
传递输入字符的方式赋给参数ch将函数返回值赋给ch
用于字符输入时函数的返回值istream对象 执行bool转化后为trueint类型的字符编码
到达EOF时函数的返回值istream对象 执行bool转化后为falseEOF(整型:-1)

使用字符参数版本更符合对象方式,因为其返回值是istream对象,这意味着可以这样子使用cin.get(ch1).get(ch2);

习题一:入口条件循环和出口条件循环的区别?

答案:其实他们分别是两种循环的代表,一种是入口条件循环的代表如while循环,出口条件循环的代表如do while循环。

习题八:int x = (1,20);与int x; x = 1,20;分别表示什么

答案:逗号运算符也是表达式的一种运算,表达式的值等于最后的值,因此对于第一种x=20;对于第二种,先是赋值运算符优先级高,因此x=1;然后多余一个20.

第六章

取反!的优先级高于所有关系运算符和算术运算符

C++逻辑OR和逻辑AND运算符||和&&的优先级低于关系运算符

逻辑AND运算符&&的优先级高于逻辑OR||的运算符

并不是所有键盘都提供逻辑运算符的符号,因此可以使用关键词 and、or和not代替,另外在C语言想使用关键词需要包含头文件 iso646.h

字符函数库cctype

函数名称返回值
isalnum()如果参数是字母or数字返回ture
isalpha()如果参数是字母返回true
iscntrl()参数是控制字符返回true
isdigit()参数是0-9的数字返回true
isgraph()参数是除了空格以外的打印字符串,返回true
islower()参数是小写字母,返回true
isprint()打印字符(包括空格),返回true
ispunct()标点符号,返回true
isspace()标志空白字符,如空格、换行符、回车、水平或垂直制表符,返回true
isupper()大写字母,返回true
isxdigit()十六进制数字,即0-9、a-f、A-F,返回true
tolower()参数是大写字符,返回其小写
toupper()参数是小写字符,返回其大写

switch不能处理取值范围、浮点测试和两个变量的比较。当选项不少于3个的时候,就代码长度和执行效率而言,应该使用switch。

文件处理:待补充

第七章-函数原型、值传参、const指针参数、函数指针

函数可以分为两类:没有返回值的函数和有返回值的函数。没有返回值的函数被称为void函数,通用格式为:

// 没有返回值的函数
void functionName(parameterList){
    statement(s)
    return;    // optional 可选的返回语句
}
// 有返回值的函数
typeName functionName(parameterList){
    statements
    return value;    // value is type cast to typeName
}

C++对于返回值的类型有一定的限制:不能是数组,但可以是其他类型------整数、浮点数、指针、甚至可以是结构体和对象。(有趣的是,虽然C++函数不能字节返回数组,但可以将数组作为结构体成员变量或对象组成部分来返回) 

函数原型:个人理解函数原型就是在首次使用函数前的函数声明 声明函数的返回值类型,函数名字,函数的参数。

// 函数声明 声明函数的返回值类型 声明函数的名字 声明函数的传入参数类型及个数 
// 传入参数的变量名称可以忽略
int sumArr(int arr[], int n);
int sumArr(int *, int);

如果在首次函数使用之前,声明并定义后,便可以不使用函数原型,原型的功能:原型可以帮助编译器完成许多工作,可以极大的降低程序出错的机率。具体来说,原型确保以下几点:

  • 编译器正确处理函数返回值;
  • 编译器检查使用的参数数目是否正确
  • 编译器检查使用的参数类型是否正确。如果不正确,则转化为正确的类型(如果可能的话)。

形参是函数定义中声明的参数,用来接收函数调用时传递的实参。 实参是函数调用时传递给函数的具体数据或变量。 形参和实参之间通过函数调用实现了值或引用的传递,实现了函数的参数化和复用。

值传递的为参数变量的副本,引用传递的为参数变量的地址,所以使用值传递不会修改原本参数变量的值,而引用传递直接在地址上修改了。为了简化,C++标志使用参数(argument)来表示实参,使用参量(parameter)来表示形参。

将数组作为参数传入函数:大多数情况下,C++和C语言一样,将数组名视为指针,将数组名解释为第一个数组的元素地址。以下的两个函数头都是正确的,以为在C++中,当且仅当用于函数头或函数原型中,int *arr和int arr[]的含义才是相同的。他们都意味着arr是一个指针。然而,数组表示法(int arr[])提醒用户,arr不仅指向int,还指向int数组的第一个int。其他的上下文中,这两种的含义并不同。例如不能使用int arr[]来声明指针。

记住,将指针(包括数组名)加1,实际上是加上了一个与指针指向的类型的长度(以字节为单位)相等的值。对于遍历数组而言,使用指针加法和数组下标时等效。

由于将数组作为参数传入函数时,传递的为指针,因此这种类型的传参是引用传递相同,于是修改数组的元素后将会修改原始数组的内容,因此需要使用const来保护原始数组。int sumArr(const int arr[], int n); 这意味着不能使用arr[i]来修改这些数据,注意,这并不意味着原始数组必须是常量,而只是意味着arr数组为只读数据。

int sumArr(int *arr, int n);
int sumArr(int arr[], int n);

int sumArr(const int arr[], int n);

7.1 指针和const

int fox = 15;
const int *pt = fox;    // pt 指向一个const int
int const *pt = fox;    // pt 为一个const指针 指向int

         一个指向const int 的指针,它的意思是*pt的值是只读的,不能被修改。pt的声明并不意味着它指向的值实际上就是一个const类型的变量,只是意味着对于指针而言,这个值是常量。所以可以使用fox变量来修改fox,但不能使用*pt修改fox的值。(注意可以修改pt指向其他元素)。但是当pt作为const指针后,那么它仅能指向fox这个元素,无法修改pt向其他元素,但是这种方式可以使用*pt来修改fox的值。注意以下情况:

将常规变量的地址赋给常规指针,这里将常规变量的地址赋给指向const的指针(指针不是const类型),是可行的;

将const变量的地址赋给指向const的指针(指针非const),是可行的;

将const变量的地址赋给常规指针,不可以!

将常规变量的地址赋给常规指针可以,将常规变量的地址赋给const类型的指针也可以。

提示:尽可能使用const,这样可以避免由于无意间修改数据而导致的编程错误;使用const使得函数能够处理const和非const实参,否则只能接受非const实参。如果条件允许,一个将指针形参声明为指向const的指针(意味着不能使用指针来修改变量,指针仍然可以修改指向其他变量)。

如何声明一个实参包含二维数组的函数原型

int sum(int arr[][4], int size);
int sum(int (*arr)[4], int size);

int arr[3][4] = {{1,2,3,4},{9,8,7,6},{2,4,5,6}};
int total = sum(arr, 3);

7.2 函数指针

        与数据相似,函数也有地址。函数的地址是存储其机器语言代码的内存的开始地址。

1.获取函数的地址,使用函数名即可传递函数的地址。例如process(think);传递的参数为think的地址,process(think());传递的为返回值。

2.声明函数指针,声明指向函数的指针必须指定指针指向的函数的所属类型。这意味着声明函数指针时,应该指定函数的返回类型以及参数列表(特征标)。也就是说,声明函数指针应该像声明函数原型那样指出有关函数的信息。

int sumArr(int);    // 函数声明
// 函数指针声明
int (*pf)(int);
// 将相应的函数的地址赋给指针
pf = sumArr;

提示:通常要声明指向特定类型的函数的指针,可以首先编写这种函数的原型,然后用(*pf)替换函数名。这样pf就是函数指针。 

注意:sumArr()的特征标和返回类型必须于pf相同。如果不相同,编译器将解决这种赋值。

3.使用指针来调用函数,使用函数指针和使用平常的函数一样,如下所示:

int x = sumArr(4);    // 调用函数
int y = (*pf)(5);     // 调用函数指针
// 实际上 C++还支持如下方式进行调用函数
int z = pf(5);

7.3 深入了解函数指针

const double * f1(const double ar[], int n);
const double * f2(const double [], int n);
const double * f3(const double *, int n);

        以上函数声明的特征标看似不同,实际上都相同,在函数原型中,参数列表const double ar[] 于 const double * ar的含义相同。其次,在函数原型中,可以省略标识符。因此,const double ar[]可以简化为const double [],而const double * ar 可以简化为 double *。因此上述所有函数特征标的含义都相同。另一方面,函数定义必须提供标识符,因此需要使用const double ar[] 或 const double * ar。

        接下来要声明一个指针,可以指向这三个函数之一。假定该指针名为pa,则只需要将目标函数原型中的函数名替换为(*pa):

const double * (*p1)(const double *, int);
// 在声明的同时进行初始化
const double * (*p1)(const double *, int) = f1;
// 使用C++11 的自动类型推断功能时,代码可以写为:
auto p2 = f2;

// 声明一个包含三个函数指针的数组
const double * (*pa[3])(const double *, int) = {f1, f2, f3};

  声明包含函数指针的数组,以上代码中由于[]的优先级高于*,所以pa首先是一个包含3个元素的数组,其次*表明该数组里面的三个元素都是指针,。然后前面的const double *表示数组里面的每个指针指向一个返回值为const double* 类型的函数,该函数的参数列表类型为后面括号。

这里是否能使用auto呢?不能,自动类型推断只能用于单值初始化,而不能用于初始化列表。但声明pa后,声明同样类型的数组就可以使用auto来自动类型推断了。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值