https://blog.youkuaiyun.com/xiaoliu0518/article/details/32707111
一、指针变量、地址、数据、内存关系
在学习指针之前,我们先统一几个概念。
(1)在计算机中本质 用 内存 来存储 数据 ,在我们写代码的时候,用变量来存储数据 。
(2)变量是在编程语言中的概念,方便我们编程,当编译运行起来以后,就只有内存了和数据了。
比如 当 我们写代码
- int a;
- int b;
- a = 1;
- b = a;
第3行,语法层面是 给变量a赋值1,计算机层面是,把数据1写到地址为0x10-0x13的4个字节内存中。
第4行,语法层面是把a的值赋值给b ,计算机层面是,把0x10-0x13的4个字节的内存中存储的数据读出来,写到 0x0c-0x0f的4个字节的内存中。
(3)描述内存只有两个属性:地址,大小,我们可以说我们访问的是从某个地址开始 多少字节的内存。
(4)在代码中我们要得到变量的地址,其实本质是内存的地址,&a;
(5)在我的文章中,指针 是 指针变量的缩写,以后所说指真是说的 指针变量, 指针是指针变量,指针是变量。
(6)在语法层面,我们要存储数据,需要用到变量,比如 int a = 1, 地址也是一种数据,在语法中存储 地址,需要用到 指针变量。
(7)地址这种数据 本质也是 1 2 3 4 5。。。等整数,只不过在我们的语法层面,数据有数据的类型,是地址类型。
二、指针变量基本使用
1、指针变量的定义,及赋值
在C语言中 变量定义的基本模型是
数据类型 变量名;
type name;
我们写如下代码
- int a; //a 的类型是int
- int *p; //p的类型是 int*
- p = &a; //&a得到的数据,类型是int*,在C语言中,在赋值的时候类型要匹配。
p是一个指针变量,它的类型是(int*)。
p是一个指针变量,他存储 地址 这种类型的数据。
&符号是用来计算变量的地址,a是int变量,int变量的地址 类型是 (int*)。
同理,char 变量的地址 类型是(char*),double 变量的地址类型是(double *);
因此可以有如下代码:
- char b;
- char *p1;
- p1 = &b;
- double c;
- double *p2;
- p2 = &c;
解释: p = &a;
变量p 存储了 变量a的地址,也就是所谓 p 指向a ,在我们初学指针的时候,不要说指向这个词,而是把他的概念说全(变量p 存储了 变量a的地址)。
可以看下面内存图,这里验证下 sizeof(p)看p占多少个字节。
2、* 符号作用解释
首先在定义指针变量的时候
type *p; //这里理解 *是形容词,修饰变量p 是个指针变量,那么 *前面的type有什么作用呢?我们在下面慢慢理解。
- int a,b;
- int *p;
- p = &a;
- *p = 1;
- b= *p;
第5行:首先读取p 变量的值,这个值是变量 a的地址,然后通过读取的这个地址 找到a的内存,然后读取这块内存的数据并把它写入到b的内存中。
由此,我们可以理解 在定义的时候,*是个形容词,形容变量是个指针变量,在使用的时候,*是个动词,是通过地址找到内存,并读写。
初学的时候把这个过程说完整。
*前面的type决定了通过p存储的地址读写该内存的方式:要读写一块内存,需要知道内存的地址,大小,和如何把数据换算成二进制放到这块内存中。
比如
(1)----------------------------------------------------------------------------------------------------------------------
int a ;
double b ;
a = 1;
b = 1.1;
当给a赋值的时候,我知道a 的地址,然后知道要写4个字节,还知道这四个字节的数据应该写 1转换成二进制。
当给b赋值的时候,我知道b 的地址,然后知道要写8个字节,还知道这八个字节的数据应该写 1.1按照一定的规则转换成的二进制。
(2)----------------------------------------------------------------------------------------------------------------------
int *p1 ;
char *p2;
假定 p1 p2 的值都是 0x10,也就是p1 p2存储的地址都为 0x10;
*p1 = 1的时候通过p1存储的地址访问0x10 0x11 0x12 0x13 这4个字节,并在这4个字节中了一个(int )1,也就是 二进制 00000000 00000000 00000000 00000001。
*p2 = 1的时候通过p2存储的地址访问0x10这一个字节,并在这一个字节中写了一个(char)1,也就是00000001。
注意以下代码:
- int a;
- int *p = &a;
- *p = 1;
第三行是通过p存储的地址找到一块内存,是在访问a的内存,也就是所谓p指向的内存。
在做*p的时候,一定要注意p 要存储一个合法有效的地址,否则就会访问一块未知内存,出现段错误,这是前期经常犯的错误。
目前要得到一个合法有效的地址 就是对 变量取地址,&a,以后还会接触到malloc.
完整测试代码如下:
- #include <stdio.h>
- int main()
- {
- int a = 0;
- int *p = &a;
- //打印地址用 %p,会以16进制打印。
- printf("p = %p",p);
- printf("&a = %p",&a);
- *p = 1;
- printf("a = %d\n",a);
- printf("*p = %d\n",*p);
- return 0;
- }
- #include <stdio.h>
- //验证指针变量的size
- int main()
- {
- char a;
- int b;
- double c;
- char *p1;
- int *p2;
- double *p3;
- printf("%d\n",sizeof(a));
- printf("%d\n",sizeof(b));
- printf("%d\n",sizeof(c));
- printf("%d\n",sizeof(*p1));
- printf("%d\n",sizeof(*p2));
- printf("%d\n",sizeof(*p3));
- return 0;
- }
3、指针加减法
根据如下代码验证:
指针变量 加上 数字,计算的是位移,跟我们常规的数学计算略有不同。
type *p;
p 存储地址 addr
p+n 计算出来的值 为 addr+n*sizeof(type);
比如:
int *p1;
char *p2;
如果 p1 = 0,p2 = 0;
则 p1+1 计算出的值为 4;
p2+1 计算出的值为 1;
对于 type *p ;来说 ,type决定了指针加减法偏移位移的多少。
以下代码验证。
- #include <stdio.h>
- int main()
- {
- /*
- 指针变量的加减
- 1、type *p;
- 2、指针变量+/-一个数字 计算的是位移
- p = addr;
- p+n = addr+n*sizeof(type);
- */
- int a = 1;
- int *pa = &a;
- char c = 0;
- char *pc = &c;
- printf("pa = %p\n",pa);
- p++;
- printf("pa = %p\n",pa);
- p+=5;
- printf("pa = %p\n",pa);
- printf("pc = %p\n",pc);
- pc++;
- printf("pc = %p\n",pc);
- pc+=5;
- printf("pc = %p\n",pc);
- }