C++ 第二周

第四章 循环和关系表达式

for 语句,while 语句 与 C语言相同,略

递增(++)/(- -)递减运算符

       这两个运算符都有两个变体,如:x++;++x .   两个版本对操作数的影响是一样的,但影响的时间不同。就像先付款后到货 ;先到货后付款一样。

       下面看一个简单的程序:

#include<iostream>
int main()
{
	using std :: cout;
	int a = 20;
	int b = 20;
	cout << "a = " << a << ": b = " << b << "\n";
	cout << "a++ = " << a++ << ": ++b = " << ++b << "\n";
	cout << "a = " << a << ": b = " << b << "\n";
	return 0;
}

运行结果:

a = 20: b = 20
a++ = 20: ++b = 21
a = 21: b = 21

       粗略的讲,a++ 意味着使用 a 的当前值计算表达式,然后将 a 的值加 1 ; 而 ++b 的意思是先将 b 的值加 1 ,然后使用新的值来计算表达式。

       例如,有下面的关系:

int x = 5;
int y = ++x;   // change x, then assign to y
               // y is 6 , x is 6
int z = 5;
int y = z++;   //assign to y, then change z
               // y is 5 , z is 6

递增/递减运算符和指针

       将递增运算符用于指针时,将把指针的值增加其指向的数据类型占用的字节数,这种规则适用于对指针的递增和递减:

double arr[5] = {21.1,32.8,23.4,45.2,37.4};
double *pt = arr;    // pt points to arr[0] ,i.e. to 21.1
++pt;                // pt poionts to arr[1] ,i.e. to 32.8

        也可以结合使用这些运算符和 *运算符来修改指针指向的值。将* 和 ++ 同时用于指针时提出了这样的问题:将什么解除引用,将什么递增。这取决于运算符的位置和优先级。前缀~和解除引用运算符的优先级相同,以从右到左的方式进行结合。后缀~比解除引用优先级高,以从左到右的方式进行结合。

         所以 *++pt 的含义如下:先将 ++ 应用于pt (因为 ++ 位于 * 的右边),然后将 * 应用于被递增后的pt :(下面的语句都是根据上面的程序独立进行)

double x = *++pt;    //  arr[1] or 32.8

另一方面, ++*pt 意味着先取得 pt 指向的值,然后将这个值加1 :

double x = ++*pt;    // arr[0]+1

圆括号对指针解除引用,然后得到21.1,然后值加1 得 22.1:

double x = (*pt)++ ;    // arr[0]+1

最后看这个组合:

#include<iostream>
int main()
{
	using namespace std;
	double arr[5] = {21.1,32.8,23.4,45.2,37.4};
	double *pt = arr;    // pt points to arr[0] ,i.e. to 21.1
	// pt poionts to arr[1] ,i.e. to 32.8

	double x = *pt++ ;    // arr[0]+1
	cout << x<< " " << *pt <<endl;
	return 0;
}

// x==21.1   *pt == 32.8

后缀运算符 ++ 用于 pt 而不是 *pt。

用while 语句 编写延时循环:

// waiting.cpp
#include<iostream>
#include<ctime>      // describes clock() function
int main()
{
    using namespace std;
    cout << "Enter the delay time , in seconds: ";
    float secs;
    cin >>secs;
    clock_t delay = secs * CLOCKS_PER_SEC;
    cout << "Starting\a\n";
    clock_t start = clock();
    while (clock() - start < delay);
    cout << "done\a\n";
	return 0;
}

do-while循环与C语言相同,略。

第五章 分支语句和逻辑运算符

字符函数库 cctype

       这玩意能有多方便呢?

       例如之前判断 ch 是不是字符的时候 :

if((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))

       现在:

if(isalpha(ch))

是不是感觉之前学了个寂寞...Hhhhhhhh

cctype中的字符函数:

isalnum()如果参数是字母或数字,返回true
isalpha()如果参数是字母,返回true
iscntrl()如果参数是控制字符,返回true
isdigit()如果参数是数字(0-9) , 返回true
isgraph()如果参数是除空格之外的打印字符,返回true
islower~~小写字母,返回true
isprint()~~打印字符(包括空格),返回true
ispunct()

