总结C的指针内容

来源:互联网 发布:ubuntu 查看显卡驱动 编辑:程序博客网 时间:2024/05/16 15:34

前文:

          c语言中的指针,可谓是重中之重,对于初学者来说,这必定是一个大坎,很多意志不坚定的学习者就倒在了这一块。努力学好并用好指针,将会让你的代码变得灵活又富有power!在本文中我将讲解:

1:指针的基本知识与运用。

2:指针的运算。

3:空指针和通用指针

正文:

       首先我们要知道 ,在计算机中,当我们定义任何数据类型的变量时,都会在存储器中申请一个内存空间,在这个内存空间中放的就是我们的数据,计算机为了让我们能够正确的访问这些数据,给每一个内存空间都分配了他们独一无二的地址(类似于我们每个人都有唯一且独特的身份证)。而指针变量就是通过找到数据的地址来访问放在这个地址空间里面的数据,下面我们用代码解释:

  1. int a=10;

   2.int *b=&a;         

   3.*b=100;

   4.int **c=&b;

   5.**c=200; 

 第一句我们定义了一个整形a然后在里面放入了10。那么这个时候我们会申请一个名字叫a大小是4个字节(int是4个字节)的空间,里面放的就是10,当然这个空间肯定会有自己的地址。在计算机中地址是以16进制表示。 

                                                                   这就是第一句代码执行后所产生的内存空间。


第二句就是我们的指针,定义是*后面就是指针变量,因此它也会申请一个空间,只是它里面放的不是数据,而是地址。其中&就是取地址运算符。

因此如果第二句是int *b;b=1000;这句就是错误的,因为1000是数值不是地址。 同样作为内存空间指针变量也会有自己的地址。

                                                                   

第三句中*b=100,其中*叫取内容运算符,也叫解引用,它后面只能跟指针变量。从*的名字看来顾名思义,它的作用就是通过b中存放的地址来访问这个地址空间中的数据,因此*b的值其实就a中所放的数值,然后将100赋给*b,就是改变了a中存放的数值。


从第二句指针变量申请的空间,我们对多级指针的理解也会变的很简单。第四句,我们又申请了一个指针变量c

。并且把b的地址放入了c中,当我们把一个指针变量的地址放入另一个指针变量空间中,那么我们叫c就是高级指针,在这里c就是二级指针。

                                                                

第五句,*c一次解引用它就是通过c中放的b的地址访问了b空间的数据,也就是0x100,是a的地址。**c在前一次接引用的基础上再一次解引用就是通过a的地址访问了a中的数据,这时赋值200,就是该变了a中存放的数值。


看了上面,大家应该对指针有了一个初步了解。接下来就是指针的一些进阶知识难度也会有所上升。

在前面我们定义的都是一个整形指针,int *b ,它前面的int代表这个指针指向的数据类型,显然指针还可以指向char,float,double,数组,结构体,函数。其中 char,float,double和int类似。所以我们下面说明指针指向数组,结构体,函数。


指针指向一维数组:(数组指针)  int arr[10]={1,2,3,4,5,6,7,8,9,10};   int *b=arr;         

首先我们要清楚,在数组定义时在内存中是连续存放的单元,也就是1元素的空间后面紧接着就是2的空间。其次数组名代表的是数组首元素的地址,也就是arr是1这个元素空间的地址。那么我们就很清楚int *b指向的就是arr数组的首元素。 

 

我们在访问数组元素时,可以用到数组下标法,它是从0开始,例如:arr[0]就是1,arr[4]就是5。

那么现在我们如何用指针来访问数组元素呢?这里我们要讲到指针的运算。


首先是指针和整数的运算:  上面的定义。int arr[10],int *b=arr; 

那么b+1代表的是什么,指针和整数的运算,并不是加了数值1也不是加了1个字节,而是加了指针所指向类型的字节数。也就是所谓的权重运算

