引用:
引用是某个对象(即变量)的别名。
形式如下:
类型 &引用名 = 变量名;
注意:
1.在定义引用时,引用符&在类型与引用名之间的位置是灵活的。
int& ir = i;
int & ir = i;
int &ir = i;
以上几种定义完全相同。
2.在变量声明时出现的&才是引用运算符,其他地方出现的&都是地址操作符。
int& fun( int &i1, int &i2); //引用参数,函数返回引用。
3.引用代表一个变量的别名,必须在定义时初始化,不能在定义完成后再给它赋值。
float f;
float &fr;
fr = f;
以上语句是错误的。
可为一个变量指定多个引用。为引用提供初始值的,可以是一个变量,也可以是另一个引用名。
4.一个引用名只能是一个变量的别名,不能再次将它指定为其他变量的别名。
5.引用实际是一种隐式指针,但它与指针的用法存在区别。
6.当用&运算符获取一个引用的地址时,实际取出的是引用对应的变量的地址。
int i = 9;
int &ir = i;
int *pi = &ir;
pi实际指向的是i。
7.建立引用时有一些限制
不能建立引用的引用;不能建立引用数组;不能建立数组的引用;可以建立指针的引用,但不能创建指向引用的指针。
int a[10];
int &aa = a; //错误,不能建立数组的引用。
int &ia[5]; //错误,不能建立引用数组。
指针:
指针功能最强但又最危险。
指针变量的定义语句:
数据类型 * 变量名;
int * iPtr;
int iCount = 28;
iPtr = &iCount;
(*iPtr的类型是整型,指针iPtr指向该整数,所以iPtr的类型是整型指针,而iPtr的地址(即&iPtr)的类型是整型指针的地址,即指向整型指针的指针。三者都不相同。)
(在32位机器中,整数和指针都占4个字节。但指针和整数表示的是不同的类型。)
指针的初始化:
指针在使用前要进行初始化。指针忘了赋值比整型变量忘了赋值危险得多。
指针类型与实际存储的匹配:
指针是有类型的,给指针赋值,不但必须是一个地址,而且应该是一个该指针类型相符的变量或常量的地址。
int i=0;
int * iPtr = &i; // *iPtr的内容是起始点为i的地址的一个整型数。
指针具有一定类型,它是值为地址的变量,该地址是内存中另一个该类型变量的存储位置。
指针运算:
数组名本身,没有方括号和下标,它实际上是地址。表示数组的起始地址。
int iArray[10];
int * iPtr = iArray; //用数组名对指针初始化。
或 iPtr = &iArray[0]; //同样表示数组的第一个元素的地址。
由于指针是具有某个数据类型的地址,所以指针运算都是以数据类型为单位展开的。即 iPtr是个整型指针,iPtr++使指针指向下一个整数。若在32位系统中,iPtr的地址值实际是增加4,因为在32位系统中int型占4个字节。
只有加法和减法可用于指针运算。
sum += *iPtr;
iPtr++;
以上两条语句可压缩为以下一条语句:
sum += *iPtr++; 或 sum += *(iPtr++);
指针和数组:
数组名可以拿来初始化指针,数组名就是数组第一个元素地址。
数组名是指针常量,区别于指针变量。给数组名赋值是错误的。
int iArray[100];
int sum = 0;
……
for(int i = 0; i < 100; i++)
{
sum += *iArray;
iArray++; //Error。数组名不是左值。
}
数组名表示内存中分配了数组的固定位置,修改了这个数组名,就会丢失数组空间。
const指针:
指向常量的指针(常量指针)
在指针定义语句的类型前加const,表示指向的对象是常量。
const int a = 78;
const int b = 28;
const int * pi = &a;
* pi = 58; //Error。
pi = &b; //OK.
int * pj = &b; //error。b为常量。不能把它的地址赋给非常量指针。
常量指针定义const int * pi = &a;告诉编译器,*pi是常量,不能将*pi作为左值进行操作。
指针常量
在指针定义语句的指针名前加const,表示指针本身是常量。
char * const pc = "asdf";
pc = "dfgh"; //Error.指针常量不能改变其指针的值。
*pc = 'b'; //OK.
*pc++ = 'y'; //Error. 指针常量不能改变其指针的值。
在定义指针常量时必须进行初始化。
指针常量定义 int * const pc = &b;告诉编译器,pc为常量,不能作为左值进行操作,但是允许修改间接访问值,即*pc可以修改。
常量指针常量
可以定义一个指向常量的指针常量,它必须在定义时进行初始化。
const int ci = 7;
int ai;
const int * const cpc = &ci;
const int * const cpi = &ai;
*cpi = 39; //Error
ai = 39; //OK.
常量指针常量 const int * const cpc = &b;告诉编译器,cpc和*cpc都是常量,它们都不能作为左值进行操作。
总结:若const位于*号左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;若const位于*号右侧,const就是修饰指针本身,即指针本身是常量。
void 指针
它是空类型指针,不指向任何类型。仅仅只是一个地址。
不能进行指针运算,也不能进行间接引用。因为这两种操作都需要指针的类型信息。
将其他指针的值赋给空类型指针是合法的。但是 将空类型指针赋给其他指针则不被允许,除非进行显式转换。
int a = 20;
int * pr = &a;
void * p = pr; //OK
pr = p; //Error
pr = (int *)p; //OK
指针函数
返回指针的函数称为指针函数。
它可以返回堆地址,可以返回全局或静态变量的地址。但不要返回局部变量的地址。
字符指针
字符串的类型是指向字符的指针(char*)。它与数组名同属一种类型。
字符串通常存放在内存data区的const区。由于字符串的地址属性,两个同样字符组成的字符串的地址是不相等的。
如:
if("join" == "join") //此判断语句得出的结论为假。
程序中两个字符串的比较实质上是两个地址的比较。
字符串、字符数组名、字符指针均属于同一种数据类型。
输出字符指针就是输出字符串。输出字符指针的间接引用就是输出单个字符。
字符串比较:
字符串比较应该是逐个字符一一比较。通常使用标准库函数。
strcmp(),它在string.h头文件中声明。
原型:int strcmp( const char * str1,const char * str2);
(1)当字符串str1等于串str2时,返回值0;
(2)当str1串大于str2串时,返回一个正值;
(3)当str1串小于str2串时,返回一个负值。
字符串赋值:
可以用字符串去初始化字符数组,但是不能对字符数组赋予一个字符串,因为数组名是常量指针,不是左值。
char buffer[10];
buffer = "hello"; //Error
char buffer[10] = "hello"; //OK
可以使用标准库函数对字符数组进行赋值。
C语言标准库函数strcpy,把从src地址开始且含有'\0'结束符的字符串复制到以dest开始的地址空间。