~~标点符号,~~

isspace()

~~空白字符,~~

isupper()~~大写字母,~~
isxdigit()十六进制数字,~~
tolower()如果参数是大写字符,则返回小写,否则返回原参数
toupper()如果参数是小写字符,则返回大写,否则返回原参数

?:  运算符

通用格式: expression1 ? expression2 : expression3

如果  expression1 为 true ,则整个条件表达式的值是 expression2 的值,否则为expression3的值

int c = a > b ? a : b;
// 与下面语句等效
int c;
if (a > b){
	c = a;
}else{
	c = b;
}

break 与continue 语句与C语言相同,略。

第六章 函数——C++ 的编程模块

复习函数的基本知识

 

 

函数参数和按值传递

         C++ 通常按值传递参数。用于接收传递值的变量被称为形参,传递给函数的值被称为实参。

         如果在main()中声明了一个名为 num的变量,同时在另一个函数也声明一个名为 num的变量,他们却完全不同。

         下面看一个程序:

// twoarg.cpp
#include<iostream>
using namespace std;
void nchars(char,int);
int main()
{
	int times;
	char ch;

	cout << "Enter a character: ";
	cin >> ch;
	while(ch != 'q')
	{
		cout << "Enter a integer: ";
		cin >> times;
		nchars(ch,times);
		cout << "\nEnter another character or "
		     << "press the q-key to quit: ";
		cin >> ch;
	}
	cout << "The value of times is " << times << ".\n";
	cout << "Bye.\n";
	return 0;
}
void nchars(char c,int n)
{
	while(n-- > 0)
	{
		cout << c;
	}
}

说明在函数中修改形参的值不会影响调用程序中的数据。

函数和数组

       函数是处理更复杂的数据类型(如数组和结构)的关键。首先,考虑函数接口所涉及的内容。函数需要知道要对哪个数组进行累计,因此需要将数组作为参数传递给它。为使函数通用,而不限于特定长度的数组,还需要传递数组长度。这里唯一的新内容是:需要将一个形参声明为数名。           下面来看看一个函数头及其它部分:

int arr(int sum[],int n);

       这看起来合理,但方括号指出 sum是一个数组,而方括号则表明,可以将任何长度的数组传递给该函数。但实际情况并非如此:sum实际上不是数组,而是指针。 所以可以用 int *sum 代替 int sum[ ] .

函数如何使用指针来处理数组

       在大多数情况下,C++将数组名视为指针。数组名解释为其第一个元素的地址:

sum == &sum[ 0 ] ;        

       该规则有些例外。首先,数组声明使用数组名来标记存储位置;其次,对数组名使用 sizeof 将得到整个数组的长度(以字节为单位);将地址运算符& 作用于数组名时,将返回整个数组的地址。

       如果像我一样傻傻分不清,可以记这两个:

sum[i] == *(sum + i) ;
&sum[i] == sum+i ;

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

注意:为将数组类型和元素数量告诉数组处理函数,请通过两个不同的参数来传递他们:

void fabbonain(int arr[],int size);

而不要试图使用方括号表示法来传递数组长度:

void fabbonain(int arr[size]);

用 const 保护数组

        使用普通参数时,函数使用的是数据的副本,不会意外地修改普通参数的原始数据;然鹅,接受数组名的函数将使用原始数据,为防止原始数据被无意修改,可这么做:

void fabbonain(const int arr[],int size);

         个人的理解是:这就是我们在各种网络平台遇到的 " 只读 "。

使用数组区间的函数

         除了上面所说的用两个参数向函数传递数据,还有另一种给函数提供所需信息的方法,即指定元素区间(range),这可以通过传递两个指针来完成:一个指针标识数组的开头,另一个指针标识数组的尾部。

         例如,假设有这样的声明: double sum[ 20 ] ;

则指针 sum 和 sum + 20 定义了区间。首先,数组名 sum 指向第一个元素。表达式 sum + 19 指向最后一个元素(即 sum [19 ]),因此,sum + 20 指向数组结尾后面的一个位置。

指针和const

 

