Hello,C(3)

指针

一级指针

  1. 指针:变量的地址

  1. 指针变量:存放指针的变量

  1. 取地址操作符是&,也叫引用,通过该操作符我们可以获取一个变量的地址值

  1. 取值操作符为*,也叫解引用,通过该操作符我们可以拿到一个地址对应位置的数据

  1. 指针变量前面的*,表示该变量的类型为指针型变量

  1. int* a 这个声明与前面一个声明具有相同的意思,而且看上去更为清晰, a 被声明为类型为 int*的指针.但是,这并不是一个好声明习惯,原因如下:int* a,b,c,人们很自然地以为这条语句把所有三个变量声明为指向整型的指针,但事实上并非如此。星号实际上是表达式*a 的一部分,只对这个标识符有用,其余两个变量只是普通的整型,要声明三个指针,正确的语句如下:int *a, *b, *c;

指针的使用场景

指针的使用场景只有两个,传递与偏移

指针的传递

  1. C 语言的函数调用均为值传递,并不会传递这个值的地址,传入函数中的值实际赋给了另一个地址,在函数执行结束后就释放了,原本的值不会改变。所以需要通过传递指针,访问指针变量修改值,称为指针法

指针的偏移

  1. 通过自增自减访问相邻地址(多用于数组等)

动态内存申请

#include<stdlib.h>

void *malloc(size_t size);
void free(void *ptr);
  1. 栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是 C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多,但堆更灵活

const常量

  1. const从汇编角度来看,只是给出了对应的内存地址,而不像#define给出立即数,所以const int PI = 3比#define PI 3的效率高

  1. const char *ptr:不能修改*ptr,但能修改ptr

  1. char* const ptr:不能修改ptr,但能修改*ptr

二维数组

  1. 二维数组与二级指针并没有关系,二维数组是通过两次偏移获取到数组中的某一个元素,所使用的指针是数组指针,数组指针是一级指针。

  1. 使用二维数组,我们使用 p[i][j]较多,首先 p+i 偏移到对应的行,然后*(p+i)就是拿到对应行,等价于一维数组,而一维数组的数组名存储的就是一级指针,所以*(p+i)+j 就偏移到对应的元素,然后再解引用就拿到对应的元素值

  1. 数组指针 int p[][4]与int (*p)[4]是等价的

  1. 二维数组的行数依然无法传递的

二级指针

二级指针的传递

  1. 二级指针变量定义是在形参

  1. 在调用函数中往往不定义二级指针,如果定义,初始化注意是一级指针的取地址

二级指针的偏移

  1. 服务对象为指针数组

函数指针

  1. 函数名本身存储的即为函数入口地址,将 p 传递给函数 a,相当于把一个行为传递给函数 a。之前我们传递给函数的都是数据,通过函数指针可以将行为传递给一个函数,这样我们调用函数 a 可以就可以执行函数 b 的行为,当然也可以实现执行其他函数的行为

void b()
{
    printf("I am func b\n");
}

void a(void (*p)())
{
    p();
}

int main()
{
    void (*p)(); //定义了一个函数指针变量
    p = b; //函数指针的返回值及入参要与函数保持一致
    a(p);
    return 0;
}

函数

  1. 实参:函数调用处的参数

  1. 形参:函数定义处的参数

嵌套调用

  1. setjmp保存进程的上下文,longjmp实现恢复进程现场

递归调用

变量和函数的作用域

  1. 从变量的作用域(即从空间)角度来分,可以分为全局变量和局部变量

  1. 从变量值存在的时间角度来分,又可以分为静态存储方式和动态存储方式

静态存储方式:指在程序运行期间由系统分配固定的存储空间的方式

动态存储方式:则是在程序运行期间根据需要进行动态的分配存储空间的方式

  1. 变量和函数有两个属性:数据类型和数据的存储类别。存储类别指的是数据在内存中存储的方式,根据变量的存储类别,可以知道变量的作用域和生存期。存储类别分为两大类:静态存储类和动态存储类。包含:

自动的(auto)

不专门声明为 static 存储类别的局部变量都是动态分配存储空间,在调用该函数时系统会给它们分配存储空间,在函数调用结束时就自动释放这些存储空间。因此这类局部变量称为自动变量。函数中的形参和在函数中定义的变量(包括在复合语句中定义的变量),都属此类。auto可以省略,所以大家往往在编程中没有看到auto

静态的(static)

  1. 静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间都不释放

  1. 用 static 修饰全局变量,那么该全局变量将不能被其他文件引用

  1. 用 static 修饰函数,那么该函数将不能被其他文件引用

寄存器的(register)

C言允许将局部变量的值放在 CPU 中的寄存器中,需要用时直接从寄存器取出参加运算,不必再到内存中去存取。由于对寄存器的存取速度远高于对内存的存取速度,因此这样做可以提高执行效率。这种变量叫做寄存器变量,用关键字 register 作声明。由于寄存器的数目是有限的,用 C 语言进行服务器编程时,性能提升采用 register 手法的非常少,嵌入式编程可能会使用到

外部的(extern)

外部变量是在函数的外部定义的全局变量,它的作用域是从变量的定义处开始,到本程序文件的末尾。在此作用域内,全局变量可以为程序中各个函数所引用。编译时将外部变量分配在静态存储区。用 extern 来声明外部变量,以扩展外部变量的作用域。所有函数默认都是 extern 类型的,因此任何一个文件的函数都可以被其他文件调用

函数调用原理

  1. 栈是向下生长的,所谓向下生长是指从内存高地址->低地址的路径延伸,栈有栈底和栈顶,那么栈顶的地址要比栈底低

  1. 寄存器 ebp指向栈底,寄存器esp指向栈顶

结构体

  1. 形式:struct 结构体名{成员列表};

  1. 考虑到内存对齐,建议集中存储小成员,小成员尽量声明在末尾

链表

  1. 增删改查

  1. calloc = malloc + memset(0)

共用体

  1. 形式:union 共用体名{成员列表}变量列表;

  1. 共用体变量所占的内存长度等于最长的成员的长度

  1. 在每一瞬时只能存放其中一种成员,起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员就失去作用

  1. 不能对共用体变量名赋值,也不能企图引用变量名来得到一个值

枚举

  1. 形式:enum 枚举名{成员列表}

  1. 将变量的值一一列举出来,变量的值只限于列举出来的值的范围内

  1. 在C编译中,对枚举元素按常量处理,故称枚举常量。它们不是变量,不能对它们赋值

  1. 枚举元素作为常量,它们是有值的,C语言编译按定义时的顺序使它们的值为0,1,2…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值