专题八 指针

8.1地址与指针的概念

8.1.1指针的含义

指针就是用来存放地址(变量占据的内存单元的首地址) 的变量。
1,这个地址可以是变量的地址,也可以是数组、函数的起始地址,还可以是指针的地址。某个指针存放了哪个变量的地址,就说该指针指向了这个变量。
2.需要注意的是指针变量的值是它所指向的变量的地址,而不是该变量的值。

8.1.2地址的含义

计算机中 CPU可以直接访问的、用来存储数据的记忆部件称为存储器。存储器由成千上万个顺序存储单元组成,每个单元有一个唯一的地址标识。给定计算机的存储器地址范围为从0到所安装的存储器数量的最大值减 1。在计算机上所运行的每一个程序都要使用存储器。
在程序中定义一个变量,在编译时就给这个变量分配内存单元,系统根据程序中定义的变量类型,分配一定长度的空间。例如,一个int 型变量占据的存储单元为2个或4个字节,一个float型为4个字节,一个char型为一个字节等。变量所占据的内存单元的首地址就是变量的地址。

8.2指针变量

8.2.1指针的定义

定义格式:
类型名 *指针名
1.*是一个指针变量的标志,指针可与非指针变量一起说明。 如

char*p,ch;

2.在使用指针之前,一定要先使指针具有明确的指向,这一点可以通过对指针初始化或者赋值来完成如

int i,j;
int *p1,*p2;//定义指针
p1=&i;
p2=&i;//赋值

与常规的变量未赋初值相同,没有明确指向的指针不会引起编译器出错,但是对于指针来说,可能导致无法预料的或者隐藏的灾难性后果。
3.只有整省变量的地址才能放到指向整型变量的指针变量中去,因为不同数据类型的指针指向下一位需移动不同的字节数,如符型需要移动一个字节,而整型需要移动二个或四个字节…

float a;//定义a为float 型
int*pointer_1;//定义pointer_1为类型名为int的指针变量
pointer_1=&a;//将float型变量的地址放到指向 int 型指针变量中,错误

4、指针变量中只能存放地址,不能将一个常量(或任何其它非地址类型的数据) 赋给一个指针变量如

int*pointer_1=100; //错误,pointer_1为指针变量,100为常量。

8.2.2与指针有关的运算符

&:取地址运算符
*:指针运算符(或称”间接访问”运算符)。取其指向的内容
1.&运算符只能作用于变量,包括基本类型和数组的元素,不能作用于数组名和常量

int a[20],n;
表达式&n,&a[0]是合法的,&a 是非法的。

2.单目运算符*是&的逆运算,它的操作对象是地址,*运算的结果是指针指向的对象本身.

char c;
char *pc;
pc=&c;//那么*pc的结果就是c的值

3.“&”和“*”两个运算符的优先级相同,但是按自右向左的方向结合,如&*p 因此先进行p 的计算,再执行&运算。
4.(*p)++、p++和(++p)的辨别:

(*p)++是指p所指向的值加一,*p++相当于* (p++),
先得到然后再使p的值加一;*(++p)指的是p先加一,然后再取"p"
8.2.3对指针变量的引用

1.给指针变量赋值。如

int a,*p;
p=&a;//把a的地址赋给指针变量p

2.引用指针变量指向的变量
(1)如果已执行“p=&a;”,即指针变量p指向了整型变量a,则 printf(“%d”,*p);
作用是以整数形式输出指针变量p 所指向的变量的值,即 a 的值。(2) 如果有以下的赋值语句

int a,*p;
p=&a;*p=1;

表示将整数1赋给P当前所指向的变量,如果p指向变量a,则相当于把1赋给a,即“a=1;
(3)引用指针变量的值。如
printf(“%o”,p);
作用是以八进制数形式输出指针变量节的值,如果p指向了a就是输出了a的地址,即&a.
3,下面举一个例子分析一下:

#include<stdio.h>
void main()
{
int a;
int *pa=&a;
a=10;
printf("a:%d\n",a);
printf("*pa:%d\n",*pa);
printf("&a:%x(HEX)n",&a);
printf("pa:%x(HEX)n",pa);
printf("&pa:%x(HEX)n",&pa);
}
运行的结果为:
a:10
*pa:10
&a:ff4(HEX)
pa:fff4(HEX)
&pa:fff2(HEX)
上述输出的结果中,第一和第二行输出的结果是值,不会改变,
而后三行输出的是地址值,每次运行可能输出的地址值不同。
8.2.4通过指针交换数值
int a,b,*m,*n,p,*q;
m=&a;
n=&b;
值交换
p=*m;
*m=*n;
*n=p;

