指针笔记(参看郝斌老师课程)

本文详细介绍了指针的概念、重要性及其在C语言中的应用,包括指针变量、指针运算符、指针与数组的关系等内容。同时,还探讨了动态内存分配的方法,对比了静态内存与动态内存的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

指针_1

一、指针的基本概念

​ 计算机内存以字节为最小单位进行编址的。

​ 1、地址就是内存单元的编号。

​ 2、指针就是地址,地址就是指针。

​ 3、指针变量是存放地址(也就是指针)的变量。指针和指针变量是两个不同的概念。

​ 4、但是要注意,通常我们叙述时会把指针变量简称为指针,实际他们含义并不一样。

int i;
int *p;	//p是变量的名字,p变量的数据类型是int*。int * 表示p变量存放的是int型变量的地址。
p = &i;	//ok
	/*
		1、p保存了i的首地址,因此p指向i。
		2、p不是i,i也不是p。修改i的值不影响p的值,修改p的值也不影响i的值。
		3、如果一个指针变量指向一个普通变量(即指针变量存放普通变量的地址),则
			*指针变量	就完全等同于		普通变量
		4、*p就是以p的内容为地址,空间存储的变量
	
	*/
p = i;	//error,因为类型不一致,p只能存放int类型变量的地址,不能存放int类型的值。

指针_1.0.1

二、指针的重要性

​ 1、表示一些复杂的数据结构

​ 2、快速传递数据

​ 3、使函数返回一个以上的数据

void f(int *pa, int *pb)
{
    *pa = 1;
    *pb = 2;		//被调函数修改主调函数的值----指针可以做到,其他做不到
}

int main(void)
{
    int a = 6, b= 8;
    f(&a, &b);
}

​ 4、能够直接访问硬件

​ 5、能够方便的处理字符串

​ 6、是理解面向对象语言种引用的基础

三、指针的定义

地址:

​ 内存单元的编号

​ 从零开始的非负正数

​ 范围:32位的最大访问空间是4G.

内存大小

指针:

​ 1、指针的本质就是一个操作受限的非负整数(指针可以相减,不能进行相加,相乘,相除运算)

​ 2、指针存放的是地址,地址是一个4字节大小(32位机器)的非负整数。不管数据类型有多大,指针只保留这个数据起始第一个字节的地址(数据类型决定每个数据在内存中所占字节的大小),所以任何类型的指针都是4字节大小。

image-20211103204040628

四、指针的分类

1、基本类型指针

​ 指针的常见错误

1.1、野指针
int main(void)
{
    int *p;		//局部变量不初始化,存放的是垃圾值
    int i = 5;
    
    *p = i;		//把i的值赋值给一个以垃圾值为地址的内存里。在这个程序里系统只分配了2个数的操作空					间(p,i),但在程序运行过程中操作了分配空间以外的空间。
    printf("%d\n", *p);
    
    return 0;
}
int main(void)
{
    int i = 5;
    int *p, *q;
    
    p = &i;
    *q = p;		//q为int*类型,则*q为int类型,p为int*类型,类型不一致不能进行赋值,出现语法错误
    
    return 0;
}
/*
	q的空间是属于本程序的,所以本程序可以读写q的内容,但如果q内部是垃圾值,则本程序不能读写*q的内容(也就是以q内容为地址的空间里的内容),因为此时*q代表的内存单元的控制权限并没有分配给本程序。
*/
int main(void)
{
    int i = 5;
    int *p, *q;
    
    p = &i;
    p = q;
    
    printf("%d\n", *p);		//error:因为q本身系统分配空间(但p的值是q局部变量里的垃圾值),								但*p是一个垃圾值地址内的内容(超出系统分配的空间)。
    printf("%d\n", *q);		//error:操作q本身没有问题,但操作*p就越界了。
    
    return 0;
}
1.2、基本类型指针的使用

​ 互换2个数

/*
函数之间,实参和形参之间的传递都是数据的拷贝,指针传递的是地址的拷贝,被调函数通过地址直接修改主调函数的值,被调函数释放后对主调函数的影响依然在。
*/

#include <stdio.h>

void Huhuan(int *pa, int *pb)
{
	int c;

	c = *pa;
	*pa = *pb;
	*pb = c;
}

int main(void)
{
	int a = 3;
	int b = 4;

	printf("*pa = %d, *pb = %d\n", a, b);

	printf("///////////////////////\n");
	Huhuan(&a, &b);
	printf("*pa = %d, *pb = %d\n", a, b);
	return 0;
}
1.3、*号的含义
1、乘法

2、定义指针变量	
    int *p;	定义了一个名字是p的变量,int* 表示p只能存放int类型变量的地址。