函数和二维数组

       例如,假设有如下代码:

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

        则sum()的原型是什么样的呢?函数为何将行数(3)作为参数,而不是列数(4)呢?

        data 是一个数组名,该数组有 3 个元素第一个元素本身是一个数组,由 4 个int 值组成。因此 data 的类型是指向由 4个 int组成的数组的指针,因此正确的原型如下:

int sum(int (*ar2)[4], int size);
int sum(int ar2[][4], int size);
// 第二种格式更容易理解
// sum()在声明参数ar2时,没有使用const,因为这只能用于基本类型的指针
// 而ar2是指向指针的指针

        数组表示法和指针表示法互换:

ar2[x][y] = *(*(ar2+x)+y);

函数和C风格字符串

将 C风格字符串作为参数的函数

(1)char 数组

(2)用引号括起的字符串常量

(3)被设置为字符串的地址的 char 指针

但上述三种选择的类型都是 char 指针,因此可以将其作为字符串处理函数的参数:

#include<iostream>
#include<cstring>
using namespace std;
int main()
{
	char ghost[15] = "galloping";
	char *str = "galloping";
	int n1 = strlen(ghost);
	int n2 = strlen(str);
	int n3 = strlen("galloping");
	
	cout << n1 << endl;
	cout << n2 << endl;
	cout << n3 << endl;
	return 0;
}
//  n1,n2,n3 都是 9 

         C风格字符串与 char 数组之间的一个重要区别是,字符串有内置的结束字符,不以空字符结尾的char数组只是数组,而不是字符串。

返回C风格字符串的函数

        函数无法返回一个字符串,但可以返回字符串地点地址,这样做效率更高。

        下面的程序定义了一个名为 buildstr () 的函数,该函数返回一个指针。该函数接受两个参数:一个字符和一个数字。函数使用 new 创建一个长度与数字参数相等的字符串,将每个元素都初始化为该字符。然后,返回指向新字符串的指针

#include<iostream>
char * buildstr(char c, int n);
int main()
{
	using namespace std;
	int times;
	char ch;
	
	cout << "Enter a character: ";
	cin >> ch;
	cout << "Enter a integer: ";
	cin >> times;
	
	char *ps = buildstr(ch,times);
	cout << ps << endl;
	delete []ps;
	
	ps = buildstr('+', 20);
	cout << ps << "-Done-" << ps << endl;
	delete []ps;
	
	return 0;
}
char * buildstr(char c, int n)
{
	char *pstr = new char[n + 1];
	pstr[n] = '\0';
	while(n-- > 0)
	{
		pstr[n] = c;
	}
	return pstr;
}

// 运行结果:
// Enter a character: h
// Enter a integer: 10
// hhhhhhhhhh
// ++++++++++++++++++++-Done-++++++++++++++++++++

函数和结构

         涉及函数时,结构变量的行为更接近于基本的单值变量,所以为结构编写函数更简单。

下面是一个示例:

#include<iostream>
struct travel_time
{
	int hours;
	int mins;
};
const int Min_hr = 60;

travel_time sum(travel_time t1,travel_time t2);
void show_time(travel_time t);

int main()
{
	using namespace std;
	travel_time day1 = {5, 45};      // 5 hours,45 min
	travel_time day2 = {4, 55};      // 4 hours,55 min
	
	travel_time trip = sum(day1, day2);
	cout << "Two-day total: ";
	show_time(trip);
	
	travel_time day3 = {4, 32};
	cout << "Three-day total: ";
	show_time(sum(trip, day3));
	
	return 0;
}

travel_time sum(travel_time t1,travel_time t2)
{
	travel_time total;
	
	total.mins = (t1.mins + t2.mins) % Min_hr;
	total.hours = t1.hours + t2.hours + (t1.mins + t2.mins)/Min_hr;
	
	return total;
}

void show_time(travel_time t)
{
	using namespace std;
	cout << t.hours << " hours, "
         << t.mins << " minutes\n";
} 

// 运行结果
// Two-day total: 10 hours, 40 minutes
// Three-day total: 15 hours, 12 minutes

传递结构的地址

下面是一个示例:

#include<iostream>
#include<cmath>

struct polar
{
	double distance;
	double angle;
};
struct rect
{
	double x;
	double y;
};

void rect_to_polar(const rect *pxy, polar * pda);
void show_polar(const polar * pda);

