跟着郝斌老师复习C语言part7--指针

一、引例

int main(void) {
	int * p;//p是变量的名字,int * 类型表示p变量存放的是 int 类型变量的地址 
	int i=3;
	int j;
//	p=i// error 因为类型不一致,p只能存放 int 类型变量的地址,不能存放int 类型变量的值
// 	p=5;//error 原因同上 
	p=&i;/*
	1.p 保存了 i 的地址,因此 p 指向 i ,
	2.但是p不是i,i也不是p,更准确的说,修改p的值不影响i的值,修改i的值也不影响p的值
	3.如果一个指针变量指向了某个普通变量, 则  *指针变量  就完全等同于  普通变量
	例子:如果p是个指针变量,并且p存放了普通变量i的地址
			则p指向了普通变量
			*p 就完全等同于 i
			或者说:在所有出现 * p的地方都可以替换成 i ,在所有出现 i 的地方都可以替换成 * p
			* p 就是以p的内容为地址的变量
	*/ 
	j=*p;//等价于j=i
	printf("i=%d,j=%d,*p=%d\n",i,j,*p);3,3,3
	return 0;
}
}

指针就是地址,地址就是指针
地址就是内存单元的编号
指针变量是存放地址的变量
指针和指针变量是两个不同的概念
但是要注意:通常我们叙述时会把指针变量简称为指针,实际他们含义并不一样。

二、指针的重要性

  1. 表示一些复杂的数据结构
  2. 快速的传递数据,减少了内存的耗用
  3. 使函数返回一个以上的值
  4. 能直接访问硬件
  5. 能够方便的处理字符串
  6. 是理解面向对象语言中引用的基础
    总结:指针使C语言的灵魂

三、指针的定义

3.1.地址

内存单元的编号
从0开始的非负整数
范围:4G(0——4G-1)

3.2.指针

指针就是地址,地址就是指针
指针变量就是存放内存单元编号的变量,或者说指针变量就是存放地址的变量
指针和指针变量是两个不同的概念
但是要注意:通常我们叙述时会把指针变量简称为指针,实际他们含义并不一样。
指针的本质就是一个操作受限的非负整数(不能乘除)

四、指针的分类

4.1.基本类型指针

指针常见错误
在这里插入图片描述
在这里插入图片描述
经典指针程序——互换两个数字

#include<stdio.h>
void huh(int * p,int * q){
	int t;//如果要互换*p和*q的值,则t必须定义成int,不能定义成int *,否则语法会出错
	t=*p;//p 是int *,*p是int
	*p=*q;
	*q=t;
	return ;
}
int main(void)
{
	int a=3;
	int b=5;	
	huh(&a,&b);
	printf("a=%d,b=%d",a,b);
	return 0;
 } 
  • *的含义:
    1->乘法
    2->定义指针变量
    int *p;//定义了一个名字叫p的变量,int *p表示p只能存放int变量的地址
    3->指针运算符
    该运算符放在已经定义好的指针变量的前面
    如果p是一个已经定义好的指针变量,则 *p表示以p的内容为地址的变量
  • 如何通过被调函数修改主调函数普通变量的值
    1->实参必须为该普通变量的地址
    2->形参必须为指针变量
    3->在被调函数中通过
    在这里插入图片描述

4.2.指针和数组

  1. 指针和一维数组
    1-> 一维数组名:
    一维数组名是个指针常量
    它存放的是一维数组第一个元素的地址
#include<stdio.h>
int main(void){
	int a[5];//a是数组名,5是数组元素的个数,元素就是变量a[0]--a[4] 
	int a[3][4];//3行4列,a[0][0]代表第一个元素,a[i][j]代表第i+1行,j+1列元素 
	int b[5];
//	a=b;//error
	printf("%#X\n",&a[0]);//0X62FE00
	printf("%#X\n",a);//0X62FE00
	
	return 0} 

2->下标和指针的关系
如果p是个指针变量,则p[i]永远等价于 *(p+i)

	int a[5]={0,1,2,3,4};
	printf("%d\n",a[3]);//3
	printf("%d\n",*(a+3));//3

3->确定一个一维数组需要几个参数(如果一个函数要处理一个一维数组,则需要接收该数组的那些信息)
需要两个参数:数组第一个元素的地址,数组的长度

void f(int *pArr,int len){
//	int i;
//	for(i=0;i<len;i++){
//		printf("%d\n",*(pArr+i));//*(pArr+i)等价于pArr[i],a[i],*(a+i)//1,2,3,4,5
//	}
	pArr[3]=88;
}
	int a[5]={1,2,3,4,5};
	int b[6]={-1,-2,-3,-4,-56};
	int c[100]={99,22,88};
	printf("%d\n",a[3]);//4
	f(a,5);
	printf("%d\n",a[3]);//88

4->指针变量的运算
指针变量不能相加,不能相乘,也不能相除;
如果两个指针变量指向的是同一块连续空间中的不同存储单元,则这两个指针变量才可以相减。

int main(void){
	int i=5;
	int j=10;
	int *p=&i;
	int *q=&j;
	//p-q没有实际意义
	int a[5];
	p= &a[1];
	q=&a[4];
	printf("p,q所指向的单元相隔%d个单元",q-p);//p,q所指向的单元相隔3个单元
	return 0;
} 

