深度理解C语言------指针

来源:互联网 发布:淘客cms优惠券 编辑:程序博客网 时间:2024/05/17 02:45

在我们学习C语言的过程中,指针是不可或缺的一部分,也可以说是最难的一部分,今天让我们来近距离的去认识它,从此无所畏惧。。。吐舌头吐舌头吐舌头


什么是指针

          在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。

       简单的    我们可以说指针是一个特殊的变量,它用来存放某块内存的地址


代码分析

int main(){ int a = 10;//在内存中开辟一块空间 int *p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。然后将a的地址存放在p变量中,p就是一个之指针变量。 return 0;}


指针的类型
       我们都知道变量有不同的类型,int型、foalt型、char型、double型等等。那么作为指针变量,它同样有自己的类型。
简单来说,只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。为了是存放该类型变量的地址。
代码分析
(1)int*ptr;//类型是int*(2)char*ptr;//类型是char*
(3)short*ptr//类型是short*
(4)float*ptr//类型是float*(5)int**ptr;//类型是int**(6)int(*ptr)[3];//类型是int(*)[3](7)int*(*ptr)[4];//类型是int*(*)[4]
复杂类型
        在我们看书的时候,经常也会出现一些比较复杂的类型,就是命名会出现很多运算符,它们也像普通的表达式一样,有优先级,其优先级和运算优先级一样,其规律大致如下 : 从变量名处起,根据运算符优先级结合,一步一步分析。
     优先级 :  在c语言中"()" "[ ]" "->" "."四个优先级相同,具有最高的优先级,其次是”*“ ”++“ ”--“ ”&“四个相同优先级的运算符。

代码分析
int p;       //这是一个普通的整型变量  
int *p;      //首先从P 处开始,先与*结合,所以说明P 是一个指针。然后再与int 结合,说明指针所指向的内容的类型为int 型.所以P是一个指向整型数据的指针  
int p[3];    //首先从P 处开始,先与[]结合,说明P 是一个数组。然后与int 结合,说明数组里的元素是整型的,所以P 是一个由整型数据组成的数组  
int *p[3];   //首先从P 处开始,先与[]结合,因为其优先级比*高,所以P 是一个数组,然后再与*结合,说明数组里的元素是指针类型,然后再与int 结合,说明指针所指向               的内容的类型是整型的,所以P 是一个由返回整型数据的指针所组成的数组  
int (*p)[3]; //首先从P 处开始,先与*结合,说明P 是一个指针然后再与[]结合(与"()"这步可以忽略,只是为了改变优先级),说明指针所指向的内容是一个数组,然后再                与int 结合,说明数组里的元素是整型的.所以P 是一个指向由整型数据组成的数组的指针  
int **p;     //首先从P 开始,先与*结合,说是P 是一个指针,然后再与*结合,说明指针所指向的元素是指针,然后再与int 结合,说明该指针所指向的元素是整型数据.
 int p(int);  //从P 处起,先与()结合,说明P 是一个函数,然后进入()里分析,说明该函数有一个整型变量的参数,然后再与外面的int 结合,说明函数的返回值是一个整                型数据  
int (*p)(int); //从P 处开始,先与指针结合,说明P 是一个指针,然后与()结合,说明指针指向的是一个函数,然后再与()里的int 结合,说明函数有一个int 型的参数,                 再与最外层的int 结合,说明函数的返回类型是整型,所以P 是一个指向有一个整型参数且返回类型为整型的函数的指针 
int (*p[int])()//从p 处开始,先与[]结合,说明p 是一个数组,数组里面元素为整型,然后再与*结合,说明此时为指针数组,然后再与最右边的()结合,说明数组的指                  针指向一个函数,这个函数返回值为整型,参数为空。 
int *(*p(int))[3]; //从P 开始,先与()结合,说明P 是一个函数,然后进入()里面,与int 结合,说明函数有一个整型变量参数,然后再与外面的*结合,说明函数返回的                      是一个指针,,然后到最外面一层,先与[]结合,说明返回的指针指向的是一个数组,然后再与*结合,说明数组里的元素是指针,然后再与int 结合,                      说明指针指向的内容是整型数据.所以P 是一个参数为一个整数据且返回一个指向由整型指针变量组成的数组的指针变量的函数.  绕口!  

指针的内存区

我们常说指针的值,或者是指针所指向的内存区或地址。这个值不是一般的数值,它被编译器当作一个地址。指针所指向的内存区就是从指针的值所代表的那个内存地址开始。
所以我们常听到一句话,一个指针的值为X,就相当于该指针指向其首元素的首地址。(PS :首元素可能为四个字节的int型,所以指针指向了其第一个字节)

指针本身的大小

在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以一个指针变量的大小就应该是4个字节。
那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地址。

指针和数组的运算

       数组变量和指针变量两者有着很大的相似性,但记住一句话——数组和指针没有关系。
下面我们来用sizeof()来简单分析一下
代码分析
char arr[] = {'a','b','c','d','e','f'};printf("%d\n", sizeof(arr));      //值为6,此时arr代表整个数组printf("%d\n", sizeof(arr+0));    //值为4,代表首元素的首地址printf("%d\n", sizeof(*arr));     //值为1,首元素printf("%d\n", sizeof(arr[1]));   //值为1,第二个元素printf("%d\n", sizeof(&arr));     //值为4,数组的地址,是一个指针printf("%d\n", sizeof(&arr+1));   //值为4,下一个数组的地址printf("%d\n", sizeof(&arr[0]+1));//值为4,指向第二个元素的地址,也是一个指针
char *p = "abcdef";printf("%d\n", sizeof(p));        //值为4,p为一个指针变量printf("%d\n", sizeof(p+1));      //值为4,指向第二个元素的地址,代表指针printf("%d\n", sizeof(*p));       //值为1,指针的解引用,代表第一个元素printf("%d\n", sizeof(p[0]));     //值为1,同上printf("%d\n", sizeof(&p));       //值为4,p的地址同样是一个指针变量printf("%d\n", sizeof(&p+1));     //值为4,下一个指针printf("%d\n", sizeof(&p[0]+1));  //值为4,指向第二个元素的地址,也是一个指针

小结几点:
a.数组名代表整个数组只有以下两种情况:1.&数组名      2.sizeof(数组名)
b.指针加一,看似加一,实质加其指向元素的类型大小。
c.指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
   PS:char*的指针解引用就只能访问一个字节,而int*的指针的解引用就能访问四个字节。
d.指向数组内的两个指针相减,其值等于俩指针之间的数组元素个数。

取地址& 和 解引用*

&是取地址运算符,*是间接运算符。
       & a 的运算结果是一个指针,指针的类型是a 的类型加个*,指针所指向的类型是a 的类型,指针所指向的地址为a 的地址。
       *p 的运算结果就是p 所指向的内容。 可能为数值,字符串,数组,甚至是指针。

上面了解了数组与指针,这里谈一下 函数与指针的关系

函数和指针的关系

函数指针就是指向代码入口地址的指针,是指向函数的指针变量。 因而“函数指针”本身首先应该是指针变量,只不过该指针变量指向函数。因为每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调用函数,所以我们经常见函数指针作为参数在另一个函数里面 (回调函数)。
代码分析

#define _CRT_SECURE_NO_WARNINGS 1#include<Windows.h>#include<stdio.h>#include<assert.h>int function(int x, int y){ int ret = 0;  ret=x>y ? x : y;  printf("这是一个函数指针调用的函数\n\n");  printf("最大值为%d\n", ret);  return ret;}int main(){ int a = 3; int b = 8; int(*p) (a, b) = function; /* 声明一个函数指针,把函数赋值给p */ p(3,8); system("pause"); return 0;}

得出结论:

函数指针在调用函数的时候既可以解引用指针,也可以直接使用指针的名称。


说完指针和数组、函数,下面我们谈指针和结构体

指针和结构体的关系

定义 : 指向结构体变量的指针
①一个指针变量用来指向一个结构体变量时,称之为结构体指针变量。结构指针变量中的值是所指向的结构变量的首地址。通过结构指针即可访问该结构变量,这与数组指针和函数指针的情况是相同的。

举个栗子:
#define _CRT_SECURE_NO_WARNINGS 1#include<Windows.h>#include<stdio.h>#include<assert.h>struct weapon{char name[20];int k;int o;int m;int a;};int main(){struct weapon lcc = { "Koma", 5,2,4,2 };//结构体的初始化,这里注意koma!struct weapon * p;// w是指向struct weapon 类型的指针p = &lcc;// w 指向weapon_1printf("这是一个结构体指针p\n");printf("%s\n%s\n", (*p).name, p->name);//两种方式等价,括号不能省,因为.的优先级比()的优先级高system("pause");return 0;}
运行结果


上面大概就是我在C语言的学习当中对指针的一些见解,如有不对,还望大佬们指出来,加以改正。

Ending...




原创粉丝点击