一,指针
1,指针的类型
指针的类型和指针所指向的类型
|
指针的类型
|
指针所指向的类型
|
sizeof(*ptr) | 说明 |
int *ptr;
|
int *
|
int
|
4
|
|
int **ptr;
|
int **
|
int *
|
4
|
|
int (*ptr)[3];
|
int(*)[3]
|
int()[3]
|
12
|
指向有3个int型元素的数组
|
int (*ptr)(int);
|
int (*)(int)
|
int ()(int)
|
|
指向函数的指针,该函数有一个整型参数并返回一个整型数
|
说明:
a,指针的类型:是指针本身所具有的类型。把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。
b,指针所指向的类型:决定指针所指向的那片内存的大小和编译器怎么看待这片内存。 把指针声明语句中的指针名字和名字左边的指针声明符 *去掉,剩下的就是指针所指向的类型。
c,指针的值:在32位系统中,它是一个32位的整数,是一个地址。其所占的内存是4byte
指针所指向的类型和指针所指向的内存是不同的,一个指针被定义时,指针所指向的类型已经确定,但由于指针未初始化,它所指向的内存区是不存在的
指针数组
int *a[3]; //一个有3个指针的数组,该指针是指向一个整型数的。sizeof(a)=12,sizeof(*a)=4
int (*a[10])(int); //一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数
2,指针的强制类型转换的应用
a,新指针的类型是TYPE*: ptr1=(TYPE*)ptr2
注意:如果sizeof(ptr2的类型)大于sizeof(ptr1的类型),那么在使用指针ptr1来访问ptr2所指向的存储区时是安全的。如果sizeof(ptr2的类型)小于sizeof(ptr1的类型),那么在使用指针ptr1来访问ptr2所指向的存储区时是不安全的。
3,函数指针
定义:void (*pf)(char *); //pf是指向void,参数是char* 的类型的函数的指针。
赋值:void fun(char *); fp=fun;
调用方法:
(*fp)(name); 或者 fp(name);
ANSI C支持这两种;unix支持第二种;K&R C支持第一种。
注意区分 void *pf(char *); //pf是返回一个指针的函数
二,数组
1,一维数组:
<1>指定初始化项目(C99):int date[4] = {[0]=1,[5]=5}; 其他项为0。
<2>数组名是该数组首元素的地址:date==&date[0],是一个指向int型的常量指针。
<3>对指针加1,等价于对指针的值加上它指向的对象的字节大小:date+2==&date[2] *(date+2)==date[2]
<4>保护数组的内容:int sum(const int ar[],int n);
<5>数组做函数形参: int sum(int *ar,int n);int sum(int ar[],int n);
2,指针和多维数组
二维数组初始化:date={{1,2,3},{4,5,6}} 也可以省去{}。
指向二维数组的指针:int zippo[4][2]; 和 int (*pz)[2];
pz指向包含两个int值的数组,即是指向二维数组,该二维数组有2列。使用该类型指针时注意不要超过二维数组的行数的范围
pz=zippo; zippo==&zippo[0]; zippo[0]==&zippo[0][0]; zippo==&(&zippo[0][0]); *(zippo+2)==zippo[2]==&zippo[2][0] //第三个元素,即包含2个int值的数组 *(*(zippo+2)+1)==zippo[2][1]
指针兼容:
int **p1;int *p2[2]; p1=pz;(非法)//pz是指向int[2]型的指针。p1是指向int *的指针 p1=p2;(合法)
二维数组做函数形参:
void fun(int (*pz)[2]); 或 void fun(int pz[][2]);
3,指针变量作为函数参数
<2>如果想要改变的是指针变量p的值,就要传递p的地址。
void getmemory(char *p, int num) { p = (char *)malloc(sizeof(char)*num); } void test() { char *str = NULL; getmemory(str, 100); //此时str仍为NULL strcpy(str, "hello"); //出现段错误 } 正确写法有两种: a种方法 void getmemory(char **p, int num) { *p = (char *)malloc(sizeof(char)*num); } void test() { char *str = NULL; getmemory(str, 100); strcpy(str, "hello"); free(str); } b种方法 char* getmemory( int num) { return (char *)malloc(sizeof(char)*num); //返回的指针指向堆区 } void test() { char *str = NULL; str = getmemory(100); strcpy(str, "hello"); free(str); }
三 , 引用
引用是C++中新增的一种复合类型,引用是对象的别名,其典型的用途是作为函数参数,具体的说是结构和对象的参数。
1,引用的定义和作为函数参数
//定义 int rats; int & rodents = rats; int * rodentsp = &rats; //作为函数参数 void swap(int &a, int &b) { int temp; temp = a; a = b; b = temp; } void main() { int a = 30 , b = 20; swap(a, b); }
引用作为函数参数使得函数中的变量名成为调用程序中变量的别名,这种传递方式成为引用传递。引用传递允许被调用函数能够访问调用函数中的变量;而C语言只能按值传递,被调用函数使用调用函数的值的拷贝。
2,临时变量,引用参数和const
double refcube(const double &ra) { retirn ra*ra*ra; } //下面的调用方式都将产生临时变量 double side = 3.0; long edge = 5L; double c1 = refcube(side + 10.0); //表达式 double c2 = refcube(7.0); //传递常量 double c3 = refcube(edge); //类型不符合
若refcube函数的参数不是const型的,则不能产生临时变量,即上述的调用方式将出错。若声明将引用定义为const,则在必要时产生临时变量,其行为类似于按值传递。
3,将const用于引用返回类型
typedef struct point { int x; int y; }Point; Point &accumulate(Point &p1, const Point &p2) { p1.x += p2.x; p1.y += p2.y; return p1; } void main() { Point p1 = {1, 2}; Point p2 = {3, 4}; //p1, p3的值是一样的,函数返回的是传入的p1的引用 Point p3 = accumulate(p1, p2); //函数返回的是p1的引用,所以这个语句是可行的。若是按值返回,则不能通过编译 accumulate(p1, p2) = p2; }
返回的非const引用使其含义模糊;将返回的引用声明为const,则最后一条语句不合法。
返回引用时,需注意:应避免返回函数终止时不再存在的内存单元的引用。
4,传值,传指针,传引用
<1>如果数据对象很小,则按值传递
<2>如果数据对象是数组,则使用指针。因为这是唯一的选择。
<3>如果数据对象是较大的结构,则使用引用或指针
<4>如果数据对象是类对象,则使用引用。类设计的语义常常要求使用引用。
传指针和引用时,若不修改调用函数的数据,尽量使用const修饰
四,指针与引用的区别
http://blog.csdn.net/listening_music/article/details/6921608
1,指针与引用的区别
a,引用不可为空;指针可以是空的。使用指针之前必须做判空操作,而引用就不必
b,引用在定义的时候初始化,且不能再被赋值,其本身是常量;而指针是变量
c,引用的大小是所指向的便量的大小;指针是指针本身的大小
d,指针和引用的自增(++)运算意义不一样。指针的自增是指针指向的地址加1,引用则是所代表的内存的值加1.
d,指针指向一块内存,它的内容是所指内存的地址;而引用是某块内存的别名,且引用不改变指向。
2,常量指针和常量引用
指向常量的指针和引用: const int *pointer = &i; const int& refs = i;
这里*pointer是常量,不能通过指针修改这块内存,该指针也不能赋给其他非常量指针;常量引用也是一样,所代表的内存是常量,不能通过该引用改变这块内存。
五,注意
<1>int days[]={....},sizeof days是整个数组的大小;sizeof day[0]是一个元素的大小(以字节为单位)
<2>C并不检查你是否使用了正确的下标,例如:int a[10];a[10]=12;编译器不会发现这样的错误。当程序运行时,这些语句把数据放在可能由其他数据使用的位置,因而可能破坏程序的结果甚至使程序崩溃。
<3>在返回指针变量时,注意不要用return返回指向栈内存中的指针。否则,函数返回后该指针指向的内存被释放。
<4>当创建一个指针时,系统只分配了用来存储指针本身的内存空间,并不分配用来存储数据的内存空间。因此在使用指针之前,必须给它赋予一个分配的内存。(可用malloc或把一已存在的变量地址赋给指针)。