1>视频中的内容
一、指针
1.指针定义
-
地址
1.内存单元的编号
2.从零开始的非负整数
3.范围问题(对于4g内存)首先明白:一个地址=一个内存单元=一个字节 cpu和内存条之间有32根地址线 一根地址线由低电压(0),高电压(1)形式控制,则可以控制2个存储单元 而有32根,根据排列组合,则有2^32种(0和1形式),则就可以控制2^32个存储单元 又知道2^10字节=1kb,2^10kb=1M,2^10M=GB;所以1GB=2^30字节 则2^30*4字节=4GB
-
补充知识:
cpu和内存条之间具体关系:
cpu,内存条之间由三种线
联系
1.控制线(控制数据的传输方向(写入,存储))
2.数据线(传输数据)
3.地址线(传输地址)
他们之间具体联系:cpu接受指令,得到一系列地址,然后通过地址线发送地址找到其在内存条当中的具体位置,然后通过控制线对该地址的进行操作(操作即为读取该地址存储的数据或者是将数据写入),然后将数据传输到cpu进行处理(或者是存储数据到该地址)
- 指针
指针就是地址,地址就是指针
指针变量和指针是两个不同的概念
指针变量就是存放地址(内存单元编号)的变量
指针(地址)的本质
就是一个操作受限的非负整数
(操作受限是指指针只能进行减法(减法表示两地址之间距离(对于连续地址而言)),不能加乘除(加乘除无意义))
2.指针重要性的体现
1、表示一些复杂的数据结构
2、快速的传递数据
3、是函数返回一个以上的值(重点
)
4、能直接访问硬件(因为是对地址进行操作,而硬件的内涵就是地址)
5、能够方便的处理字符串
6、是理解面向对面语言中的引用基础
3.指针的分类
基本指针
- int * p p是指针变量名字(p又名指针变量),而int * 表示p只能存放int类型变量的地址
- p=&i
1、p保存了i的地址,因此p指向i
2、p不是i,i也不是p,两者地址独立不同,修改p的值并不影响i的值,反之也成立
3、如果一个指针变量指向某一其他变量,则* 指针变量 就完全等同
于普通变量(即*p=i,所以只要出现了*p就可以与i互换) - p+1的含义
p+1表示地址加定义P的数据类型的字节数
如double * p,加了P+1,其地址加了8
指针和一维数组
- 为什么要和数组联系起来
因为当需要在其他函数中使用main函数中的数组时,调用是发送值,不可能我把数组元素全部发送,可想工程很大,而我们用了指针,那就只需发送两个值即可(地址,数组长度)
……………… - 一维数组名
一维数组名是个指针常量(切不可当作变量)
它存放的是一维数组第一个元素的地址即(a(常量)与a[0](变量)的地址相同)
- 确定一个一维数组需要两个参数
第一个元素的地址
数组长度
- 用指针在其他函数输出主函数中的数组问题
void f(int *q, int len)
{
int i;
for (i = 0; i < len; i++)
{
printf("%d ", q[i]);//这里q[i]等价于*(q+i) (等价于*(a+i)等价于a[i],但这里不能用,因为局部变量)
}
}
int main()
{
int a[5] = {1, 2, 3, 4, 5};
f(a,5);
return 0;
}
- 其他注意点
1.q[i]=a[i]=*(q+i)=*(a+i),他们可以相互转换(指内容一个改变,另一个跟着改变),但要知道他们的本质还是不同的,变量地址也是不一样的
2.p=a(数组名),则p指向的字节数由定义p的类型
所决定的,如int * p就表示p指向4个字节数。而p存放的地址,为p指向的字节数中首个
字节数的地址(单元编号),即int 类型变量的地址是4个存储单元其首个单元编号。
指针和函数
为什么指针和函数联系起来:
当模块化写代码时,想要通过调用函数实现改变其他函数
内的已经定义变量内容。我们知道调用函数只能返回一个值进行赋值,且从一个函数到另一个函数,我们只能发送
本函数变量的数据,而不能直接改变本函数变量的值。所以我们运用指针,发送该变量的地址,即可在其他函数内直接对其地址所代表的变量进行操作
总结而言,指针是函数之间的桥梁
如看下面几个例子,我们来清楚明白指针对函数的功能
经典例题(交换数值)
错误案例:
错误点:形参和实参以为一致
错误点(重):没有准确的理解什么是发送。调用swap_2函数,发送的是a,b地址,但在swap_2函数中,却只是将形参p,q中存放ab的地址进行交换,但并不影响a,b的内容(值)
正确案例:
发送的是a,b的地址,然后在swap_2函数中p=a,q=b进行交换,则内存条中,其对应地址的内容发生改变。
如何准确理解 * p的含义,就是可以想象直接在内存条搜寻p的内容,找到后进行改变操作(管你定义时的变量在哪个函数中,我们变量所占的地址都是在内存条中,而我的指针就是对内存条进行操作)
多级指针(套娃)
根据如图,做一下解释是更好理解
1、 p存放的是i的地址,那么*p就代表i变量
q里面存放的是p的地址,则*q就是p(则有i的地址),则**q就是i
r里面存放的是q的地址,则*r就是q(则有p的地址),则**r就是p(则有i的地址),则*** r就是i
2、注意他们定义时的区别点
语法规则:
int *类型的变量=int *类型的变量=& int类型的变量
比如 int * q;
int * p;
int i;
则p=q=&i,这样才符合语法规则
int ** q;
int * p;
则*q=p或者q=&p;这样才符合语法规则;
指针和数据体结构
无
4.其他一些相关指针的问题
一定要明白的核心
1、就是p是存放的是其他变量的地址,而p就相当于是“解其中的地址”,首先p要有值必须p中一定存在地址,这样*p才能解其中的地址。这也是多级指针的核心,就是不停的代换,别被绕进去,不要单纯的互换一下,一定要明白其内在的东西,这样才不容易出错
2、当一个变量被定义时,则该变量的地址就已经确立,地址是一定不会变的
(在函数,程序还在运行时)。所以我们只能改变变量的值
3.任何指针变量
都只占4个字节(如double * p;int * q)
(double * p表示p存放的是类型为double类型变量的地址)
*号的意义
sezeof函数(系统函数,在头文件stdio.h里)
- 格式:sizeof(数据类型或者变量名)
- 功能:返回值即为该数据类型或该变量所占的字节数
- 例子:sizeof(int)=4, sizeof(char)=1
, int i;sizeof(i)=4;
malloc函数(系统函数,在头文件malloc.h里)
-
格式(常用于指针的空间分配) :int * p=(int *(与前面类型一致))maclloc(字节数(常量))
-
功能:为指针变量手动分配动态空间
-
注意点:
使用前必须加头文件#include <malloc.h> malloc函数只有一个形参,并且形参根据定义的类型确定 字节数表示请求系统为本程序分配几个字节 malloc函数只返回第一个字节的地址 例如int * p=(int *)maclloc(20) 则这一语句系统一共为其分配了24个字节,p指针变量占4个, 而又在内存里分配了20个动态内存单元(20个字节), 其中p由于是int *类型,则p指向这20个字节前4个字节, 其p里保存的就是这4个字节 的地址,也就为首个字节的地址
如图所示:
动态内存的分配
-
传统数组的缺点
1.传统定义的数组,该数据的内存程序员无法手动释放 2.数组长度一旦定义,程序运行时就无法更改数组的长度,也就不能动态的扩充和缩小 3.A函数中定义的数组,在A函数运行期间可以被其他函数调用, 但A函数运行完毕后,其中的数组内存将被释放掉,无法在被利用
-
为什么需要动态内存分配
因为:解决传统数组的三个缺点 。
就是当主函数想或者其他函数
调用其他函数
中的数组时, 如果是静态数组的话就无法实现,而如果定义一个动态数组,则就会一直存在; -
动态内存分配举例(动态内存数组的构造(利用指针)) 1.为什么只能用指针构造:
因为动态内存是命令系统分配的,而我们要找到这个动态内存必须得通过其地址寻找, 而就是用指针才能找到。所以这就是为什么没有int i=(int) malloc(4)的原因
2.如何构造
#include <stdio.h>
#include <malloc.h>
int main()
{
int len;
printf("输入你想要存放的元素:");
scanf("%d",&len);
int * p=(int *)malloc(4*len);
int i;
for(i=0;i<len;i++)
{
scanf("%d",&*(p+i));//一定不能缺地址符,或者将其换成P+i;
}
for(i=0;i<len;i++)
{
printf("%d\n",*(p+i));
}
return 0;
}
其解释如下
- 静态内存和动态内存的比较
静态变量:
程序运行时,系统自动分配,且由系统自动释放。当一个程序开始运行,从主函数进,从上至下执行语句,该过程按执行语句顺序分配内存的过程叫做进栈
,而静态变量释放的时候是本函数终止时,释放该函数内所定义所有的变量的内存的过程叫做出栈
,所以进栈是一个一个语句进,出栈是一个一个函数出
。
动态内存:
程序运行时,手动命令系统进行分配,可手动释放,也可系统终止运行时释放。且动态内存的分配过程叫做堆,是连续的空间。
- 跨函数使用内存问题
1.静态变量无法跨函数,函数终止时就会被释放
动态内存可跨函数
2.举例
静态变量跨函数:
这个答案是p会报错,虽然p存放的i的地址还在,但i的内容在函数f终止时已经被释放掉了,所以p没有内容
如何去改变已经定义好的变量的内容
根据现所学
1、直接在本函数对其变量赋值
2、跨函数用指针,必须发送该变量的地址
,才能对其变量中的内容进行操作
2>作业
10.12
输出内容为:
8 8
4 8
0 8
2 8
ref有4个元素
ref地址是ref[0],
ref+1是第二个元素的地址,
++ref指向ref中的变量
a:
*ptr为12
*(ptr+2)为14
b:
*ptr为 12
*(ptr+2)为16
a:
** ptr : 12
**(ptr+1): 16
b:
** ptr : 12
**(ptr+1): 14