那么我们就知道其实b+1是把指针b中放的arr首元素地址加了4个字节(因为sizeof(int)是4个字节)。那么加了4个字节的地址对应的空间就是下一个元素的空间,因为我们前面说过,数组是在内存中连续存放的单元。也就是我们要通过指针访问数组元素只需要通过这种方法在解引用就能找到里面的元素。例如:*b=arr[0]=1;*(b+1)=arr[1]=2;*(b+4)=arr[4]=5;(p++,++p其实就是指针和整数的运算)。


指针变量和整数的运算:*b+1代表arr首元素数值+1,也就是arr[0]+1,这时的arr[0]就是变成了2。*(b+3)+5就是数组的第四个元素数值+5,也就是arr[3]+5,这时arr[3]就变成了9.


指针变量和指针变量的运算:int a=10; int b=20 ;  int *p=&a;int *q=&b;   其中*p+*q相当于就是a+b;


指针和指针的运算:指针和指针运算意味它们指向的数组相差的数组元素个数(2个指针指向同一数组才可运算)。

int arr[10];  int *p=&arr[0] ; int *q=&arr[9];  我们定义个一个指针p指向数组首元素空间,q指向数组末元素空间,那么

q-p的值就是8,q-p的值就是-8,为何没说指针和指针的加法运算,因为加法运算是毫无意义的,2个地址相加然后除去他们指向类型字节,得到的结果毫无意义。



指针指向结构体: (结构体指针)

#include<stido.h>typedef struct Student{      char name[20];      int  age;}Student;int main(){     Student b={"wys",10};    //定义了一个Student类型的变量b     Student *p=&b;               //定义一个Student类型的指针p指向了b的空间     printf("%s,%d",b.name,b.age);  //正常访问结构体成员     printf("%s,%d",p->name,p->age);  //通过指针去访问结构体成员 ->是指针操作符      return 0;}
其中的指针操作符其实做了2步,一步就是先解引用到结构体,然后在用点操作符访问成员。  


指针指向函数:(又称函数指针)

#include<stdio.h>int Max(int a,int b){     return a>b?a:b; } int main(){     int (*p)(int ,int); //从优先级开始看,我们知道这是一个指针指向的是一个形参为2个int返回值为int的函数
     p=Max;   //这个时候我们把Max函数接口放入指针中     int a=10;      int b=20;     printf("Max=%d",p(a,b));  //这时我们可以通过函数指针来直接调用函数     return 0}

指针指向字符串:int *p;p="hello world".它也可以写成int *p="hello world" 但是在这里大家要注意一点,就是此时p中的放不是字符串hello world  而是字符串首元素的地址,也就是放的是&h。它在访问时和运算时和数组是一样的。


指针数组(多维数组):int *p[3],首先指针数组它是一个数组只是它比较特殊里面的放的不是数值而是指针。我们可以用它来指向一个多维数组。

我们知道内存是一条长长的直道,它没有十字路口,所以它没办法放下咱们平时所想的二维甚至三维的数据,其实二维数组是一个特殊的一维数组,只是这个一维数组的每一个元素又是一个数组。

int arr[3][3]={1,2,3,4,5,6,7,8,9};   int *p[3]={arr[0],arr[1],arr[2]}, 这时p就是一个指针数组([]的优先级高于*说明p是个数组,然后里面放的指针) 而在这句中它的三个元素放的就是指向arr二维数组的第一行,第二行,第三行的指针。

那我们就可以通过*p[0]来访问二维数组的第一行第一个元素,*(p[0]+1)访问第一行第二个元素,*(p[1]+2)访问第二行的第三个元素。


指针函数:int *fun(int a,int b) 它是一个函数,但是它的返回值是一个是int * 也就是整形指针。


空指针:我们在C和C++中都把空指针用NULL来表示,其实也可用0来表示,但是有一点区别的是在c语言中我们的NULL 是用(void *)0宏定义。在C++中则直接用0来定义,常用于指针的初始化防止出现野指针(int *p=NULL),以及判断指针是否为空(if(p!=NULL)))


