C语言_7 指针

7 指针

7.1 概述
7.1.1 内存
内存的含义:

  • 存储器:计算机的组成中,用来存储程序和数据,赋值CPU进行运算处理的重要部分。
  • 内存:内部存储器,暂存程序/数据——掉电丢失 SRAM、DRAM、DDR、DDR2、DDR3。
  • 外存:外部存储器,长时间保存程序/数据——掉电不丢失ROM、ERRROM、FLASH(NAND、NOR)、硬盘、光盘。
    内存是沟通CPU与硬盘的桥梁:
  • 暂存放CPU中的运算数据
  • 暂存于硬盘灯外部存储器交换的数据

7.1.2 物理村吃起和存储地址空间
有关内存的两个概念:物理存储器和存储地址空间。
物理存储器:实际存在的具体存储芯片。

  • 主板上装插的内存条
  • 显示卡上的显示RAM芯片
  • 各种适配卡上的RAM芯片和ROM芯片
    存储地址空间:对存储器编码的范围。我们再软件上常说的内存是指这一层含义。
  • 编码:对每个物理存储单元(一个字节)分配一个号码
  • 寻址:可以根据分配的号码找到相应的存储单元,完成数据的读写

7.1.3 内存地址

  • 将内存抽象成一个很大的一维数字符数组
  • 编码就是对内存的每一个字节分配一个32位或64位的编号(与32位)或者64位处理器相关
  • 这个内存编号我们称之为内存地址
    内存中的每一个数据都会分配相应的地址:
  • char:占一个字节分配一个地址
  • int:占四个字节分配四个地址
  • float、struct、函数、数组等

7.1.4 指针和指针变量

7.2 指针基础知识
7.2.1 指针变量的定义和使用
7.2.2 通过指针间接修改变量的值

#include<stdio.h>
int main01()
{
   
	int a=10;
	//a=100;
	printf("%p\n",&a);//获取a的内存地址
	getchar();
	return 0;
}
int main02()
{
   
	//定义指针变量存储变量地址
	int a=10;
	//指针类型 --> 数据类型*
	int *p;
	p=&a;
	*p=100;//通过指针间接改变变量的值
	printf("%p\n",&a);//a的地址
	printf("%p\n",p);//a的地址 同上
	printf("%p\n",a);//100
	printf("%p\n",*p);//100
	return 0;
}
/*
int *p=&a;//p是一个变量 不是地址 
*p=100;//*p是一个整型
*(int *p)=100;//强制类型转换,把普通变量转成int类型再取*
&是取地址符号 是升维度的
*是取值符号 是降维度的
p如果是一级指针,加一个* 变成变量,
p如果是二级指针,加一个* 变成一级指针,两个* 变量
*/
//指针在内存中占的字节大小
int main03()
{
   
	int a=10;
	int *p=&a;
	//printf("%d\n",sizeof(p));
	printf("%d\n",sizeof(int*));//4 所有地址均是无符号十六进制整型
	
	char ch='a';
	char *p=&ch;
	//printf("%d\n",sizeof(p));
	printf("%d\n",sizeof(char*));//4 
	return 0;
}
int main04()
{
   
	char ch='\a';
	int *p = &ch;
	printf("%p\n",p);
	printf("%p\n",&ch);
	return 0;
}

小端对齐:低位数据存在低位内存地址,高位数据存在高位内存地址;
反之,大端对齐 低位数据存在高位内存地址
在这里插入图片描述
在这里插入图片描述
在定义指针类型 一定要和变量的类型对应上
右边int对应找左边大小为4个,char对应找左边1个,void不是数据类型
所有的指针类型存储的都是内存地址,都是一个无符号十六进制整型数
在32位操作系统下,所有指针类型是4个字节大小
在64位操作系统下,所有指针类型是8个字节大小

7.2.3 指针大小

  • 使用sizeof()测量指针的大小,得到的总是:4或8
  • sizeof()测得是指针变量指向存储地址的大小
  • 在32位平台,所有的指针(地址)都是32位(4字节)
  • 在64位平台,所有的指针(地址)都是64位(8字节)

