地址(Adress)
1.地址的作用
系统用来查找数据位置的依据,标识存储单元空间。
2.地址的表示
i>地址是一个整数值,(十六进制表示)每8bit一个址。
ii>编址。
1>按字节编址:每一个字节都有一个唯一的地址。
2>按字编址:双字=四个字节。
3.变量地址的表示
&+变量名
& 运算符
1> 单目运算符,结合性由右向左,优先级同 ! 、- 、~ 、前缀++、- -、* 、sizeof,可完整的表示变量的地址。
2>程序的每一个变量都有唯一的可标识的地址。
变量地址
1>按字节编址:一个变量单元占几个字节就占几个地址编号。
2>变量地址是变量第一个地址。
变量地址(决定第一个字节)+变量类型 可完整表示空间。
4.变量地址的分配
5.地址的计算
1>计算过程
&变量名+(-)整数*sizeof(变量名)
2>*地址值:可表示一个单元的地址,但必须在表达式中体现改地址所对应的单元类型。
3>系统内真实计算
“ 段页式寻址 ”:段地址+段的偏移量+段内页地址+页的偏移量+页内偏移量。
指针
一级指针
一级指针:所有普通变量的第一个字节的地址都是一级指针,存放“一级指针“的变量为一级指针变量。
普通变量:凡是定义中没有 * 的都为普通变量。如:char a,int b。
一级指针类型
(1)类型结构:普通变量的类型+‘*’;
如: char a=‘a’;
char *p=&a; &a的类型为char * ,放&a的变量为 char * ,两边的类型不一样需强制转换。
(2)理解char *
char :指针指向空间的解释方式。
*:它是一个指针。
(3)a/&a/p/*p/&p的含义。
char a=‘a’;
char *p=&a;
a:char型普通变量。
&a:a的指针,类型为char *.
p:char *指针变量。用来char *的存放。
*p:p中指针所指向的空间。p为char *,p解引时抵消一个‘’;
&p:变量p的指针,类型为char **。
#include<stdio.h>
int main(void)
{
char a='a';
char *p=&a;
printf("a=%c &a=%d *p=%c &p=%d p=%d",a,&a,*p,&p,p);
printf("\n");
}
结果区:
a=a &a=7011711 *p=a &p=7011696 p=7011711
多级指针之二级指针
对级指针:指针变量也是变量,所以指针变量的每个字节是有地址的,那么“指针变量”第一个字节的地址就是多级指针。指针变量的指针就是多级指针。在多级指针中*的个数代表指针的级数。
二级指针:一级变量指针的指针为二级指针,存放二级指针的变量为二级指针变量。
(1)类型结构:一级指针类型+ *;
如:int a=100;
int *p1=&a;
int **p=&p1;
(32位系统中)
&p1:其类型为 int **,放&p1的变量p2自然 也是int **;
int **:int *:指针指向空间的解释方式。
*:指针。
(2)a/p1/*p1/&p1/p2/*p2/**p2/&p2各自的含义。
int a=100;
int *p1=&a;
int **p2=&p1;
a:int 型变量。
p1:int *指针变量,用于存放int *的指针。
*p1:p1中指针所指向的空间。
&p1:一级指针变量p1的指针为int **的二级指针。
p2:int **指针变量,用来存放int **的二级指针。
p2:一级解引用,代表的是p2指针中所指向的空间。
**p2:二级解引用,代表p2所指向的p1所指向的空间,就是a的空间。
**p2------>(*p2)------->*p1----------->a;
&p2:二级指针p2的指针,类型为int **.
#include<stdio.h>
int main(void)
{
int a=100;
int *p1=&a;
int **p2=&p1;
printf("a=%d\tp1=%d\t*p1=%d\t&p1=%d\n*p2=%d\t**p2=%d\t&p2=%d",a,p1,*p1,&p1,*p2,**p2,&p2);
}
结果如下:
a=100 p1=7011708 *p1=100 &p1=7011696
*p2=7011708 **p2=100 &p2=7011688
野指针
概念::指向内存被释放的内存或者没有访问权限的内存的指针(非法访问)。野指针指向一个不确定的地址空间,或者指向的是一个确定的地址空间的,但引用空间的结果却是不可预知的。
与空指针不同,野指针无法通过简单地判断是否为 NULL避免,而只能通过养成良好的编程习惯来尽力减少。对野指针进行操作很容易造成程序错误。
造成原因:
1、指针定义时未被初始化:指针在被定义的时候,如果程序不对其进行初始化的话,它会指向随机区域,因为任何指针变量(除了static修饰的指针变量)在被定义的时候是不会被置空的,它的默认值是随机的。
2、指针被释放时没有被置空:我们在用malloc开辟内存空间时,要检查返回值是否为空,如果为空,则开辟失败;如果不为空,则指针指向的是开辟的内存空间的首地址。指针指向的内存空间在用free()或者delete(注意delete只是一个操作符,而free()是一个函数)释放后,如果程序员没有对其置空或者其他的赋值操作,就会使其成为一个野指针。
3、指针操作超越变量作用域:不要返回指向栈内存的指针或引用,因为栈内存在函数结束的时候会被释放
如
#include <stdio.h>
//这就是一种错误的写法
int main(void)
{
int *p = NULL;
p = (int *)malloc(4);
//释放P所指向的内存空间,但指针变量p仍然留在栈中,成为了野指针
if (p != NULL)
{
free(p);
}
if (p != NULL)
{
free(p);
}
}
正确的写法:
#include <stdio.h>
//指针变量和指针所指向的内存变量是两个不同的概念
//使用动态内存分为三步
//1.定义时,将指针为定义NULL
//2.释放内存时,把指针变量重新赋值或者NULL
//3.释放内存后,把指针变量赋值为NULL
int main()
{
int *p = NULL;
p = (int *)malloc(4);
//这才是正确的写法
if (p != NULL)
{
free(p);//释放P所指向的内存空间,但指针变量p仍然留在栈中,成为了野指针
p = NULL;//释放野指针
}
return 0;
}