指针
指针是C语言的灵魂,用好了指针可以在C编程中事半功倍地实现一些强大的功能。同时,也是难点,其概念复杂,用法灵活,使用不当也会导致隐蔽而严重的程序问题。
指针概述
简单来说,指针就是一种数据类型,用来表示内存地址。使用指针类型声明的变量就是指针变量,使用指针变量可以灵活地对内存空间进行灵活的操作。
-
访问内存的两种方式:第一种是直接访问,第二种是间接访问。
我们知道变量有变量值和变量地址,直接访问就是直接从空间的地址获取该内存内容的访问方式,比如*(&a);
间接访问就是使用地址操作符来获取变量的地址,比如 &a ,再将 &a 赋值给另一个类型的变量 b,借助变量 b ,用 *b 可以获得 a 的内容。在这个过程中,系统要访问 b,先找到与变量 b 对应的内存地址,再根据该地址找到为 b 分配的空间,获取 b 的值,即 &a ,根据 b的类型,系统可以知道这个值是一个地址,于是继续查找该地址对应的内存空间,最后获取该空间的内容。
指针的概念:地址就是指针,一个变量的地址就是指针型常量,如 a 的地址和 b 的地址,用来保存地址的变量就是指针型变量,如b。指针变量关联到 4 个属性:指针变量的地址、指针变量的值(可变)、指针指向的空间地址(以指针变量的值为地址的空间地址,常量,与指针变量的值相同)、指针指向的内存空间的内容。
指针类型由两部分组成:数据类型名和指针操作符。标准形式:数据类型名 * 指针变量名;数据类型名声明了指针变量指向的内存空间存储的数据类型,定义指针变量时,一般将指针操作符放在靠近变量名的位置。举例说明:char * cp;是将变量 cp 声明为一个 char 型指针,即指针变量 cp 指向一个 char 型内存空间。
指针的使用:赋值和初始化
-
赋值就是设定指针指向的内容空间,必须赋给它一个地址或其他指针的值。指针变量的值在一次赋值后,可以再次被赋值为其他地址,这时,指针变量的指向从一个空间转移到另一个空间。
原则上,不能将整数数值赋值给指针变量,否则指针变量会指向以该整数数值为地址值的内存空间。比如:int * p1 = 12; p1 指向地址为 12 的内存空间。
-
初始化和其他变量一样,也应该在其定义语句中初始化,明确该指针变量指向的内存空间(变量),否则指针将指向一个不可知的空间。如果不能明确设定其指向的对象,就将其初始化为NULL。
const 指针有三种:1、指向 const 的指针变量 2、const 型指针变量 3、指向 const 型的 const 指针变量 1、int const *p 2、int * const p 3、const int * const p
-
指针型变量作为函数的形参和函数值:
指针形参:函数调用时,将实参的值赋给形参,使用指针变量作为函数参数,可以将一个内存空间的地址传递到函数中,可以通过地址来操作该地址上的内存空间。首先我们要定义一个含有指针变量形参的函数;其次要在主调函数中为该变量分配空间,并将一个指针变量指向该空间;然后以这个指针变量为实参调用定义好的函数;在这个函数内改变该指针指向的值;函数返回后,主调函数的变量已经被改变。
指针型函数:指针型的数据也可以作为函数的返回值,含有指针型函数值的函数的声明一般为:数据类型 * 函数名(形参列表);如:int *
max(int a, int b,intc);此 max 函数中的 return 语句必须返回一个变量的地址或者一个指针变量的值。函数型指针:指向函数的指针。如 int (* fp)(const int a, const int b);括号不能省。然后将 fp 赋值为相应类型的函数变量,这样就可以使用 fp 和 *fp 来调用函数了。
-
void 型指针:无类型指针。可以指向存储任意数据类型的空间。定义形式: void * 变量名 无法对 void
型指针做加减运算和取内容操作,因为对指针的加减是基于指针指向的类型空间的字节长度进行的。而 void
型指针变量指向的地址空间的类型是不可知的。 -
知识点:地址传递并不是说传递实参的地址,而是指传递的是一个变量的地址,这个地址仍是实参的值。
以上就是指针的基本知识,另外,指针与不同的数据类型结合产生了几组十分相似但功能不同的数据类型:指针与数组、指针与二维数组、指针与字符。
-
指向数组元素的指针:把数组中某元素的地址赋值给指针变量。 比如有一个 int 型 array 数组,定义: int array[10] =
{0}; 将第 0 个元素的地址赋值给一个 int 型指针:int * p0 = &array[0]; 这样,指针变量 p0
就指向数组的第 0 个元素。 -
指针访问数组:若有指向某数组的指针变量 p ,那么数组中各个元素的地址可以使用数组元素型指针 p 加上偏移量表示(索引法)。
-
数组指针:数组名和地址偏移量组成的指针。它可以作为函数形参,形式如下:void print_array(int array[SIZE]);
void print_array(int array[]); void print_array(int * array);
这三种声明是一样的,编译器都会将其中的 array 处理为 int 型指针。调用含数组形参的函数时,数组变量和数组元素型指针变量都可以作为实参,它们的值都是数组的首地址。调用函数时,指针变量型数组的形参会被赋值为数组的首地址。
-
指针与二维数组:假设有数组: int a[3][2] = {{1,2}, {11,12}, {21,22}}; 此二维数组的地址为 a
,也是该二维数组的首地址,表示为:a(数据类型为 int(* )[2])、&a(int( * )[3][2])
、&a[0](int(*)[2]) 、&a[0][0] (int *)、a[0](int *) 、*a(int *) 。 第 m 行第n
列元素的地址用指针法表示为 *(a+m)+n;或者直接取地址:&a[m][n]; -
指针与字符:字符指针就是字符型内存空间的指针变量,定义如下: char * p = NULL;使用字符指针可以访问字符数组和字符串。
指针作为C 语言中最重要的内容,是C 语言编程的灵魂,要想学得明白,还得付诸实践。