ndk学习之C语言基础复习----指针、函数、预处理器
指针:
指针乃C、C++的灵魂之所在,所以有必要好好的复习复习。什么是指针?一句话来概括:“指针是一个变量,它的值是一个地址。”,其中指针变量的声明有如下三种形式:
其中第一种是被推荐的写法。
其中还需要注意:在声明指针时如果未赋值,则是一个野指针【也就是有可能指向了一个不能被使用的地址从而造成程序的错误】,所以在声明时一定要赋值,如下:
那如果想取变量的地址则可以用“&”符,如下:
那如果想获取指针指向变量地址的值则需要用“*”解引用的操作,如下:
下面来看一下p指针占用了几个字节:
需要注意的是:由于目前是在64位系统上运行的,所以是8个字节,如果是在32位运行则长度是4个字。
有了指针之后就可以用它去操纵内存,下面来通过指针的形式来修改变量的值,如下:
指针是可以进行++、--操作的,比如用指针来遍历数组,下面来看下:
其中“*array_p1++”是先取了值,然后再对其指针进行++,如果是写成"*++array_p1",则是先对指针进行加加,然后再取值,最终输出就会漏掉一个,如下:
其中还有一种直接通过数组来进行相加也能达到遍历的目的,如下:
要取其数组的内容则需要解引用:
另外还有一个细节:为啥数组取地址时木有加“&”符号:
这是因为在C中数组名就是数组的首地址,下面来看下:
下面有个概念需要弄清楚:“数组指针”和“指针数组”,这个在面试可能会经常变问到,下面来看下:
其中指向的数组的元素个数为3,如果咱们想要通过数组指针array_p2来获得第二维的55,如何来写呢?
首先肯定得要将数组的指针+1,来定位到第二维的数组,所以array_p2+1,然后再取出它的值则是*(array_p2+1),接着这个值是一个数组,所以还得数组名+1来将指针移到要输出的第二个元素上来,所以此时为*(array_p2+1)+1,最后再解引用取出指针的值,所以整个的式子如:*(*(array_p2+1)+1),下面来验证一下:
接下来更绕的来了,先把代码写出来:
我去!!什么鬼~const char~~char const~~搞死人的节奏~~但是在学C时必须要理解它的,下面一个个来理解,在理解之前,先记着这个原则:“从右往左看 const 修饰谁 谁就不可变”:
意味着不能通过p2来修改tem的值,如下:
因为const是修饰的char,而非p2变量,所以p2的内容可以被更改,如下:
继续来理解下一个:
这个跟上一个效果是一模一样的,为啥?因为const只能修饰char,不能修饰*。
继续看下一个:
还是按照从右往左的原则,const这次修饰的是变量p4,也就是说p4的内容是不允许修改的,如下:
但是可以通过指针修改指向地址的值,如下:
好,继续,下面两个是啥都不能变了,如下:
拿p5举例,既不能修改p5指针的值,如下:
下面再来看一个跟指针相关的东东---多级指针:
解引用则为:
函数:
函数声明:
C中的函数跟Java的方法基本类似,但是在C中的函数需要注意:我们使用的函数必须在之前声明,否则会编译不过,如下:
可以在之前做一个声明既可:
所以一般函数都声明在头文件中,然后一.c文件中头部进行include,这样就如同上面的声明一样了。
函数传参:
- 传值:把参数的值给函数,如下:
也就是说不会改变原有变量的值。
- 传引用:
也就是可以通过指针来修改原值,有了这个特性,那么多级指针就变得非常有意义了,如下:
可变参数:
在Java中我们知道可变参数是由...来弄的,其实在C中也类似,其中我们经常打印的printf()函数就接收一个可变参数,查看一下源码便知:
所以咱们也来弄一个可变参数:
呃~~报错了~~参数中不能只有可变参数,必须要有一个确定参数,所以修改如下:
接着问题来了,如何来取出可变参数的值呢?看下面:
然后接着进行遍历,根据类型:
注意:其确定参数给NULL值是可以的,反正是要有一个,什么类型的都可以,不能没有确参,如下:
函数指针:
定义:指向函数的指针。举个例子:
其中"void (*p) (char*)"就是一个函数指针,void表示该函数无返回值;(char*)表示函数的参数列表,目前只接收一个参数;(*p)表示指向函数的指针。
接着咱们来调用一下:
其实也就相当于Java中的方法回调的意思,另外可以将函数的声明定义成一个typedef,如下:
可以用函数指针模拟HTTP请求,如果成功就执行某个函数,失败则执行某个函数,如下:
预处理器:
预处理器主要是完成文本替换的,常用的预处理器如下:
下面具体来看一下:
- #include:这个就不多说了。
- #if、#elif、#else、#endif:在实际代码编写中会遇到这样的写法,如下:
假如不想要这段代码了,则直接更改条件既可:
适用的场合就是假如写的代码不想要了,则不用注释掉了。
#define、#ifdef、#ifndef:这里可以配合#define的宏定义来配合上面的一些条件来使用,如下:
其中定义的宏是可以被取消的,如下:
其中#define宏定义分为两种:宏变量和宏函数,具体如下:
这样在代码中就可以使用I来表示1了,如下:
而在之前说过预处理其实也就是做文本替换用的,所以代码中所有的I就会被预处理器替换为1。
接下来看一下宏函数:此时就可以在代码中进行调用了,如下:
但是宏函数也有陷阱需要注意,看下面这个:
如果修改一下:
期望的结果应该是(1 + 10)* (10 + 10) = 220,但是运行看:
居然变成了:1 + 10 * 10 + 10了,所以需要特别注意,可以加个括号解决:
下面来看一下宏函数有哪些优缺点:
优点:它只是文本替换,使用到宏函数的地方会执行替换,不会有函数调用的开销(将参数压栈,释放栈之类的)。
缺点:1、不会对我们的代码执行检查,不像普通的函数在编写阶段就会给出相印的错误提示。2、假如宏函数是一个非常复杂的函数,那么每个调用它的地方就会完全替换,造成代码冗余使得最终生成的目标文件(如so)增大了,比如:如果代码中调了两次它,如下:
实际上文本替换之后就是:
其实内联函数跟宏函数的执行模式是一样的,也是执行代码替换,但不是一个概念,内联函数在编写时会做检查,另外它里面的代码不能编写过于复杂的代码,如使用了switch、while等复杂控制逻辑,否则会将内联函数降级为普通函数,那何为内联函数呢?其实就是inline关键字,如下:
- #pragma:这个用得较少,在VS中在头文件中会自动有一个如下东东:
它表示该头文件只能被引用一次,其实通用的写法是用它:
其效果都是一样的。
ndk学习之C语言基础复习----指针、函数、预处理器的更多相关文章
- ndk学习之C语言基础复习----虚拟内存布局与malloc申请
在这一次中来学习一下C语言的内存布局,了解它之后就可以解释为啥在用malloc()申请的内存之后需要用memset()来对内存进行一下初始化了,首先来了解一下物理内存与虚拟内存: 物理内存:通过物理内 ...
- ndk学习之c++语言基础复习----C++线程与智能指针
线程 线程,有时被称为轻量进程,是程序执行的最小单元. C++11线程: 我们知道平常谈C++线程相关的东东基本都是基于之后要学习的posix相关的,其实在C++11有自己新式创建线程的方法,所以先来 ...
- ndk学习之c++语言基础复习----C++容器、类型转换、异常与文件流操作
继续来复习C++,比较枯燥,但是这是扎实掌握NDK开发的必经之路,不容小觑. 容器: 容器,就是用来存放东西的盒子. 常用的数据结构包括:数组array, 链表list, 树tree, 栈stack, ...
- ndk学习之C语言基础复习----基本数据类型、数组
关于NDK这个分类在N年前就已经创建了,但是一直木有系统的记录其学习过程,当然也没真正学会NDK的技术真谛,所以一直也是自己的一个遗憾,而如今对于Android程序员的要求也是越来越高,对于NDK也是 ...
- ndk学习之c++语言基础复习----面向对象编程
关于面向对象编程对于一个java程序员那是再熟悉不过了,不过对于C++而言相对java还是有很多不同点的,所以全面复习一下. 类 C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程 ...
- ndk学习之C语言基础复习----结构体、共用体与C++开端
自己实现sprintf功能: 关于C中的系统函数sprintf在上次[https://www.cnblogs.com/webor2006/p/7545627.html]学习中已经用到过了,这里再来回顾 ...
- MySQL学习笔记_8_SQL语言基础复习
SQL语言基础复习 一.概述 SQL语句注释方式 1)以"#"开头直到行尾的所有内容都是注释 2)以"--"(--后还有一个空格)开头直到行尾的所有内容都是注释 ...
- GO学习-(10) Go语言基础之指针
Go语言基础之指针 区别于C/C++中的指针,Go语言中的指针不能进行偏移和运算,是安全指针. 要搞明白Go语言中的指针需要先知道3个概念:指针地址.指针类型和指针取值. Go语言中的指针 任何程序数 ...
- 嵌入式-C语言基础:指针函数
指针函数:返回指针的函数,即函数返回一个地址.例如:int * a(int x,int y);由于()的优先级比*高,因此a先与()结合,a(int x,int y)显然是一个函数,函数前面带一个in ...
随机推荐
- Andrew Ng机器学习课程11之贝叶斯统计和正则化
Andrew Ng机器学习课程11之贝叶斯统计和正则化 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 在统计学中有两个学派,一个是频率学派,另一个是贝叶斯学 ...
- OpenCV Python 4.0安装
1.安装OpenCV-Python 如果你是第一次使用OpenCV Python开发包,想要安装OpenCV Python4.0只要执行如下命令行即可: pip install opencv-pyth ...
- Java线程安全队列Queue实现原理
原文链接:https://www.cnblogs.com/DreamRecorder/p/9223016.html 在Java多线程应用中,队列的使用率很高,多数生产消费模型的首选数据结构就是队列.J ...
- [转帖]Linux命令pmap
Linux命令pmap https://www.cnblogs.com/lnlvinso/p/5272771.html jmap可以查看Java程序的堆内存使用情况,pmap可以查看Linux上运行的 ...
- java日志框架系列(7):logback框架Layout详解
1.Layout layout从字面意思来看就是排版.布局咯. 1.Layout简介 功能:负责把事件转换成字符串.Layout接口的格式化方法doLayout()负责将代表任何类型的事件的转换成一个 ...
- java基础--Java虚拟机
·JVM (Java Virtual Machine ):Java虚拟机,简称JVM,是运行所有Java程序的假想计算机,是Java程序的运行环境,是Java 最具吸引力的特性之一.我们编写的Java ...
- Laravel安装和composer安装
下载地址:https://getcomposer.org/download/ 他会自动找到你的php目录,如果没有记得手动修改 一直点下一步,即可. 如果安装不成功,可能是之前安装过composer ...
- spring 框架的核心总结
最近在学习Java语言,从而也学习了SpringFramework 这个大名鼎鼎的框架.从而做一些的记录. 题外话: 学习过几种不同的语言,后来知道所有的编程语言里所有的概念翻来覆去都是一样的事物,只 ...
- Python开发【第二章】:深浅拷贝剖析
Python深浅拷贝剖析 Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果. 下面本文就通过简单的例子介绍一下这些概念之间的差别. 一.对象赋值 ...
- vue-cookies的使用
安装vue-cookies npm install vue-cookies --save 使用vue-cookies // 在main.js中 // require var Vue = require ...