复杂表达式与指针高级应用==C语言4

一、指针数组与数组指针

1、分析指针数组与数组指针表达式

  • int *p[5]; int (*p)[5]; int *(p[5])
  • 一般规律:int *p;(p 是一个指针) int p[5];(p 是一个数组)
    我们在定义一个符号时,关键在于:首先要搞清楚你定义的符号是谁(第一步:找核心);其次再来看谁跟核心最接近(第二步:找结合);之后继续向外扩展直到整个符号完结。
  • 如果核心和*结合,表示核心是指针;如果核心和[]结合,表示核心是数组;如果核心
    和()结合,表示核心是函数。
  • 用一般规律来分析 3 个符号:
    • int *p[5]; 核心是 p,p 是一个数组,数组有 5 个元素大,数组中的元素都是指针。指针指向的元素都是 int 类型的。整个符号是一个指针数组。
    • int (*p)[5]; 核心是 p,p 是指针,指向一个数组,数组有 5 个元素大,数组中的元素都是int 类型的。整个符号是一个数组指针。
    • int *(p[5]); 指针数组,解析方法与①相同,()在这里可有可无
  • 注意:遇到符号优先级问题,查优先级表,自己要记住一些常用的优先级
二、函数指针与 typede

1、函数指针的实质

  • 函数指针是一个普通的指针变量,它的值是某个函数的地址,也就是函数名这个符号
    在编译器中对应的值。

2、函数指针的书写和分析方法

  • C 语言是强类型语言(每一个变量都有自己的变量类型),编译器会做严格的类型检查。
  • 假设有个函数是:void func(void);对应的函数指针:void (*p)(void);类型是:void( * )(void)。
  • 函数名和数组名最大的区别是:函数名作右值时加不加&效果都是一样的,但是数组
    名则不一样。
  • 写出 strcpy 函数 char *strcpy(char *dest, const char *src)的指针:
    char * (*pfunc)(char *dest,const char *src)
    #include <stdio.h>
    
    int add(int a,int b);
    int sub(int a,int b);
    int multiply(int a,int b);
    int divide(int a,int b);
    
    typedef int (*pFunc)(int,int) pFunc;
    
    int main(void)
    {
    	pFunc p1=NULL;//防止变成野指针
    	int a,b,b;
    	char c;
    
    	printf("please enter two number:\n");
    	scanf("%d %d",&a,&b);
    	printf("please enter flag:+-*/\n")
    	do{
    		scanf("%c",&c);
    	}while(c == '\n');
    	switch(c){
    		case '+':p1=add;break;
    		case '-':p1=sub;break;
    		case '*':p1=multiply;break;
    		case '/':p1=divide;break;
    	}
    	d=p1(a,b);
    	printf("%d%c%d=%d\n"a,c,b,d);
    }
    

3、typedef 关键字的用法

  • 用来定义或者重命名类型。
  • C 语言中的类型一共有 2 种:一种是编译器定义的内件类型(ADT),另一种是用户自
    定义类型(UDT)。
  • 数组指针、指针数组、函数指针都属于用户自定义类型。
  • typedef 与 const
    • typedef int * PINT; const PINT p2; // 相当于const int *p2;
    • typedef int * PINT; PINT const p2; // 相当于 int *const p2;
    • typedef const int *CPINT; CPINT p2; // 相当于 const int *p2;

4、使用 typedef的重要意义

  • 简化类型的描述。
  • 创造平台无关类型,譬如 32 位系统 Linux 内核中定义了 typedef unsigned int size_t,用size_t 来表示 32 位无符号整形;若移植到 64 位平台,则只需要改成 typedef unsignedlong size_t,就能使 size_t 表示 64 位无符号整形,而不用改很多代码。
三、Linux 命令行

1、Linux 命令行默认是行缓冲的

  • 即printf输出时,Linux不会一个字一个字地输出内容,而是放在缓冲区,遇到\n再一次性输出。因为这样效率高。
  • 所以使用 printf 最后一定要加\n。

2、scanf 相关

  • 我们在输入内容时都会以\n 结尾,但 scanf 不会去接收最后的’\n’,导致这个回车符还留在标准输入中。下次 scanf 时就会被先拿出来,如果 scanf 中是%d、%s 还好,这时会自动跳过空格、制表符、回车符;如果 scanf 中是%c,那么就会将’\n’读走并返回。
四、二重指针

1、二重指针与普通一重指针的区别

  • 二重指针是一重指针的指针。
  • 两者本质上都是指针,都占四个字节。

2、C 语言中没有二重指针行不行

  • 其实是可以的一重指针完全可以做二重指针做的事情,之所以发明二重指针,就是为了让编译器了解这个指针被定义时的用途,帮程序员做静态类型检查。
  • 发明二重指针跟发明函数指针、数组指针、结构体指针的原因是一样的

3、二重指针的用法

  • 二重指针指向一重指针的地址:在函数传参时为了通过函数内部操作改变外部的指针变量。
  • 二重指针指向指针数组:通过二重指针调用指针数组的元素。
五、二维数组

1、二维数组的内存映像

  • 一维数组在内存中是连续分布的多个内存单元,二维数组也是。
  • 二维数组和一维数组在内存使用效率、访问效率上的差异可以忽略不计,使用二维数组是因为某种情况下它好理解、代码好写、利于组织。

2、哪个是第一维,哪个是第二维

  • 二维数组 int a[2][5]中,2 是第一维,5 是第二维。
  • 结合内存映像来理解,第一维是最外面一层数组,有 2 个元素;第二维是里面的那一层,对应第一维的一个元素时第二维有 5 个元素

3、二维数组的下标式访问和指针式访问

  • 回顾:一维数组的两种访问方式,以 int b[10]为例,int * p = b;
    b[0]等同于 * (p + 0); b[9]等同于 * (p + 9); b[i]等同于 * (p + i)
  • 二维数组的两种访问方式:以 int a[2][5]为例,int (* p)[5] = a;
    a[0][0]等同于 * (* (p + 0) + 0); a[i][j]等同于 * ( * ( p + i) + j)

4、二维数组的应用和更多维数组

  • 最简单的情况:有 10 个学生的成绩要统计,如果这 10 个学生是没有差别的一组,就用 int b[10];如果这 10 个学生是两个组的,每组 5 个,就适合用 int a[2][5]
  • 最常用的情况:一维数组用来表示直线,二维数组用来表示平面。
  • 三维数组类似于三维坐标系,表示立体空间
  • 四维数组也是存在的,在数学上有意义,但在空间中没有对应
六、二维数组指针访问

1、数组指针指向二维数组的数组名

  • 二维数组的数组名表示第一维数组中首元素的首地址,也就是数组地址
  • 二维数组名 a 等同于&a[0],解引用后为 a[0],即第一维数组的首元素,表示一个数组,相当于是第二维数组的数组名,即第二维数组首元素的首地址,因此 a[0]等同于&a[0][0]。

2、指针指向二维数组的第一维元素

  • int *p = a[0]; // a[0]表示第二维数组首元素的首地址,是一个变量地址。

3、指针指向二维数组的第二维元素

  • 二维数组的第二维元素其实就是普通变量了,不能用指针类型与其相互赋值。
  • 但可以用它的地址来给指针赋值,int *p = &a[i][j]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

栋哥爱做饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值