3、指针运算符
    该运算符放在已经定义好的指针变量的前面;
    如果p是一个已经定义好的指针变量,则*p就是以p内容为地址空间内存放的变量。  
4、除定义指针变量外,变量名前边加*。
    在变量使用过程中,只有指针变量前边可以加*号,普通变量前边坚决不可以加*号。
1.4、如何通过被调函数修改主调函数中普通变量的值
1、实参必须是该普通变量的地址
2、形参必须为该类型指针变量
3、在被调函数中通过
    *形参名 = ......
    的方式就可以修改主调函数相关变量的值。
2、指针和数组
2.1、指针和一维数组
一维数组名:

​ 一维数组名是一个指针常量,它存放的是一维数组第一个元素的首地址。

//错误
int a[5]; b[3];
a = b;	//error,一维数组名是一个指针常量
#include <stdio.h>

int main(void)
{
    int a[3];
    
    printf("%#X\n", &a[0]);
    printf("%#X\n", a);
}

//运行结果
fuchunjie@FCJ:/mnt/hgfs/VMshare/mySpace/指针互换2数$ ./app 
0XD5E2C42C
0XD5E2C42C
    
//证明:一维数组名是一个指针常量,它存放的是一维数组第一个元素的首地址。
下标和指针的关系
如果p是一个指针变量,则p[i] 永远等价于 *(p+i);
如何确定一个一维数组(确定一个一维数组需要几个参数)
数组名:
数组长度:		
指针变量运算

​ 指针只能相减,不能进行加,乘,除。

​ 如果两个指针变量指向的是同一个连续空间中的不同存储单元,则这两个指针变量才可以相减。不同存储单元指针变量相减没有任何意义。

2.2、指针和二维数组
3、指针和函数
4、指针和结构体
5、多级指针

image-20211103152756031

image-20211103230421587

五、动态内存的分配
5.1、传统数组的缺点

​ 1、数组的长度必须事先指定,并且只能是常整数,不能是变量。

​ 2、传统形式定义的数组,该数组的内存无法手动释放。除非程序终止,由系统释放。

​ 3、数组的长度不能在函数运行过程中动态的扩充和缩小。数组长度一旦定义在运行过程中不能改变。

​ 4、A函数定义的数组,在A函数运行期间可以被其他函数使用,但在A函数运行完毕之后,A函数中的数组将无法被其它函数使用。(静态内存在函数终止之后不能再被使用)

5.2、为什么需要动态分配内存

​ 动态分配内存很好的解决了传统数组(静态内存)的4点缺陷。

5.3、动态内存分配举例,动态数组的构成

​ 1、使用malloc函数分配动态内存空间。并把从系统申请的动态内存的第一个字节地址返回,为了确定所指空间每个数据变量大小(确定变量类型),malloc函数前边必须加强制数据类型。

int *p = (int *)malloc(4);
/*
	1、malloc函数只用一个参数,并且参数值整型
	2、4表示请求系统为本程序分配4个字节空间
	3、malloc函数只能返回第一个字节地址(如何确定这些空间每个变量占几个字节?)由malloc前边的强制类型转换确定。
	4、本行程序分配了8个字节,p本身占4个字节,malloc函数分配4个字节。
	5、p本身是数据类型+变量名形式分配(静态分配内存),p所指向的内存是动态分配的。
*/

image-20211103220608132

5.4、静态内存和动态内存的比较
/*
1、int a[5];	//如果int占4个字节,则该数组总共包含20个字节,每四个字节被当作了一个int变量来使用
2、	int *pArr;
	pArr = (int *)malloc(sizeof(int) * 5);
	pArr变量保存的是malloc返回动态分配空间的首地址,因为是int*类型指针,所以pArr指向了以首地址开始连续4字节空间。pArr+1则指向接下来的4个字节空间,以此类推。
*/

image-20211103223322624

​ 静态内存:

​ 1、静态内存由系统分配,由系统释放。

​ 2、静态内存是在栈中分配的。

​ 动态内存:

​ 1、动态内存是程序员手动分配的,手动释放。

​ 2、动态内存是在堆里分配。

5.5、快函数使用内存的问题

思考:指针最主要的目的是为了跨函数使用指针。

​ 指针运算符*使用分2种情况

​ 1、定义时

​ 类型名 * 变量名;定义了某类型的指针变量。

int *p;			//定义int类型指针变量
int **p;		//定义int*类型指针变量
int ***p;		//定义int**类型指针变量

​ 2、使用时

int ***p;
/*
*p		是int**类型变量
**p		是int*类型变量
***p	是int类型变量
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值