环境准备
可以选择使用 VS2013开发,但是这个家伙比较重量级,所以我们还有一个选择就是使用 Clion,如果只使用 Clion需要配置 MinGW环境。
VS2013
下载链接:https://pan.baidu.com/s/1uOMk6LEAazBG5YQf_R6Ssg 提取码:3ts6
Clion
Jetbrains旗下产品之一,主要用来开发C/C++,软件相比VS来说轻巧很多,官方下载链接:http://www.jetbrains.com/clion/?fromFooter
Clion的安装就是傻瓜式的下一步下一步,这里就不再赘述,太侮辱大家智商了,哈哈哈~ 安装好Clion之后,别急着运行,得先装MinGW,因为它才是真正执行C/C++程序的东东。
MinGW
链接:http://sourceforge.net/projects/mingw/files/
点击下载按钮:

运行安装包:
点击 Install:
点击Continue,等待安装完成之后,再点Continue:
安装完成之后,需要下载相关包的支持,如下图所示:点击左侧的 Basic Setup,勾选所有包:
点击 Installation→Apply Changes:
然后就是漫长的等待,大约半个小时左右后,右侧的包前面的框框变绿了,说明MinGW环境OK了。
第一个C程序
打开Clion,打开File→Settrings→Build,Execution,Deployment→Toolchains,可以看到 Clion会自动匹配 MinGW,因为我本地安装了 VS2013,所以这里会同时出现 MinGW和 VS,随便选择一个即可。
找到工具栏中的 File→New Project:
接着我们选择C Executable,再选择自己存放C工程的目录,C标准一般选择C99,然后点击 Create。
工程创建好之后,默认会创建一个 main.c文件,等工程加载完成之后,点击运行按钮即可。
PS:Clion只有30天的免费试用时间,点击加入我的安卓技术训练营,群共享中有无限试用的方法。
初识NDK
NDK是什么
- NDK(C/C++) <-------------------> SDK(Java)性质是一样的
- 定义:Native Development Kit,是 Android的一个工具开发包
- 作用:快速开发C、 C++的动态库,并自动将so和应用一起打包成 APK
- 提供了把.so和.apk打包的工具
- 提供了交叉编译器,用于生成特定的CPU平台动态库
- 提供了很多很多的native支持,就相当于SDK提供了很多上层的支持一样
NDK特点
- 运行效率高
- 代码安全性高
- 功能拓展性好
- 易于代码复用和移植
NDK能做什么
打开支付宝APK,微信APK,等等,里面就有很多native库
NDK的学习由哪些内容所组成
第一阶段:C语言的学习,C++语言的学习,JNI的学习。
第二阶段:CMake的学习,Linux基本操作,Linux Shell脚本编程。
第三阶段:各种实战(身份证识别,MMKV组件,QQ变声 等)。
第四阶段:FFmpeg视频播放器项目,RTMP直播流。
第五阶段:OpenCV人脸定位,OpenGL视频处理,OpenGL视觉效果。
目前先按这五个阶段一步一步来。
C语言基础
解读第一个程序
#include <stdio.h>
//#include "stdio.h"
//<>表示寻找系统库;如果用“”,则会先去寻找自定义的库,找不到才会去找系统的库
//.h .hpp 是头文件,声明文件
//.c .cpp 是实现文件
int main() {
printf("Hello world!");
return 0;//0表示程序执行完成后正常退出
}
基本数据类型
#include <stdio.h>
// 基本数据类型
int main() {
int i = 100;
double d = 200;
float f = 300;
long l = 400;
short s = 500;
char c = 'a';
// 字符串
char *str = "Luffy";
// 不是随便打印的,需要占位
printf("i的值是:%d\n", i); // d == decimal
printf("d的值是:%lf\n", d); // lf == long float
printf("f的值是:%f\n", f); // f == float
printf("l的值是:%d\n", l); // d == decimal
printf("s的值是:%d\n", s); // s == short
printf("c的值是:%c\n", c); // c == char
printf("字符串:%s\n", str); // s == string
getchar();//阻塞程序
return 0;
}
关于getchar的作用移步这里:getchar()作用
#include <stdio.h>
/**
* 基本类型占用的字节数(后续过程中,非常常用的) sizeof获取字节数
* 因为有些基本数据类型的所占字节数与操作系统有关,比如32位的系统int
* 可能占2个字节,64位的占4个
*/
int main() {
// int 占几个字节 == 4
// double 占几个字节 == 8
// char 占几个字节 == 8
printf("int 数据类型所占的字节数:%d\n", sizeof(int));// 4
printf("double 数据类型所占的字节数:%d\n", sizeof(double));// 8
printf("char 数据类型所占的字节数:%d\n", sizeof(char));// 1
return NULL; // NULL == 0
}
指针
概念
#include <stdio.h> // C99 标准库
// 地址概念
// Java ------ 万物皆对象
// C C++(对象) ------ 万物皆指针
// Linux ------ 万物皆文件
int main() {
// 指针 == 地址
// %p == 地址输出的占位
// & == 取出地址
int number = 100000;
printf("number变量的地址是:%p\n", &number); // 地址 == 0061FF1C
return NULL;
}
PS:解决打印语句在控制台输出中文乱码问题,双击shift,输入 File encoding修改编码格式。
取出指针保存的值
#include <stdio.h>
int main() {
int number_int = 100;
double number_double = 200;
printf("number_int的值是:%d\n", number_int);
printf("number_double的值是:%lf\n", number_double);
// * 取出number_int地址所对应的值 == 100
// 指针取出值
// 既然任何变量都是地址,可以使用地址获取值
printf("number_int的值是:%d\n", *(&number_int));
printf("number_double的值是:%lf\n", *(&number_double));
// ================ 难度升级
// 在这里,赋值号左边的星号是为了声明指针变量
int *intP = &number_int;
double *doubleP = &number_double;
// 输出 100 和 200
printf("number_int的值是:%d\n", *intP);//printf格式化输出语句中,后面的星号是用来取地址的
printf("number_double的值是:%lf\n", *doubleP);
// 概念
/**
如果你去上网查询,指针的文章,就会发现,一些专业术语,导致大学老师一直说不清楚,成功劝退很多学生放弃:
内存地址变量,内存地址别名,指针,指针变量,指针别名,.... 一大段的专业术语 ...
理解: 大道至简 (化繁为简)
内存地址 == 指针
指针 == 内存地址
int * ------ (int类型的指针),double * ------ (double类型的指针)
指针别名,指针变量 == 就是一个变量而已,只不过 是指针的 变量 而已
上面代码中的 intP 和 doubleP 就是指针变量
*/
return NULL;
}
通过指针修改值
#include <stdio.h>
// 通过指针(地址)修改值
int main() {
int i = 100;
// p:我只接收地址,你给我一个100,不规范
// int * p = i;
int * p = &i;
i = 200;
printf("i的值:%d\n", i);
*p = 300;//取出指针 p存放的数据,然后用 300覆盖给这个数据的原始值
printf("通过指针修改i的值:%d\n", i);
return 0;
}
函数中的值传递和地址传递
#include <stdio.h>
// C语言不允许函数重载 Java可以,C++可以
//void change(int i); // 先声明 ------ 这样的是值传递,形参相当于change函数中的局部变量
void change(int *i); // 先声明 ------ 这样是地址传递
//调用函数修改值,传参需要用指针
int main() {
int i = 100;
// change(i);
change(&i);
printf("main中i的地址%p,i的值%d\n", &i, i);
/*
int * i; 定义指针
*i = 666; 取出内存地址所对应的值修改成666
*/
return 0;
}
// 函数不能写在 main的下面,会报错
// void change(int i) {}
// 再实现
//void change(int i) {
//
// printf("change内存地址:%p\n", &i);
//
// i = 200;
//}
// 再实现
// 使用指针 来修改
void change(int *i) {
printf("change中 i 的内存地址:%p\n", i);
*i = 666;
}
#include <stdio.h>
// 由于C语言不支持函数重载,所以声明的函数,不需要写参数 (只要函数名一样,
// 就会报错,即使返回值不一样也不行)
//int changeAction();
void changeAction();
int main() {
int a = 100;
int b = 200;
changeAction(&a, &b);
printf("交换完成后的效果:a = %d,b = %d\n", a, b);
return 0;
}
// 只接收指针(内存地址) 内存地址 == 指针
void changeAction(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}