📄 c++7.dat
字号:
所谓指针数组就是指数组的每一个元素都是指针.
6.2 用指针访问数组元素
我们已经知道:数组名就是数组在内存中的首地址,即数组中第一个元素的地址.我们可以通过下标访问数组元素,也可以通过指针访问数组元素.对于下面的数组:
int ara[5] = {10, 20, 30, 40, 50};
如果打印ara[0]和*ara均输出结果10,即数组ara第一个元素的值.如果要打印ara的第三个元素,可用下面的语句:
cout << *(ara+2) ; // 即打印ara[2]
对于数组ara:
ara+0 指向 ara[0]
ara+1 指向 ara[1]
ara+2 指向 ara[2]
ara+3 指向 ara[3]
ara+4 指向 ara[4]
虽然数组名是指针,但它是常量指针,数组名的值是不能改变的.
我们也可以用指针访问二维数组元素,不过比一维数组元素的访问麻烦一些.由于二维数组元素在内存中是一维的,且按行存放.所以用指针访问二维数组的关键是如何计算出某个二维数组元素在内存中的地址.例如,对于一个m行、n列的二维数组num,num[i][j](i≤m,j≤n)在内存中的地址应为:num+i×n+j.
6.3 main函数的参数
到目前为止,我们编写的程序中,main函数都没有参数.实际上main函数也可以带参数,它们用于接收命令行参数.main函数原型为:
返回类型 main( int argc, char *argv[] )
其中,argc是参数个数(文件名也是参数),argv是一个指向字符串的指针数组.
// command.cpp
#include <iostream.h>
void main( int argc, char *argv[] )
{
int i;
for( i = 1; i < argc; i++ )
cout << argv[i] << " ";
cout << endl;
}
command.cpp文件中的main函数的功能是:打印从命令行输入的、除文件名外的其它字符串.假如我们将文件command.cpp编译、连接,生成执行文件command.exe,在命令行提示符下键入:
command I am learning C++
则argc=4,argv[0]="I", argv[1]="am" ,argv[2]="learning" ,argv[3]="C++".
输出结果为:
I am learning C++
由于main函数不能被其它函数调用,只能被系统调用,因此不可能在程序内部取得实际值.那么,在何处把实参值赋予main函数的形参呢? 实际上,main函数的参数值是从操作系统命令行上获得的.当我们要运行一个可执行文件时,在DOS提示符下键入文件名,再输入实际参数,便可把这些实参传送到main的形参中去.
DOS提示符下命令行参数的一般形式为:
C:\>可执行文件名 参数 参数……
需要注意的是:main 的两个形参和命令行中的参数在位置上不是一一对应的.因为,main的形参只有二个,而命令行中的参数个数原则上未加限制.argc参数表示了命令行中参数的个数(文件名本身也算一个参数),argc的值是在输入命令行时由系统按实际参数的个数自动赋予的,而其它参数的标识符被存放在指针数组argv中.
例如,如果运行程序时,键入命令:
c:\path\program -c filename.txt
则命令行参数共有3个,即argc=3,它们分别是c:\path\program、-c、filename.txt.标识这三个参数的字符串的地址分别存放在argv数组的argv[0]、argv[1]和argv[2]中.
第七节 函数指针
在C++中,可以将函数地址保存在函数指针中,然后用该指针间接调用函数.例如:
int (*Compare)(const char*, const char*);
该语句定义了一个函数名为Compare的函数指针,它能用于保存任何有两个常量字符形参、返回整型值的函数的地址.例如,Compare能指向C++标准的字符串比较函数库中的函数strcmp:
Compare = &strcmp; // Compare 指向strcmp函数
&运算符可以省略:
Compare = strcmp; // Compare 指向strcmp函数
函数指针也能在定义时初始化:
int (*Compare)(const char*, const char*) = strcmp;
当把函数地址赋给函数指针时必须匹配.上面的定义是有效的,因为函数strcmp的原型与Compare匹配:
int strcmp(const char*, const char*);
给定了上面的定义后,strcmp能被直接调用,也能通过Compare被间接调用,下面的三个调用是等价的:
strcmp("Tom", "Tim"); // 直接调用
(*Compare)("Tom", "Tim"); // 间接调用
Compare("Tom", "Tim"); // 间接调用
第八节 引用
引用是一个变量的别名,除用&取代*外,定义引用的方法与定义指针类似.例如:
double num1 = 3.14;
double &num2 = num1; // num是num2的引用
定义num2为num1的引用,它并没有复制num1,而只是num1的别名.也就是说,它们是相同的变量.例如,如果执行下面的语句:
num1 = 0.16;
则num1和num2 的值均为0.16.
不同于变量的定义:可以先定义,后初始化.正如上面看到的:引用必须在定义时初始化.例如,下面的定义是错误的:
double &num3; // 非法:引用没有初始化
num3 = num1;
引用可用常量来初始化,此时,常量会被复制,引用与其复制值保持一致:
int &n = 1; // n 取1的复制值
为什么用常量初始化引用时要被复制,我们看下面的例子:
int &x = 1;
++x;
int y = x + 1;
第一行的1和第三行的1可能占用相同的存储单元(大多数编译器将两个1分配在内存中相同的地方),虽然我们期望y的值为3,但它的结果可能是4,这是由于第二行的++x运算后,常量1的值变成了2.如果我们使x取1的复制值,可保证x的改变不会影响到常量的值.
其实,引用作为另一个变量的别名用处不是很大,除非变量名很长.引用最重要的用处是作函数的参数.我们知道,函数参数传递有值传递和引用传递两种方式.用引用作为函数,是引用传递方式.为了比较值传递和引用传递的区别,我们仍然以交换两个变量值的函数作为例子:
1 void Swap1 (int x, int y) //值传递
{
int temp = x;
x = y;
y = temp;
}
2 void Swap2 (int *x, int *y) //引用传递(指针)
{
int temp = *x; *x = *y;
*y = temp;
}
3 void Swap3 (int &x, int &y) //引用传递
{
int temp = x;
x = y;
y = temp;
}
在上面的三个函数中,虽然Swap1交换了x和y,但并不影响传入该函数的实参,因为实参传给形参时被复制,实参和形参分别占用不同的存储单元.
Swap2使用指针作为参数克服了Swap1的问题,当实参传给形参时,指针本身被复制,而函数中交换的是指针指向的内容.当Swap2返回后,两个实参可以达到交换的目的.
Swap3通过使用引用参数克服了Swap1的问题,形参是对应实参的别名,当形参交换以后,实参也就交换了.
使用引用的规则:
1. 初始化后,程序不能改变引用的值.
2. 不能创建指向引用的指针.
3. 不能比较两个引用的值,可比较被引用变量的值.
4. 不能使引用的值加,减和改变,但对被引用变量的值可以.
5. 不能对void进行引用.
6. 不能建立引用数组.
7. 没有引用的引用.
8. 有空指针,无空引用.
第七节 Typedef
C++不仅提供了丰富的数据类型,而且还允许由用户自己定义类型说明符,也就是说允许由用户为数据类型取"别名",该功能是通过关键字typedef来完成的.例如,有整型量a、b:
int a,b;
int是整型变量的类型说明符,int实际上是integer的简写.为了增加程序的可读性,可把整型说明符用typedef定义为:
typedef int INTEGER
以后就可用INTEGER来代替int作整型变量的类型说明了,例如:
INTEGER a,b;
它等效于:
int a,b;
用typedef定义数组、指针、结构等类型将带来很大的方便,不仅使程序书写简单而且使意义更为明确,因而增强了可读性. C++中是用关键字typedef定义一个标识符来代表一种数据类型,该标识符可以象其它基本类型的标识符一样使用.在用typedef进行类型定义时,其语法和变量定义很相似.typedef定义的一般形式为:
typedef 原类型名 新类型名
例如:
typedef int * intptr;
定义intptr为一个指向整型的指针类型.变量定义语句:
intptr p;
等价于:
int * p;
需要注意的是:typedef定义的类型只是C++已有类型的别名,而不是新类型.有时也可用宏定义来代替typedef的功能,但是宏定义是由预处理完成的,而typedef则是在编译时完成的,后者更为灵活方便.
typedef可以为数据类型定义一个符号名,就象引用是一个变量的别名一样.它的主要用途是简化复杂的类型说明,改进程序的可读性.下面是几个例子:
typedef char *String;
Typedef char Name[12];
typedef unsigned int uint;
这些定义的效果是String变成char*的别名,Name变成有12个元素的字符数组的别名,uint变成unsigned int的别名.
String str; // 等价于char *str;
Name name; // 等价于 char name[12];
uint n; // 等价于unsigned int n;
前面复杂的的Compare说明,用typedef简化后,可读性就好多了:
typedef int (*Compare)(const char*, const char*);
int BinSearch (char *item, char *table[], int n, Compare comp)
{
//...
if ((cmp = comp(item, table[mid])) == 0)
return mid;
//...
}
typedef使得Compare作为一个新的类型名,它表示一个有给定原型(有两个常量字符指针参数,返回值为int型)的函数指针类型.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -