Table of Contents

image-20240216160508528

original video: https://www.youtube.com/watch?v=h-HBipu_1P0&list=PL2_aWCzGMAwLZp6LMUKI3cc7pgGsasm2_

Basic

image-20230523092542256

dereferencing

image-20230523093047220

*有不同的概念:

  • *p : 这个pointer指向的address里存的value

  • int *p; //定义一个指针

image-20231122110747688

有时候有的人会写成

int* p 和 int *p 是一样的

image-20231122111053099

问 address in p会指向b吗?

不会image-20231122111137262

image-20230523093511573

image-20230523094059102

image-20230523094538221

generic type?

为什么不能用generic type, 而是要给 *p 也声明一个type呢?

we do not only use the point to store the address, but also use them to dereference these address, so we can access and modify the value in these address

image-20230523094943503

这四个橙色的框是一个int的表示(因为int 是4byte, 一个byte含有4个bits)

signbit : 来存储这个数字是positive or negative(正还是负)

当我们dereference p的时候, 因为p是strong type, 所以他就知道我们要看4个位(start from 200), know how to extract an value from an integer type

image-20230523095547415

we put the same address as we have in p to p0

p0 = p, 但这个会报错? 为什么?

image-20230523095555883

generic pointer type

这不是空指针,空指针指的是不指向具体地址(NULL)的指针, void强调的是无类型. 所以没有办法dereferencing(*p0),

也没有办法运算(p0+1 这种是不行的)

image-20230523100044881

pointer to pointer

image-20230523100827742

这里r里面应该为205

image-20230523101417170

pointer use as function arguments

stack : 保存parameters, local variables, the calling function to which is should return(返回的地址)...

each function 都有一个 stack frame

首先执行main,遇到increment函数,main暂停, 在stack中开辟一块新的空间来执行increment, 当执行完, 清楚increment所在的stack frame, 也就意味着increment 从 stack中退出, 此时继续执行main

(注:下面这段代码我们期待输出11, 但输出10, 这是为什么呢?)

image-20230523104105129

image-20230523104141593

image-20230523104413431

了解了为什么不是11的原理之后, 我们现在提出解决方法: 用pointer

image-20230523104856048

image-20230523105713237

pointers and arrays

image-20230523110042117

image-20230523110212489

其实可以直接写成 p = A, 都不需要写&符号

image-20230523110548170

image-20230523110813579

image-20230523110920959

array as function arguments

image-20230523112004289

按理来说 sizeof(A)应该是20, sizeof(A[0])是4(因为是int, 所以占四个bytes), 但为什么会输出1呢?

image-20230523112114351

image-20230523112121308

为什么?

当数组做formal argument的时候, 不会copy整个数组, 而是创建一个同名的pointer, 准确地说, 是A数组的首元素的地址传了过去image-20230523122106934

compiler 看这个int A[], 就是一个 int* A

image-20230523122711616

character arrays and pointers

how to store Strings

我们把String当作参数传入, 假如array 的长度是8, string 存在 array里, 那怎么知道这个字符串到index几结束呢?

所以我们会添加一个标识'\0'来表明,这个字符串到这里就结束了, 所以也解释了为什么 需要 字符串+1的空间来存储字符串

image-20230523123623538

image-20230523123755477

image-20230523124101969

image-20230523124154840

用下图这种方式定义, \0 是 implicit

image-20230523124316506

这样的话是explicit, 意思也就是你必须自己把 \0写出来

image-20230523124436024

arrays and pointers use

image-20230523124804790

image-20230523124927069

arrays are always passed to function by reference

image-20230523125508888

image-20230523131442089

若字符串常量出现在在表达式中,代表的值为 该字符串常量的第一个字符的地址。

image-20230523131735667

image-20230523131700692

比如不可以写 C[0] = 'A', 会报错, 但是看下面

image-20230523132050015

​ C是个地址,传给函数就是pointer

pointers and multi-dimensional arrays

1-D array

image-20230523134341048

整型数组不是整型,整型数组里的元素是整型?

多维数组, 就是数组的数组

image-20230523135434546

当仅使用数组名的时候, 它会返回数组首元素的pointer, B返回的不是一个整型指针, 所以不可以写int *p = B

我们可以看出, B是一个指向一维数组的指针(含3个int), 那 B+1也是一个指向一维数组的指针

B是二维数组的名字, B[0]是一个1-D数组, 不是数组里面的元素

B相当于二维数组首地址(一维数组),那一维数组的首地址就是首元素地址

image-20230523135833661

image-20230523160236799

二维数组(数组的数组),*代表解引用一层,从二维解到一维,再从一维解到值。所以 *B就是代表一维数组的地址?

直接输出C数组, 输出的是C数组第一个元素的地址

