目录
1.指针的概念
①:指针就是地址,地址就是指针。
②:指针就是内存的单元编号
③:指针变量是存放地址的变量。
④:指针和指针变量是两个不同的概念
注意:通常会把指针变量简称为指针,实际他们含义不一样
例子:
#include <stdio.h>
int main(void)
{
int *p; // p是变量的名字,而(int *)表示p存放的是int(整型)变量的地址
int i = 3;
p = &i;
/*=======================
1.p保存了i的地址,因此p指向i
2.p不是i,i也不是p,修改p的值不影响i的值,修改i的值也不影响p的值
3.如果一个指针变量指向了某个普通变量,那么
(* 指针变量) 就完全等价于 普通变量
如上的例子: (*p) 等价于 i变量
*/
简图如下:
- 注意点:
1.p和i不是相同的变量,改变p的值2000H,不会改变 i =3 的值,因为他们是不同的变量,同理,改变 i =3 的值也不会改变 p =2000H的值。
2.(*p)等价于 i(语言设计的结果),这句话解释的实质是:就是以p内容为地址的变量
2.地址的概念
假设我们的内存有4个G,那么总共有多少个字节呢?
内存单位换算:
1K = 1024B
1M =1024*1024 B
1G = 1024*1024*1024 B
4G = 1024 *1024 *1024 *4 =4294967296 B =0xFFFFFFFF B
3.一个指针变量占用的内存空间
注意:这个也是根据系统而异,比如64位的编译系统,指针变量可能占用8个字节。
在计算机的内存中,每个字节(B)作为一个单元,也就是最小单元, 1B = 8bit(一个字节能存储8位二进制的数据)
一个指针变量到底占用几个字节的内存空间?
预备知识
使用函数:sizeof(数据类型)
功能:返回值就是该数据类型所占的字节数。
例子:
sizeof(int) =4 sizeof(char) =1 sizeof(double) =8
sizeof(变量名)
功能:返回值是该变量所占的字节数。
假设p指向char类型变量(一个字节),q指向int类型变量(4个字节),r指向double类型变量(8个字节)
请问:p q r本身所占的字节数是否有区别?
结论:一个指针变量,无论它指向的变量占几个字节,该指针变量本身只占四个字节,一个变量的 地址是用该变量首字节的地址来表示。
值得注意的是,在硬件中每个地址都有一个编号,而且都是一个字节一个编号的。
为什么一个变量的地址用首字节表示,那为什么指针变量需要使用四个字节?
举例:
房子的大小和房子的编号是没有关系的,就像是变量的大小和变量地址所占内容大小是没有关系的,因为一个变量的地址仅仅用首地址来表示。
- 如果现在我的房子只有100间的话,那么我的房间编号用8个位(一个字节)表示就够咯,如上(0-255)。无论在哪个位置我都可以用一个字节来表示你的位置。
- 但是如果你的房间有2的32次方(等于4G的空间)那么大,你的一个字节还够表示吗?一个字节最大只能表示255啊,后面的房间编号就表示不了了,所以此时你需要的房间编号数量应该大于或者等于房间的数量吧,那么就应该就是2的32次方个编号咯,转换成字节就是4个字节。所以用四个字节表示地址,最大的内存是4G,就是这个道理!
注意:通过上面知道,无论表示哪一个房间号都应该用四个字节的地址,即使表示的是第一个,例如第1个表示的地址为:0x0001,第16个:0x000F。
小结:
1.所有变量都存放在内存中(包括普通变量 char ,int 和指针变量)
2.所有的变量都可以保存某些值
3.指针的使用: 1.取值 2. 移动指针
4.指针的例子
例子:
现在编写一段程序如下:
#include "stdio.h"
#include "stdlib.h"
void test(void)
{
char c;
char *pc;
printf("c的地址是: %p\n",&c);
printf("pc的地址是:%p\n",&pc);
c = 'A';
pc = &c;
printf("c的值是 :%c\n", c);
printf("pc的值是:%p\n", pc);
}
int main()
{
printf("sizeof(char )=%d\n", sizeof(char ));
printf("sizeof(int )=%d\n", sizeof(int ));
printf("sizeof(char *)=%d\n", sizeof(char *));
printf("sizeof(char **)=%d\n", sizeof(char **));
printf("==========================\n");
test();
system("pause");
return 0;
}
程序解析:
1.首先程序会打印出,char和int在变量在系统所占的字节数,然后打印(char *) 类型的指针变量和( char **)双重指针变量所占的字节数,发现char占用一个字节,int 占用四个字节,(char * )和(char ** ) 都是占用四个字节。
注意:这是根据编译的系统而不同的,一般子啊32位的编译系统中是这个结果。
2.然后执行test程序,程序做的很简单,首先打印两个地址的值,可以发现地址的值都是32位的,然后对变量c进行赋值,对变量pc也进行赋值,运行结果大体如下,使用简图表示:
解析:从运行结果看出,c变量只占用一个字节,而pc是char类型的指针变量,现在把A的值给了c,那么A的值就存放于0x007EF95B地址中,接着把变量c的地址存放于pc中,由于系统默认的是小端模式,因此存储的结果如上图。
3.使用 *pc 可以取pc地址开始的值,那么访问多少个字节呢?
因为在定义中有 char * pc; 因此通过pc只能访问从pc地址开始的sizeof(char)个类型的数据,也就是一个。
例子2:
程序如下:
#include "stdio.h"
#include "stdlib.h"
void test02(void)
{
int ia;
int *pi;
char *pc;
//所有的变量都保存于内存之中,打印内存地址
printf("ia的地址是: %p\n", &ia);
printf("pi的地址是: %p\n", &pi);
printf("pc的地址是: %p\n", &pc);
//对变量进行赋值操作,并打印变量的值
ia = 0x12345678;
pi = &ia;
pc = (char *)&ia;
printf("ia的值是: 0X%x\n", ia);
printf("pi的值是: %p\n", pi);
printf("pc的值是: %p\n", pc);
//通过 pi 和 pc来取值,并移动指针
printf("*pi=0x%x\n",*pi);
printf("pc的值是: %p\t", pc); printf("*pc=0x%x\n", *pc); pc++;
printf("pc的值是: %p\t", pc); printf("*pc=0x%x\n", *pc); pc++;
printf("pc的值是: %p\t", pc); printf("*pc=0x%x\n", *pc); pc++;
printf("pc的值是: %p\t", pc); printf("*pc=0x%x\n", *pc);
printf("==========================\n");
}
int main()
{
printf("sizeof(char )=%d\n", sizeof(char ));
printf("sizeof(int )=%d\n", sizeof(int ));
printf("sizeof(char *)=%d\n", sizeof(char *));
printf("sizeof(char **)=%d\n", sizeof(char **));
printf("==========================\n");
test02();
system("pause");
return 0;
}
分析:
1.在主程序中调用test02函数,在test02函数中整形变量 ia ,整形指针变量pi, char类型指针变量pc,然后打印这些变量的地址
2.接着对变量进行赋值操作,接着打印这些变量的值
3.通过指针变量来取值和移动char类型的指针
注意:每一次重新运行,这些地址的值都可能发生变化,变量的地址不一定是连续的。
简图如下:
解释:
1.首先定义几个变量,在内存中的存储地址如上图所示。
2.变量ia在内存中占用四个字节,且对ia进行复制,默认采用的小端模式,如上述存储
3.然后把ia的地址保存于pi指针变量中
4.把ia的地址保存于pc指针变量中,所以此时pc和pi都指向了ia。
5.利用pi和pc进行取值操作,(*pi)的意思是:以pi内容为地址的变量的值,pi的内容作为地址,那就是0x00D4F9A4,注意,这只是这个变量的起始地址而且。
6.从这个地址开始取几个字节的内容呢? 这还是得根据前面定义指针变量的设定:如:
pi 是整形变量的指针,所以当使用 *pi 时,取值的内容为以 pi 起始地址开始的sizeof(int)四个字节的地址。
pc 同理可得就是以 pi 起始地址开始的sizeof(char)一个字节的地址。
7.从运行的内容可以看出来,的确是我们设想的那样,而且如果想要把ia整形变量四个字节的值完全取出来,因为通过*pc取值,每一次只能访问一个字节的地址,因此需要移动指针,进行下一个字节的访问。
例子3:数组指针
#include "stdio.h"
#include "stdlib.h"
void test03(void)
{
char a[3] = { 'A','B','C' };
char *pc;
//所有的变量都保存于内存之中,打印内存地址
printf("a数组的首地址是: %p\n", a);
printf("pc的地址是: %p\n", &pc);
//使pc指向这个数组
pc = a;
//打印pc的值
printf("pc的值是: %p\n", pc);
//通过 pi 和 pc来取值,并移动指针
printf("pc的值是: %p\t", pc); printf("*pc=0x%x\n", *pc); pc++;
printf("pc的值是: %p\t", pc); printf("*pc=0x%x\n", *pc); pc++;
printf("pc的值是: %p\t", pc); printf("*pc=0x%x\n", *pc);
printf("==========================\n");
}
int main()
{
printf("sizeof(char )=%d\n", sizeof(char ));
printf("sizeof(int )=%d\n", sizeof(int ));
printf("sizeof(char *)=%d\n", sizeof(char *));
printf("sizeof(char **)=%d\n", sizeof(char **));
printf("==========================\n");
test03();
system("pause");
return 0;
}
简图如下:
解释:
1.pc指向了数组的首地址。
2.使用*pc进行取值是,因为pc是char * 类型的,所以一次读取的是一个字节。