int main()
{
	using namespace std;
	rect rplace;
	polar pplace;
	
	cout << "Enter the x and y values: ";
	while (cin >> rplace.x >> rplace.y)
	{
		rect_to_polar(&rplace, &pplace);
		show_polar(&pplace);
		cout << "Next two numbers (q to quit): ";
	}
	cout << "Done.\n";
	return 0;
}

void show_polar(const polar * pda)
{
    using namespace std;
	const double Rad_to_deg = 57.29577951;
	
	cout << "distance = " << pda->distance;
	cout << ", angle = " << pda->angle * Rad_to_deg;
	cout << " degrees\n";	
}

void rect_to_polar(const rect *pxy,polar * pda)
{
	using namespace std;
	pda->distance =
	    sqrt(pxy->x * pxy->x + pxy->y * pxy->y);
	pda->angle = atan2(pxy->y,pxy->x);
}

// 运算符 -> 是重中之重

函数和string对象

        如果需要多个字符串,可以声明一个 string 对象数组,并将该数组传递给一个函数以显示其内容。

下面是一个示例:

#include<iostream>
#include<string>
using namespace std;
const int SIZE = 5;
void display(const string sa[], int n);
int main()
{
	int i;
// 如果需要使用 string 数组,只需使用通常的数组声明格式即可
	string list[SIZE];        
	cout << "Enter your " << SIZE << " favorite astronomical sights:\n";
	for(i=0; i<SIZE; i++)
	{
		cout << i + 1 << ": ";
		getline(cin,list[i]);
	}

	cout << "Your list:\n";
	display(list,SIZE);

	return 0;
}

void display(const string sa[], int n)
{
	int i;
	for(i=0;i<n;i++)
	{
// 形参 sa 是一个指向 string 对象的指针,因此 sa[ i ] 是一个string 对象
		cout << i + 1 << ": " << sa[i] <<endl;
	}
}

函数指针

           与数据项相似,函数也有地址。函数的地址是存储其机器语言代码的内存的开始地址。通常,这些地址对用户而言不重要,但对程序却很重要。例如,可以编写将另一个函数的地址作为参数的函数。这样第一个函数将能够找到第二个函数,并运行它。与直接调用另一个函数相比。这很笨拙,但它允许在不同时间传递不同函数的地址,这意味着可以在不同时间使用不同函数

获取函数的地址:

       获取函数地址很简单,只使用函数名(后面不跟参数)即可。

例如:

// 有函数process() 和 think() 
process(think);        // 传递的是think()函数的地址 
process(think());      // 传递的是think()函数的返回值 

声明函数指针:

       声明函数指针应指定函数的返回类型以及函数的特征标(参数列表)。

例如:

double pam(int);
double (*pf)(int);
// pam 替换为 (*pf)
// 由于 pam是函数,因此(*pf)也是函数
// 所以 pf 就是函数指针 

        两者的返回类型和特征标必须相同!

另外,由于括号优先级比 * 高 ,所以:

double (*pf)(int);
// pf 是指向函数的指针 
double *pf(int); 
// pf() 是一个返回指针的函数 

          在使用函数指针时,比较棘手的是编写原型。

下面是一个示例:

#include<iostream>
double betsy(int lns)
{
	return 0.05 * lns;
}

double pam(int lns)
{
	return 0.03 * lns + 0.0004 * lns * lns;
}

void estimate(int lines, double (*pf)(int))
{
	using namespace std;
	cout << lines << " lines will take ";
	cout << (*pf)(lines) << " hour(s)\n";
}
int main()
{
	using namespace std;
	int code;
	cout << "How many lines of code do you need? ";
	cin >> code;
	cout << "Here is Betsy's estimate:\n";
	estimate(code,betsy);
	cout << "Here is Pam's estimate:\n";
	estimate(code,pam);
	return 0;
}

深入探讨函数指针

       下面通过一个示例演示使用函数指针时面临的一些挑战:

const double * f1(const double ar[],int n); 
const double * f2(const double [],int);
const double * f3(const double *, int);
// 这三个函数的特征标实际上是相同的! 
// ar[] 可简化为 [] 
// * ar 可简化为 * 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DDsoup

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值