C语言指针是什么?学好了指针就几乎学好了C语言……指针注意事项
在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。
在C语言的学习过程中,指针是相当重要的一部分,学好指针对C语言的学习有很重要的意义。
想学好C语言的伙伴可以私信回复 领取资料 领取C语言学习资料哦!
指针和内存
如果说内存相当于街道,那么地址就相当于位于街道中房子的房号。
一个字节(8bit)包含一个地址。内存中每一个位置都包含一个独一无二的地址标识,而每一个位置都包含一个值。
注意:①区别指针变量的内容(即地址)、指针指向变量的内容、指针的地址。
为什么程序中的数据会有自己的地址?
弄清这个问题我们需要从操作系统的角度去认知内存。
电脑维修师傅眼中的内存是这样的:内存在物理上是由一组DRAM芯片组成的。
而作为一个程序员,我们不需要了解内存的物理结构,操作系统将RAM等硬件和软件结合起来,给程序员提供的一种对内存使用的抽象。,这种抽象机制使得程序使用的是虚拟存储器,而不是直接操作和使用真实存在的物理存储器。所有的虚拟地址形成的集合就是虚拟地址空间。
在程序员眼中的内存应该是下面这样的。
也就是说,内存是一个很大的,线性的字节数组(平坦寻址)。每一个字节都是固定的大小,由8个二进制位组成。最关键的是,每一个字节都有一个唯一的编号,编号从0开始,一直到最后一个字节。如上图中,这是一个256M的内存,他一共有256x1024x1024 = 268435456个字节,那么它的地址范围就是 0 ~268435455 。
由于内存中的每一个字节都有一个唯一的编号,因此,在程序中使用的变量,常量,甚至数函数等数据,当他们被载入到内存中后,都有自己唯一的一个编号,这个编号就是这个数据的地址。指针就是这样形成的。
下面用代码说明
<pre class="ql-align-justify">#include <stdio.h>int main(void)
{
char ch = 'a';
int num = 97;
printf("ch 的地址:%p\n",&ch); //ch 的地址:0028FF47
printf("num的地址:%p\n",&num); //num的地址:0028FF40
return 0;
}</stdio.h> </pre>
指针的值实质是内存单元(即字节)的编号,所以指针 单独从数值上看,也是整数,他们一般用16进制表示。指针的值(虚拟地址值)使用一个机器字的大小来存储,也就是说,对于一个机器字为w位的电脑而言,它的虚拟地址空间是0~2w - 1 ,程序最多能访问2w个字节。这就是为什么xp这种32位系统最大支持4GB内存的原因了。
我们可以大致画出变量ch和num在内存模型中的存储。(假设 char占1个字节,int占4字节)
变量和内存
为了简单起见,这里就用上面例子中的 int num = 97 这个局部变量来分析变量在内存中的存储模型。
已知:num的类型是int,占用了4个字节的内存空间,其值是97,地址是0028FF40。我们从以下几个方面去分析。
1、内存的数据
内存的数据就是变量的值对应的二进制,一切都是二进制。97的二进制是 : 00000000 00000000 00000000 0110000 , 但使用的小端模式存储时,低位数据存放在低地址,所以图中画的时候是倒过来的。
2、内存数据的类型
内存的数据类型决定了这个数据占用的字节数,以及计算机将如何解释这些字节。num的类型是int,因此将被解释为 一个整数。
3、内存数据的名称
内存的名称就是变量名。实质上,内存数据都是以地址来标识的,根本没有内存的名称这个说法,这只是高级语言提供的抽象机制 ,方便我们操作内存数据。而且在C语言中,并不是所有的内存数据都有名称,例如使用malloc申请的堆内存就没有。
4、内存数据的地址
如果一个类型占用的字节数大于1,则其变量的地址就是地址值最小的那个字节的地址。因此num的地址是 0028FF40。 内存的地址用于标识这个内存块。
5、内存数据的生命周期
num是main函数中的局部变量,因此当main函数被启动时,它被分配于栈内存上,当main执行结束时,消亡。
如果一个数据一直占用着他的内存,那么我们就说他是“活着的”,如果他占用的内存被回收了,则这个数据就“消亡了”。C语言中的程序数据会按照他们定义的位置,数据的种类,修饰的关键字等因素,决定他们的生命周期特性。实质上我们程序使用的内存会被逻辑上划分为: 栈区,堆区,静态数据区,方法区。不同的区域的数据有不同的生命周期。
无论以后计算机硬件如何发展,内存容量都是有限的,因此清楚理解程序中每一个程序数据的生命周期是非常重要的。
我会在以后的文章中再对C语言的内存管理做出介绍,敬请期待。
下面说一下C语言关于指针的注意事项
一、指针的四个关键概念
1、指针的类型
2、指针指向的类型
3、指针的值,也就是指针指向的地址
4、指针自己所占用的内存空间
注意:指针变量所存的内容就是内存的地址编号!
例如:
int **pp = NULL;
1、指针的类型是 int **
2、指针指向的类型 int *
3、指针的值为NULL
4、指针自己所站内存的大小 sizeof(pp)
二、强制类型转换
强制类型不会改变内存中二进制的排列与顺序,只会将二进制按照目标类型解释。
例如:
int i = 10;
二进制位 0110;
float f = (float)i;
变量f的二进制还是 0110
三、关于CONST修饰变量
看const修饰变量的时候,完全可以将数据类型名视而不见
例如
int const p; //修饰p , p可以变 , *p不能够变
const int p; //修饰p , p可以变 , *p不能够变
const int * const p; //修饰p和*p , p不可变, *p也不可变
四、关于变量类型
1、数据类型的本质是固定内存空间大小的别名
2、变量的本质是一段连续内存空间起始地址的别名
五、关于变量声明的意义
1、建立变量符号表
通过声明变量,编译器可以建立变量符号表,如此一来,程序中用到了多少变量,每个变量的类型是什么,编译器非常清楚,是否使用了没有声明的变量,编译器在编译期间就可以发现。从而帮助开发人员远离由于疏忽而将变量名写错的情况
2、变量的数据类型指示系统为变量分配多少内存空间
3、变量的数据类型指示了系统如何解释存储空间中的值,同样的数值,不同的类型将有不同的解释。int占据4个字节,float也占据4个字节,在内存中同样是存储的二进制数,并且这个二进制数也没有标志区分当前是int型还是float型。如何区分?就是通过变量的数据类型来区分。由于声明建立了变量符号表,所以系统知道变量该如何解释
4、变量的数据类型确定了该变量的取值范围
例如短整型数据取值-32767~32767之间
5、不同的数据类型有不同的操作
如整数可以求余。C语言用符号”%”表示求余。整数可以,实数不可
六、关于函数调用传递指针的总结
1、如果在被调函数中想修改主调函数中变量的值,则需要将主调函数中的变量的地址(指针)传递到被调函数中
2、如果主调函数要传递一个超大的数据到被调函数中时,也可以将主调函数的变量的地址(指针)传递到被调函数中,这样有利于提高程序的性能
3、传递N级指针是为了修改N-1级指针的值,
例如 : int *p;如果需要修改p的值,则需要将&p传递到函数中,才能修改p的值
七、关于指针与数组互换的问题
在表达式中,指针和数组是可以互换的,因为他们在编译器里面的最终形式都是指针,并且都可以进行取下标操作
八、数组与指针的区别
数组: 一个数组就是一个地址,并且该地址是一个常量值,不能改变。因此,数组名不能作为左值。
指针: 一个指针就是一个地址的地址 , 并且该地址是可以改变的。也就可以作为左值。
九、指针与地址的区别
指针就是地址,但地址并不是指针。指针有类型,地址没有类型。
十、传值与传址的区别
c语言其实只有一种传值方式,就是按值传递
按值、按址传递的区别在于,在函数中使用的方式而已。如果在函数中是要修改地址所指向内存的值,则可以修改实参地址指向的内容。因为在内存中内存地址是唯一的,所以不论在什么地方,都可以通过地址来修改内存中的值
指针变量总结
想学好C语言的伙伴可以私信回复 领取资料 领取C语言学习资料哦!
【C/C++学习、面试;文档、视频资源免费获取】