7.2.4 野指针和空指针
指针变量也是变量,是变量就可以任意赋值,不要越界即可(32位为4字节,64位为8字节),但是,任意数值赋值给指针变量没有意义,因为这样的指针就成了野指针,此指针指向的区域就是未知(操作系统不允许操作此指针指向的内存区域)。所以,野指针不会直接引发错误,操作野指针指向的内存区域才会出问题
野指针:指针变量指向一个未知空间
程序中允许出现野指针,操作系统将0-255作为系统占用不允许访问操作,操作野指针对应的内存空间可能报错
不建议将一个变量的值直接赋值为指针

int a=100;
int *p;
p=a;//把a的值赋值为指针变量p,p为野指针,ok不会有问题,但没有意义
p=0x12345678;//给指针变量p赋值,p为野指针,ok不会有问题,但没有意义
*p=1000//操作野指针指向位置区域,内存出问题,err

但是,野指针和有效指针变量保存的都是数值,为了标志此指针变量没有指向任何变量(空闲可用),C语言中,可以把NULL赋值给此指针,这样就标志此指针为空指针,没有任何指针。

#include<stdio.h>
int main05()
{
   
	int *p=NULL;//空指针是指内存地址编号为0的空间
	*p=100;//操作空指针对应的空间一定会报错
	printf("%d\n",*p);
	//空指针可以用作条件判断
	if(p==NULL)
	{
   }
	return 0;
}

NULL是一个值为0的宏常量:

#define NULL((void*)0)//把0强制类型转换为void *类型

7.2.5 万能指针void*
void * 指针可以指向任意变量的内存空间:

#include<stdio.h>
int main06()
{
   
	int *p=NULL;
	int a=10;
	p=(void *)&a;//指向变量时,最好转换为void*
	//使用指针变量指向的北村时,转换为int *
	*((int *)p)=11;
	printf("a=%d\n",a);

	int a=10;
	//int *p=&a;
	void *p=&a;
	//*p=100;//err,非法间接寻址
	*(int *)p=100;
	printf("%d\n",a);//100
	printf("%d\n",*(int *)p);//100
	
	//printf("万能指针在内存占的字节大小:%d\n",sizeof(void *));//4
	//printf("void在内存占的字节大小:%d\n",sizeof(void));//error,不允许使用不完整类型
	return 0;
}

void无法通过sizeof计算数据类型大小,无法改变值
万能指针可以接收任意类型变量的内存地址
在通过万能指针修改变量的值时 需要找到对应的指针类型

7.2.6 const修饰的指针变量
在编辑程序时,指针作为函数参数,如果不想修改指针对应内存空间的值,需要使用const修饰指针数据类型。
const离谁近就不能修改谁(离*近)
1.const修饰指针类型 const int *p=&a;
可以修改指针变量的值(指针变量的地址) 不可以修改指针指向内存空间的值
2.const修饰指针变量 int *const p=&a;
可以修改指针指向内存空间的值 不可以修改指针变量的值(指针变量的地址)

int a=100;
int b=200;
//指向常量的指针
//修饰*,指针指向内存区域不能修改,指针指向可以变
const int *p1=&a;//等价于int const *p1=&a;
//*p1=111;//err
p1=&b;//ok