*C 输出的是 C 数组中第一个元素的值

*B 输出的是 B数组中第一个元素的值

而 B 是一个 2-D 数组, 所以第一个元素是个数组 B[0] , 输出这个数组.

那我们知道, 输出数组也就是输出它第一个元素(B [0] [0] )的地址

所以 *B会输出一个地址, 而 B+1 是指的是第二个数组, 所以同理

*(B+1) 输出的也是一个地址, 也就是第二个数组第一个元素的地址

image-20230523160529713

image-20230523204102233

B 和 *B都返回指针,

但是B返回一个指向一维数组的指针, *B 返回一个指向整形的指针

三维数组

image-20230523212429825

c[0]指向的是一个一维数组,c才是指向二维数组

image-20230523213111573

C[1]指向的是从816开始到831结束的一维数组,但是这个一维数组里面嵌套了两个二维数组C[1] [0]和C[1] [1]。但是C[1]指的是C[1] [0]的地址,然后指针运算+1

如果把三维数组传进function

image-20230523213735204

stack and heap

首先看一下全局的application memory

image-20230524101146234

在运行的过成功, 上面这三个区域是不会grow的

image-20230524104508627

运行过程

main() -> total -> a,b

Sos() -> xyz

sq() => x

sq在运行的过程中paused, 等待sos 或者 main return一些数据来, 然后再继续执行, 当sq()这个方法return了, 就会从stack中被清除, 然后sos() 退出, 然后print方法加入进来

image-20240201172413915

然后print方法再退出, mian finish 也退出, 然后total 也会被decleared

当program开始的时候, os会allocate一些空间给stack

the size of the stack-frame is calculated while compling, 如果占完了stack的空间, 那就是stackoverflow(比如你写了一些奇怪的recursion), 所以当我们申明一些大的变量, like array, 我们需要know the size at complie, 而不是running

在stack上面的先执行,其他的会暂停 , 执行完就退出, 当mian也执行完, global也退出了

给 large chunks of memory allocate空间 或者 保持变量在memory中 直到而我们需要的时候, 我们need Heap

heap大小是可变的, 也叫做free store, dynamic memory, 这里我们说的heap不是data structure里的heap, 我们这里只指large free pool of memory, 当我们需要的时候就可以用

image-20230524110312685

用malloc方法,传入参数(4 bytes),就会在heap里创建一个内存空间, 不调用free, 这个10就会在heap里一直占内存

malloc方法会返回一个pointer, (也就是starting address of this block, 图上首先是200, 然后是400), 所以我们需要使用free方法

注: new出来的东西在heap里

下图是在heap里面存一个array(用的是C++了. 不是C)

image-20230524110636027

malloc, calloc, realloc, free

这些函数, 适用于支持 dynamic memory allocation, 我没听这节

memory leak

improper use of dynamic memory of the heap section, 就是在堆上增长垃圾, (我们申请了内存, 但用完之后不释放它)

比如我每次调用方法, 都用malloc分配空间, 所以每次调用方法都有一个pointer指向heap里面的一部分空间,

所以方法一直调用的话, heap里面就堆满了垃圾,

但java和C#不会 ,堆上的垃圾会被自动回收, 这就是java 的垃圾回收机制

image-20230524113253470

pointers as function returns

image-20230524114227154

我的理解是mai函数中传过来的值a的地址值,所以Add函数中a的值为传过来的地址值,所以Add中的a的值等于main中的&a,但Add中的a的地址即&a则是其他值, 所以不一样

image-20230524114159584

image-20230524114511711

我们在顶部添加一个函数叫helloword之后(直接输出一句helloword), 结果add方法输出的sum出了问题, 这是为啥

image-20230524115032426

现在add方法执行完了, 退出空间了

image-20230524115116843

现在要执行helloword方法, 要为其分配内存空间, 那加入分配到130-135, 那岂不是原来add方法的空间, 现在144这个空间就不再存储6了

image-20230524115244083

那也就意味着, 如果方法返回一个指针, 如果后面还需要执行其他方法, stack内存会被其它方法占用, 那么怎么办呢?

用malloc在heap上分配内存, 这样pointer就指向heap了

image-20230524115511481

function pointers

用来store the address of functions

image-20230524115742023

in memory, function is one continious block with some instrctions

function 的地址, 我们也把他称为函数的入口点, will be the address of the first instrcution

调用函数就是jump to 函数的第一条instruction

image-20230524121120661

image-20230524121244606

参数类型要和你要指向的函数的类型是一样的

image-20230524121708301

image-20230524121818753

image-20230524121828892

image-20230524121914936

image-20230524122006712

image-20230524122109764

image-20230524122152091

image-20230524122247709

image-20230524122521931

image-20230524122556819

image-20230524122715605