指针
1、 指针:它是一种用符号形式使用地址的方法,计算机的所有指令都依赖于地址,指针在某个程度上更阿基贴合计算机的处理方式,因此更有效率,之前也说过,数组即是指针的一种表现,呢么接下来我们聊聊指针。
2、 数组和指针:
现在自己可以试试下面的代码:
int main(){
int array2[11]={ 0,1,2,3,4,5,6,7,8,9};
array2==&array2[0];
…
return 0;
}
此时你会发现编译器没有报错,那么我们就聊聊这个。
array2==&array2[0];
中array2是数组名,&array2[0]指的是数组array2的第一个元素的地址,那么这两个相等成立,表明两者都表示该数组的第一个元素的地址,在程序运行过程中,这二者里面的地址是不会改变的,但是可以吧这个地址赋值给指针变量,然后修改指针变量的值。
来一段代码
int main(){
int array2[11]={ 0,1,2,3,4,5,6,7,8,9};
double array[10];
int *pi;
double *pj;
pi=array2;
pj=array
for(inti=0;i<10;i++){
printf(“指针+%d”:%10p %10p,i,pi+i,pj+i);
}
return 0;
}
此时得到的结果是:
指针+0: 0x7fff5fbff8dc 0x7fff5fbff8a0
指针+1: 0x7fff5fbff8e0 0x7fff5fbff8a8
指针+2: 0x7fff5fbff8e4 0x7fff5fbff8b0
指针+3: 0x7fff5fbff8e8 0x7fff5fbff8b8
…
输出地址的第一列是int类型指针,第二列为double类型的地址,我满可以清楚地看到,当相应的数组+1的时候,实际上在内存之中它相当于加上了一个当前指针类型的字节数,这也就是为什么指针必须和相同类型的变量才能够匹配,如果不匹配,当这个数组变量+1时,加的就不是相应的字节数,就会发生未知的错误。
小结:
1、 指针的值是他所指向对象的地址,通常来说是指这个对象第一个字节的地址
2、 在指针之前加上*号可以得到该指正所指向对象的值;
3、 指针+1,指针的值递增它所对应的类型的大小,通常是字节为单位
好了,下面我们看指针的灵活使用:
定义指针变量 dates
dates+2== &date[2];
*(dates+2)== date[2];
可以轻易的看出,数组和指针之间关系十分的密切,但是也要注意下面的问题
“*”“+”两者之间的关系,=这两个操作符之间,”*”是比”+”的优先级要高的,所以请注意
*(dates+2),这代表dates的第三个值;
*dates+2,这代表dates的第一个值+1;
3、函数、数组与指针
我们之前也说过数组是指针的一种引用方式,那么我们再设计函数的时候,也能通过引用指针的方式去代替数组,呢么我们就说他们之间的关系。
定义一个int类型的数组 array[],现在我们设计一个函数sum,
那么我们引用数组去计算的时候就可能出现以下的情况,
intnumber=sum(array);
那么在这个函数sum里面我们获取的是这个数组的什么呢?
其实获取的就是array的首地址,所以这个引用的函数原型是
int sum(int *p);
那么在这个函数获取到这个数组的首地址之后,要如何进行对数字的提取呢?
int sum(int * p){
Int I;
Int total=0;
for(i=0;i<10;i++){
total+=p[i];
}
return total;
}
当然,这是固定数组长度的做法,我们平时是不提倡这样做的,在这个函数体里面我们可以清楚地看到数组参数和指针参数其实是一回事,呢我们应该如何使用这样的情况呢?
int sum(int * p,int n){
Int I;
Int total=0;
for(i=0;i<n;i++){
total+=p[i];
}
return total;
}
应该吧数组的长度通过另外一个参数去调用,这样不会固定数组长度,更加灵活多变,方便使用。
通过下面的例子再次说数组与指针相等(下列情况都是等价的)
int sum(int *p,int n);
int sum(int *,int );
int sum(int arrat[],int n);
int sum(int [],int );
但是,在函数定义中不能省略参数名。
另外一种方式就是讲该数组的初始指针和终点指针一起传过去,但我个人觉得没有什么道理(或者不常使用)。
指针的基本操作:
赋值:把地址赋给指针
解引用:很抽象,就是指针之前加* 号引用他所存储的值
取值:和一般的变量一样,指针也有自己的地址和值,对指针而言&运算符给出本身的地址
指针与整数相加:使用运算符+号与整数相加,结构都会指向这个整数的值和指针类型所代表的字节数的乘积加上原有地址的地址上去
递增指针:指的是指针元素++,代表指向给数组下一个值的地址
指针减去一个整数:指的是指向现有地址数减去整数与类型所代表字节的乘积
递减指针:指现有数组指向前一个元素,但是此时该指针不应该是第一个元素
指针求差:两个指针求差,意味着求出这二者之间的距离,要记得编译器能够了解你这种操作的意图,所以他会自动转换为都少个类型的的距离而不是字节,这点很重要
了解到指针的操作之后我们提一点需要注意的事项
不要去解引用一个未初始化的指针
例如:int*pt;
*pt=5;
此时,要将5存储到这个指针pt所指向的地址,但是这时该指针并没有初始化,里面的地址是一个随机的值,这就会非常的危险,你不知道他到底在什么位置,,但也可能会擦出数据或者代码,造成程序崩溃,这一点要牢牢记住。
在之前的数组织中我们曾提到const关键字,用来保护文件不被错的修改,我们在函数额定义之中,就可以使用这样的方式去预防这个问题
例如我们的函数需求里面没有要求对所传数组进行修改,所以我们的程序可以这样写:
int sum(const int array[],int n){
}
int sum(const int *p,int n){
}
这样的操作,就可以实现更加安全的函数。
4.指针与多维数组
指针的具体应用包含在数组中,我们通过一个分析来说明这个结论
Intarray[100][100];
这是一个整形的二维数组,数组名代表的这个数组的第一个地址,它是一种怎样的结构呢?是一个内含两个int值得数组,我们具体来分析:
因为array是这个数组首元素的地址,所以array的值和&array[0]相等,而array[0]本是一个内含两个整数的数组,因为array[0]的值和&array[0][0]相等,array[0]是一个int 类型,array[0][0]又是一个int值,所以说有两个int的值
给指正+1,由上述可知array+1是加两个int的距离,array[]+1是加一个int的距离。
那么我们该如何定义指向一个二维数组的指针呢?
我们说过二维数组的首地址为两个定义类型的值,那么我们用之前的例子来说说明,二维int类型的数组的指针定义方法如下:
int array[100][100];
int (*P)[2];
p=array;
在引用的时候我们虽然指针p没有二维,但是我们可以用二维数组的表示方法来表示指针的指向:
int p[0]和int p[0][0]都表示第一个值。
以此类推,我们在建立多维数组的指针时就可以按照这样的方法去表示。
5. 指针的兼容问题
指针的类型是固定的,因为我们在使用指针的时候每次+1的时候地址所增加的值是不同,所以我们不能效仿变量转换去随意的转换他,这一点是要特别注意的。
数组的大概就是这么多,可能有有些东西我说的不是很明白或者说确切,所以后面我会勤加练习,多多试验,验证我的想法和原理,希望大家去看一本书,就是《C primer plus》本次内容也大部分来自这本书的内容加上我的理解,希望大家能够去参照这本书,多理解,多练习。
下面一个部分我会说一说有关字符串的问题,希望大家可以继续阅读。