//指针常量
//修饰p1,指针指向不能变,指针指向的内存可以修饰
int *const p2=&a;
//p2=&b;//err
p2=222;//ok
#include<stdio.h>
int main07()
{
   
	//常量
	const int a=10;
	//a=100;//err,a的值不能修改
	//指针间接修改常量值
	int *p=&a;
	*p=100;
	printf("%d\n,a);//100,把常量的值替换了(栈区),#denfine在数据区 不能修改
	return 0;
}
int main08()
{
   
	int a=10;
	int b=20;
	const int *p=&a;
	p=&b;
	printf("%d\n",*p);//ok,20 可以修改指针变量的值
	
	//*p=100;
	//printf("%d\n",*p);//error 不可以修改指针指向内存空间的值
	return 0;
}
int main09()
{
   
	int a=10;
	int b=20;
	int * const p=&a;
	p=&b;//err 不可以修改指针变量的值

	*p=100;
	printf("%d\n",a);//100 可以修改指针指向内存空间的值
	return 0;
}
int main10()
{
   
	int a=10;
	int b=20;
	const int *const p=&a;//const修饰指针类型 修饰指针变量
	//p=&b;//err 不可以修改指针变量的值
	//*p=100;//err
	
	int **pp=&p;
	*pp=&b;//*pp 一级指针的值
	printf("%d\n",*p);//20	
	**pp=100;//**pp 变量的值
	printf("%d\n",*p);//100	
	return 0;
}

7.3 指针和数组
7.3.1 数组名
7.3.2 指针操作数组元素
数组名字是数组的首元素地址,但它是一个常量。
数组就是地址加下标的偏移

#include<stdio.h>
int main11()
{
   
	int arr[]={
   12,2,3,4,5,6,7,8,9,10};
	//arr=100;//err,数组名是一个常量 不允许赋值 数组名是元素首地址
	int *p;
	p=arr;
	printf("%p\n",p);
	printf("%p\n",arr);
	printf("%d\n",*p);//12
	
	//p++;
	//printf("%p\n",p);
	//printf("%p\n",arr);//指针类型变量+1 等同于内存地址sizeof(int)

	for(int i=0;i<10;i++)
	{
   
		//printf("%d\n",arr[i]);
		//printf("%d\n",*(arr+i));//arr[i] *取值 &取地址 地址加偏移量再取值
		//printf("%d\n",p[i]);
		//printf("%d\n",*(p+i));
		
		printf("%d\n",*p);
		p++;
		
		//printf("%d\n",*p++);//先算*p后算++
	}
	//printf("%p\n",p);
	//printf("%p\n",arr);//此时p和arr已不同,p以超出数组的指针范围变成野指针

	//两指针相减 得到的结果是两个指针的偏移量(步长)
	//所有的指针类型相减 结果都是int类型
	int strp = p-arr;
	printf("%d\n",step);
	return 0;
}
int main11()
{
   
	//可以通过指针修改数组中的数据
	int arr[]={
   1,2,3,4,5,6,7,8,9,10};
	int *p=arr;//指向数组的指针
	//p是变量 arr是常量
	printf("指针类型大小:%d\n",sizeof(p));//p是一个指针 4个字节大小
	printf("数组类型大小:%d\n",sizeof(arr));//arr一个指针 40个字节大小

	//p[i];
	//*(p+i);
	return 0;
}
void BubbleSort(int arr[])//数组作为函数参数 退化指针类型变量 丢失数组的精度 修改如下
{
   
	printf("%d\n",sizeof(arr));//4
	int len=sizeof(arr)/sizeof(arr[0]);
	printf("%d\n",len);//1 
	for(int i=0;i<len-1;i++)
	{
   
		for(int j=0;j<len-1-i;j++)
		{
   
			if(arr[j]>arr[j+1])
			{
   
				int temp=arr[j];
				arr[j]=arr[j+1];
				arr[j+1]=temp;
			}
		}
	}
}
void BubbleSort(int *arr,int len)
{
   
	for(int i=0;i<len-1;i++)
	{
   
		for(int j=0;j<len-1-i;j++)
		{
   
			if(*(arr+j)>*(arr+j+1))//写法麻烦,写上面数组方式
			{
   
				int temp=*(arr+j);
				*(arr+j)=*(arr+j+1);
				*(arr+j+1)=temp;
			}
		}
	}
}
int main12()
{
   
	int arr[]={
   9,1,5,6,3,8,10,2,7,4};
	BubbleSort(arr,10);
	for(int i=0;i<10;i++)
	{
   
		printf("%d\n",arr[i]);
	}
	return 0;
}

指针类型变量+1 等同于内存地址sizeof(int)
p+1:0xf00–>0xff04
在这里插入图片描述
7.3.3 指针加减运算
(1)加法运算

  • 指针计算不是简单的整数相加
  • 如果是一个int *,+1的结果是增加一个int的大小
  • 如果是一个char *,+1的结果是增加一个char的大小
    (2)减法运算
#include<stdio.h>
//字符串拷贝
void my_strcopy01(char *dest,char *ch)
{
   
	int i=0;
	//while(ch[i]!='\0')
	while(ch[i])
	{
   
		dest[i]=ch[i];
		i++;
	}
	dest[i]=0;
}
void my_strcopy02(char *dest,char *ch)
{
   
	int i=0;
	//while(*(ch+i)!=0)
	while(*(ch+i))
	{
   
		*(dest+i
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值