C语言之指针

目录

1.指针的概念

2.地址的概念

 3.一个指针变量占用的内存空间

 4.指针的例子


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 * 类型的,所以一次读取的是一个字节。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值