了解指针
指针完整的名字叫指针变量,所以指针的实质就是变量。
指针的作用:实现间接访问,当用指针变量做函数的形参,就可以返回函数处理的多个结果
指针的使用:
1.用int *p定义一个指针变量p,因为p是局部变量,所以遵循c语言局部变量的一般规律(定义了局部变量但未初始化,则其值是随机的),所以p变量中存储的值是随机的。
2.如果我们此时解引用p,则相当于我们访问了这个随机数字为地址的内存空间。但这个内存空间能否访问未知,故必须先初始化或者赋值。
定义同时初始化的格式:int a = 32; int *p = &a; (*靠近变量类型还是变量都无所谓)
先定义后再赋值的格式:int a = 32; int *p; p=&a;
("*"的作用是引用指针指向的变量值,引用其实就是引用该变量的地址,“解”就是把该地址对应的东西解开,解出来,就像打开一个包裹一样,那就是该变量的值了,所以称为“解引用”。)
3.*号的两个功能:
第一种是指针定义时,*结合前面的类型用于表明要定义的指针的类型;
第二种是解引用,*p 就表示 p 指向的变量本身 。
4.取地址符&
使用时直接加在一个变量前面,如&p,这就表示p变量的地址。
5.左值与右值:
当一个变量做左值时,编译器认为这个变量符号的真实含义是这个变量对应的内存空间。
当一个变量做右值时,编译器认为这个变量符号的真实含义是这个变量的值,即这个变量对应内存空间中存储的数。
6.const关键字与指针
(1)const关键字,在c语言中修饰变量,表示这个变量是常量,一个const关键字只能修饰一个变量。
(2)const修饰指针有4种形式
第一种:const int *p = &b;
第二种:int const *p = &b;
//第一、二种情况相同,即指针指向常量,p是没有权限改变的,只能通过改变b的值来改变p,或者把p指向另一个地址。这两种情况是可以不进行初始化的。
第三种:int * const p = &b;
//该情况为常量指针,不能改变指向的地址,可以改变指向的内容,必须进行初始化。
第四种:const int * const p = &b;
//指向的地址和内容都是常量,故不能改变指向的地址和内容。
指针与一维数组的关系
首先,从内存角度来理解数组:
从内存角度讲,数组变量就是一次分配多个变量,而且这多个变量在内存中的存储单元是依次相连接的。
例如,我们分开定义多个变量(int a,b,c,d;)和一次定义一个数组(int a[4];)这两种方法都定义了4个int型的变量,且这4个变量都是独立的成单个使用的。它们的不同点是,单独定义时a、b、c、d在内存中的地址不一定相连,但定义成数组后,数组中的4个元素地址肯定是依次相连的。
故数组中的多个变量虽然必须单独访问,但是因为它们的地址相连,因此可以用指针来操作。
对数组中几个关键符号(a a[0] &a &a[0])的理解:
以 int a[10] 为例
1. a 就是数组名
c语言规定不能整体操作数组,要独立到单个元素操作,所以 a 不能做左值。
a 做右值表示数组首元素的首地址(首地址就是起始地址,就是4个字节中最开始第一个字节的地址)。a 做右值等同于 &a[0]。
2. a[0] 表示数组的首元素
做左值时表示 a[0] 对应的内存空间(连续4个字节)
做右值时表示 a[0] 的值
3. &a 就是数组名 a 取地址
&a 不能做左值,做右值时表示整个数组的首地址。
4. &a[0] 就表示 a[0] 的首地址
当 &a[0] 做右值时等同于 &a
现在我们定义有:int a[4]={1,2,3,4}; int *p=a;
则指针p就指向数组a首元素的首地址,(p+i)就是访问数组a中下标为 i 的元素的首地址,*(p+i)就是该元素的内容。也可以用 (数组名+偏移量) 即 (a+i) 来表示元素地址。
或者也可以采用 p[i] 来访问数组,p[i]==a[i]
指针数组与数组指针
1.指针数组
由指针变量组成的数组。定义:int *p[n];
若要将二维数组赋给一指针数组:
int *p[3];
int a[3][4];
for(i=0;i<3;i++)
p[i]=a[i]; //或 p[i]= &a[0][0];
指针数组 p 的每个元素存放 数组 a 的每一行元素的首地址
2.数组指针(也称行指针)
指向数组的指针,即数组首元素地址的指针。定义 int (*p)[n];
若要指向一个二维数组:
int a[3][4];
int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]