5->一个指针变量占几个字节?
在这里插入图片描述
在这里插入图片描述

  • 总结:
    一个指针变量,无论他指向的变量占几个字节,该指针变量本身只占四个字节(32位系统占四个,64位系统占8个)。
    一个变量的地址是用该变量首字节的地址来表示
	char ch='A';
	int i=99;
	double x=66.6;
	char *p=&ch;
	int *q=&i;
	double *r=&x;
	printf("%d,%d,%d\n",sizeof(p),sizeof(q),sizeof(r));//8,8,8
  1. 指针和二维数组

4.3.指针和函数

4.4.指针和结构体

4.5.多级指针

五、专题:动态内存分配

5.1传统数组的缺点:

  • 数组长度必须事先指定,且只能是常整数,不能是变量
    在这里插入图片描述

  • 传统形式定义的数组,该数组的内存程序员无法手动释放。
    数组一旦定义,系统为该数组分配的存储空间就会一直存在,除非数组所在的函数运行结束。
    在一个函数运行期间,系统为该函数中数组所分配的空间会一直存在,直到该函数运行完毕时,数组的空间才会被系统释放。

  • **数组的长度一旦定义,其长度就不能再改变。**数组的长度不能在函数运行的过程中动态的扩充或缩小。

  • A函数定义的数组,在A函数运行期间可以被其他函数使用,但A函数运行完毕之后,A函数中的数组将无法再被其他函数使用。
    传统方式定义的数组不能跨函数使用

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

动态数组很好的解决了传统数组的这四个缺陷
传统数组也叫静态数组

5.3动态内存分配举例_动态数组的构造

  • 例1.介绍malloc函数
#include<stdio.h>
#include<malloc.h>
int main(void){
	
	int i=5;//分配了4个字节,静态分配 5行 
	int *p=(int *)malloc(4); //6行 
	/*
		1.要使用malloch函数,必须添加malloc.h这个头文件
		2.malloc 函数只有一个形参,并且形参时整数类型
		3.4表示请求系统为本程序分配4个字节
		4.malloc函数只能返回第一个字节的地址 
		5. 6行分配了8(int *p)+4(malloc请求分配的)个字节 。
		(p变量占了8个(64位系统),p指向的内存占了4个) 
		6. p本身所占的内存时静态分配的,而p所指向的内存时动态分配的 
	*/
	
	*p=5;//*p代表的就是一个int变量,只不过*p这个整型变量的内存分配方式和 5行的i变量的分配方式不同 
	free(p);//表示把p所指向的内存给释放掉。 p本身的内存是静态的,不能由程序员手动释放,p本身的内存只能在p变量所在的函数运行终止时由系统自动释放
	 
	
	return 0;
} 

在这里插入图片描述

  • 例2。修改指针所指向变量值,free()函数的应用
void f(int *q){
//	**q=200//error。只有指针变量前可以加*,而*q是int型 
	*q=200;
//	free(q)//把q所指向的内存释放掉 ,本语句必须注释掉,否则会导致第20行的代码出错 
} 

int main(void){
	int *p=(int *)malloc(sizeof(int));//sizeof(int)返回值时int所占的字节数 
	*p=10;
	printf("%d\n",*p);//10 
	f(p);
	printf("%d\n",*p);//200 20行 
	return 0;
} 

在这里插入图片描述
在这里插入图片描述
p和q指向同一个内存,free(q)则释放此内存

  • 例3
int main(void){
	int a[5];//如果int占4个字节的话,则本数组总共包含由20个字节,每四个字节被当作了一个int变量来使用 
	int len;
	int * pArr;
	int i;
	 
	//动态的构造一维数组 
	printf("请输入你要存放的元素的个数:");
	scanf("%d",&len);
	pArr=(int *)malloc(4*len);//本行动态的构造了一个一维数组,该一维数组的长度是len,该数组的数组名是pArr,该数组的每个元素是int类型。类似于int pArr[len];
	
	//对一维数组进行操作, 如对动态一维数组进行赋值 
	for(i=0;i<len;i++){
		printf("请输入第%d个数:",i+1);
		scanf("%d",&pArr[i]);
	} 
	
	//对一维数组进行输出
	printf("一维数组的内容是:");
	for(i=0;i<len;i++){
		printf("%d\t",pArr[i]);
	} 
	free(pArr);//释放掉动态分配的数组 
	return 0;
} 

在这里插入图片描述
在这里插入图片描述

5.4静态内存和动态内存的比较

  1. 静态内存是由系统自动分配的,由系统自动释放
    静态内存是在栈分配的
  2. 动态内存是由程序员手动分配,手动释放的
    动态内存是在堆分配的

5.4多级指针

int main(void){
	int i=10;
	int * p=&i;
	int ** q=&p;
	int *** r=&q;
	//r=&p;//error 因为r是int ***类型,r只能存放int **类型变量的地址
	printf("i=%d\n",***r);//10 
	return 0;
} 

在这里插入图片描述
在这里插入图片描述

void f(int **q){
	int i=5;
//	*q就是p 
}
void g(){
	int i=10;
	int *p=&i;
	f(&p);//p是int *类型,&p是int ** 类型 
}
int main(void){
	g();
	return 0;
} 

5.5跨函数使用内存的问题

  1. 例子
#include<stdio.h> 
#include<malloc.h>
void f(int **q){
	*q=(int *)malloc(sizeof(int));//sizeof(数据类型)返回值是该数据类型所占的字节数 
	//等价于p=(int *)malloc(sizeof(int));
	//q=5;//error
	//*q=5;//error,等价于p=5
	**q=5;//*p=5;
}
int main(void){
	int *p;
	f(&p); 
	printf("%d\n",*p); //5
	return 0;
} 
  1. 例题
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    答案:C
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值