1.内存和地址
1.1内存
计算机中常见的单位:bit - 比特、byte - 字节、KB、MB、GB、TB、PB
1byte=8bit、1KB=1024byte、1MB=1024KB、1GB=1024MB……
在内存空间中,为了提高对内存的高效管理,我们将内存划分为一个一个的内存单元,每个内存单元的大小为1字节。
为了容易理解,我们可以把内存单元比作一个宿舍,一个内存空间里有8个比特位,相当于一个宿舍里有8个人,一个人就是一个比特位。每个宿舍都有一个特定的门牌号,又称为地址,因此我们将计算机内存单元的编号也称为地址,而在C语言中我们将地址又称为指针。因此,内存单元的编号==地址==指针
对32位的机器我们可以理解为它有32根地址总线,每根线有两种状态,表示0,1,因此一根线有2种含义,故32位的机器就相当于有2^32中含义,一种含义相当于一个地址,因此32位的机器有2^32个地址。
1.2指针及指针的应用
为了获得每个变量的地址,我们就需要用到&-取地址操作符,而用到的地址我们需要存放到指针变量中。
#include<stdio.h>
int main()
{
int a = 10;
int* pa = &a; //取出a的地址,并将其存放在指针变量pa中
return 0;
}
在以上代码中,pa左边的int*中,*是在说明该变量是一个指针变量,而int是在说明pa指向的是一个整型的数据。(pa左侧的int不是固定的,pa指向什么类型的数据就写什么类型,如果pa指向的是一个char类型的数据,我们就要创建成char* pa)
为了使用地址,我们就要用到解引用操作符(*)。
#include<stdio.h>
int main()
{
int a = 10;
int* pa = &a;
printf("%d\n",a); //在这里输出的是10
*pa = 0;
printf("%d\n",a); //在这里输出的是0
printf("%d\n",*pa);//这里输出的也是0
}
根据上面的代码我们可以得出*pa==a,pa里面存放的是a的地址,*pa的意思就是通过pa中存放的地址找到指向的空间,*pa=0就相当于a=0。
1.2.1指针变量的大小
前面我们知道在32位机器中有32根地址总线,每根地址总线只能传输0或1,因此32根地址总线所产生的32位的二进制序列就是一个地址,因此在32位机器中,一个地址的大小是32个比特位,相当于4个字节。
而在64位机器中,就有64根地址总线,相当于一个地址由64位的二进制序列构成,一个地址的大小是64个比特位,相当于8个字节。
注:指针变量的大小与类型是无关的,在相同的平台下,无论指针变量的是什么类型,大小都是相同的。我们可以通过下面的代码进行验证:
#include<stdio.h>
int main()
{
printf("%zd\n",int*);
printf("%zd\n",short*);
printf("%zd\n",char*);
printf("%zd\n",double*); //要在不同的环境下运行
return 0;
} //在X86下都是4
//在X64下都是8
1.2.2指针变量类型的意义
int main()
{
int n = 0x11223344;
int* pa = &n;
*pa = 0;
return 0;
}
当把0x11223344存入n中时,变量n的地址如图:
而当执行*pa=0时变成了如图:
我们可以看出该代码int为4个字节,因此会将4个字节的内容全部改变。
int main()
{
char n = 0x11223344;
char* pa = &n;
*pa = 0;
return 0;
}
而将int改为char后,他只改1个字节赋值
因此当执行*pa=0时,也只将n的第一个字节变为0,如图:
通过以上讲解,我们可以得出结论:指针类型决定了对指针解引用时权限的大小(一次能够操作几个字节)。
1.2.3指针+-整数
我们可以先观察一段代码
#include<stdio.h>
int main()
{
int n = 10;
char* pa = (char*)&n; //强制类型转换
int* pi = &n;
printf("%p\n", &n);
printf("%p\n", pa);
printf("%p\n", pa+1);
printf("%p\n", pi);
printf("%p\n", pi+1);
return 0;
}
运行结果如下图所示
通过观察我们可以看出,当指针类型是char*时指针变量+1跳过了1个字节,而当指针类型是int*时指针变量+1跳过了4个字节,因此我们可以得出结论:指针类型决定指针向前或向后走一步有多大(距离)。