8.3指针与数组

8.3.1指向一维数组的指针

int a[10];
int *p;
p=&a[0];或p=a//将数组a的首地址赋给指针变量P
访问数组元素的3种方式对比(三种方法都是等价的)

1.数组名
*a *(a+1)
2.下标法
a[0]/p[0]
3.指针变量
*p *(p+1)

8.3.2指向二维数组的指针

int a[10][10];
与数组a相关的地址表示形式

表示形式含义
&a指向二维数组的指针
a[0],*(a+0),*a第1行第1列元素地址
a+1,&a[1]第2行首地址
a二维数组名,数组首地址
a[1],*(a+1)第2行第1列元素地址
a[1]+1,*(a+1)+1,&a[1][1]第2行第2列元素地址
(a[1]+1),(*(a+1)+1),a[1][1]第2行第2列元素的值

说明:
1.a[0]、a[1]、a[2]是一维数组名,而在C 语言中数组名代表数组的首地址,因而此 a[0]代表第1行一维数组中第1列元素的地址。即&a[0][0]。a[1]的值就是&a[1][O],a[2]的值就是&a[2][0]。
2.既然 a[0]是第1行的首地址(一个一维数zu的首地址),那 +1 就是第1行第2列的元素的地址这个一维数组的第2个元素的地址)了。
3.a[i]和*(a+i)等价,则a[i]+1和*(a+i)+1的值都是&a[O][1]。
4.指向行的指针和指向列的指针的区别
如 char a[2][10]= {“hello”,“xuejie”}
(1)二维数组名(如a)是指向行的,因此"a+1”代表"xuejie"这一行。
(2)一维数组名(如a[0]、[1] 是指向列元素的。“a[0]+1”指向的是"hello"中的字符’e’。
(3)在指向行的指针前面加上一个“”,就转换成了一个指向列的指针,如a和a+1都是指向行的指针,前面加上“”就变成了a 和(a+1)它们是指向列的指针。相反如果在列指针前面加上一个“&”,则它们就成了指向行的指针。

8.4字符串的指针

8.4.1字符数组的定义

char *str=“hello world!”; char str; str=“hello world!”
在指向字符串的时候,并不是把字符中的所有字符存放到str中,也不是把字符串赋给
str,只是把字符串的首地址赋给指针变量

8.4.2字符数组与字符指针的定义

char string[ ]=“hello world!”;
char *str=“hello world!”.
l.sting 和 str 的值都是字符串"hello world的首地址,但是sring 是一个字符数组,名字本身是一个地址,而str 是一个指向字符串首地址的字符指针,因而 str 可以被赋值,而 string 不能。
2.通过字符数组名或者指针变量可以输出一个字符串,而对一个数值型数组,是不能试图用数组名输出它的全部元素的。 如

char string="hello world!,*p=string;
printf("%s\n",string);//正确
int a[]={1,2},*p=a;
printf("%s\n",a);//错误

8.5指针数组与数组指针

8.5.1指针数组

如果一个数组的元素是由指针变量组成,那么这个数组称为指针数组
定义形式:类型名数组名[常量表达式] 如:inta[10];
优点:1.指针数组对处理字符串提供了更大的方便和灵活,由于每个元素都为指针变量,因此通过地址运算来操作正文行是比较方便的。
2.用数组来存储这些长度不等的字符串,那么必须设定数组的长度可以容纳下字符串中最长的字符串,这样也许会浪费掉很多的内存空间。
3.如果要对字符串进行排序,不必改动字符串的位置,只需改动指针数组中各元素的指向。

8.5.2数组指针

是一个指向长度为整型常量的一维数组的指针。
定义形式:类型名 (*指针名)[整型常量]
如:int(*a)[10];
int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};
int (p)[4];p=a+1;
//p指向数组的第二行,则
p 或 p[0]是 p[1][0]的地址。

8.6 多级指针

指向指针的指针定义与理解指向指针数据的指针变量,简称为指向指针的指针。 例: int**p;理解,指针变量也是变量,和其他类型的变量一致,也需要内存单元,既然占据内存单元,就有相应的地址,那么,可以再定义另外一种“指针”指向这个地址。这种指针就是“指向指针的指针”。从理论上说,间接方法可以延伸到更多的级,但是实际上在程序中很少有超过二级间址的,级数越多,越容易产生混乱,出错的机会也多。建议初学者在编程时要慎用多级指针,即指向指针的指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值