站点图标 Yorafaの家~欢迎来玩!~

C 指针与内存地址

PS: 本文主讲 C Language的 Pointer和Memory. 内容全凭个人理解而写,若有不同见解可以评论讨论


Pointer

在了解指针是什么东西之前,首先来了解一个特殊符号 &。一般情况下我们在日常交流或者表达&用于表达and,但在编程语言中有很多不同的表达

通俗的理解指针就是,得到想要的地址,有了地址就可以上门做很多事情大雾

下面来看个赋予值的例子

int a = 1;
int * address_a = &a;

在此处

指针的运算

接着上面的例子,以及*的定义
试想一下 执行*address_a ++a 的值为多少?

结果是2。未免有点纳闷,这计算和直接执行a++一样,为什么我们还需要用到指针呢?
这就不得不再重复重复过很多遍的点

举个例子

void func(int num){
num++;
}

运行func(a)后,我们会发现num并没有变化这是因为int为原始数据类型
但是

int num;
void func(int* num_ptr){
(*num_ptr)++;
}

运行func(&num)后,我们会发现num竟然神奇的加了1,这就是指针的妙用

地址的运算

书接上面的例子,加上下面几句

int *b;
b = address_a + 1;

上面我们说过 指针的变量本身是一个地址,对于地址的运算会产生什么变化呢?
在这里 我们将b赋予address_a + 1的值,但实际上我们运行出来会发现 地址实际上 + 4,这是因为int类型的大小为4bytes。有时候我们会发现变量地址,与赋予的地址不一样,这是因为不同visualizer的显示方式可能有所不同,但是pointer的值永远指向的是绝对地址
这里列出不同类型的大小

数组与指针与数组的指针

当我们将数组本身当成一个地址时, 例如

int num_array[5] = {1,2,3,4,5};
func(num_array);

另一个例子

int sum(int * a, int size){
    int sum = 0;
    for (int i=0; i<size; i++){
        sum += a[i];
    }
    return sum;
}
int main(){
    int a[3] = {0, 1, 2}
    int result = sum(a, 3);
}

此处调用sum方法时我们写入的为数组a, 此时就被当作a[0]地址使用

在执行过后,num_array[0] 将会加1。这说明了数组不加[]是可以当作指针来使用,而默认的数组(没有[])表达第一位值的地址。但要注意,数组与指针 还是有很多不同
在举个指针与数组的例子

int c[3] = {1,2,3};
int * address_c = c;

C数组可以out of index?

书接上面的例子,我们可以尝试给c[4]赋予一个值,学过其他编程语言的人可能会意识到out of index error,在c里可能会有部分ide报错,可以成功运行。
在上述情况下,程序内存是这样的(我随机捏造2个初始地址):

在上述条件下,两者的大小分别为:

在执行c[4] =3后,在内存中:

函数的指针

我们可以指针指向变量,指向数组,当然也可以指向函数。那么怎么样才能去指向一个函数呢,让我们从一个例子开始。

int func(){
    return 1;
}
int main(){
    int (*x)() = func;
    return x();
}

在上述例子中,我们将 x 作为指针指向了 func,具体的

有没有发现一件事,我们可能有许多函数所需的参数类型与参数数量都一样,也就是说我们这个指针可以指向任意一个满足该条件的函数。也就是说我们可以利用指针当接口来调用不同的函数。

内存地址

很多人对内存的分配不是很了解笑死我也不了解,在这里,代码运行一般从靠近0但不能为0的地址开始, 对c程序的内存地址的分配浅析一下
一般的内存组成如下:

Code 代码

代码也会占有内存

Global Data 全局数据

Heap 堆

执行动态内存分配类的函数时,所被分配变量会被存在堆中

malloc函数

当我们查看api时,会发现malloc的前缀时void *,这是因为

Stack 栈

根据程序所含的函数/方法而将内存分成不同的栈(stack)

我内存学的有点垮,等我学业有成再回来修改

退出移动版