通用指针:我们定义指针,肯定要知道他所指向的数据类型,int * p,char *p,float *p,int (*p)[10],int (*p)(int ,int),整形指针,字符指针,浮点数指针,数组指针,函数指针。

void *p就是我们的通用型指针,顾名思义,他指向的数据类型可以是所有的数据类型。在C语言任何类型指针都可以转成通用指针,通用指针也可以转换为任何类型指针(但是这样是不合理的),但是在C++中通用指针就不能转换成任何类型指针(因为当我们整形指针转成通用指针时,如果这个通用指针再转成一个字符指针时,我们在使用时会出现一些奇怪的错误,因为指向的空间大小不同,自然而然运算,赋值都会出错。)



本章小结
1. 指针是C语言中一个重要的组成部分,使用指针编程有以下优点:
(1)提高程序的编译效率和执行速度。
(2)通过指针可使用主调函数和被调函数之间共享变量或数据结构,便于实现双向数据通讯。
(3)可以实现动态的存储分配。
(4)便于表示各种数据结构,编写高质量的程序。

2. 指针的运算
(1)取地址运算符&:求变量的地址
(2)取内容运算符*:表示指针所指的变量
(3)赋值运算
·把变量地址赋予指针变量
·同类型指针变量相互赋值
·把数组,字符串的首地址赋予指针变量
·把函数入口地址赋予指针变量
(4)加减运算
对指向数组,字符串的指针变量可以进行加减运算,如p+n,p-n,p++,p--等。对指向同一数组的两个指针变量可以相减。对指向其它类型的指针变量作加减运算是无意义的。
(5)关系运算
指向同一数组的两个指针变量之间可以进行大于、小于、 等于比较运算。指针可与0比较,p==0表示p为空指针。

3. 与指针有关的各种说明和意义见下表。
int *p;     p为指向整型量的指针变量
int *p[n];   p为指针数组,由n个指向整型量的指针元素组成。
int (*p)[n];  p为指向整型二维数组的指针变量,二维数组的列数为n
int *p()    p为返回指针值的函数,该指针指向整型量
int (*p)()   p为指向函数的指针,该函数返回整型量
int **p     p为一个指向另一指针的指针变量,该指针指向一个整型量。

4. 有关指针的说明很多是由指针,数组,函数说明组合而成的。
但并不是可以任意组合,例如数组不能由函数组成,即数组元素不能是一个函数;函数也不能返回一个数组或返回另一个函数。例如
int a[5]();就是错误的。

5. 关于括号
在解释组合说明符时, 标识符右边的方括号和圆括号优先于标识符左边的“*”号,而方括号和圆括号以相同的优先级从左到右结合。但可以用圆括号改变约定的结合顺序。

6. 阅读组合说明符的规则是“从里向外”。
从标识符开始,先看它右边有无方括号或园括号,如有则先作出解释,再看左边有无*号。 如果在任何时候遇到了闭括号,则在继续之前必须用相同的规则处理括号内的内容。例如:
int*(*(*a)())[10]
↑ ↑↑↑↑↑↑
7 6 4 2 1 3 5
上面给出了由内向外的阅读顺序,下面来解释它:
(1)标识符a被说明为;
(2)一个指针变量,它指向;
(3)一个函数,它返回;
(4)一个指针,该指针指向;
(5)一个有10个元素的数组,其类型为;
(6)指针型,它指向;
(7)int型数据。
因此a是一个函数指针变量,该函数返回的一个指针值又指向一个指针数组,该指针数组的元素指向整型量。


 

OK,最后引荐了别人的总结(偷了下懒),因为我也是一个学习不到5个月的学生,所以有写错的地方还望指出,谢谢大家。还有指针的知识远不止这些,希望大家认真学习。



原创粉丝点击