C语言基础
从现在开始准备学习ndk开发,从基础开始学习和记录,大神勿喷,如有不对的地方,可以指出,谢谢。
只学一点以后NDK会用到的C语言基础知识。
C 面向过程,一个一个的执行函数,没有类,没有面向对象
C++ 面向对象,思想和java的一摸一样 开始有class了
指针
C语言中,最重要的就是指针,很多人都说是最难的
指针的概念:指针变量 和 指针 的区别:指针变量就是定义指针的标记而已,指针就是指向的内存地址。
int *p = 内存地址; p=指针变量 指针=内存地址;
&:取地址符号;
因为在C语言中,是面向过程的方式,所有的函数是一个一个的顺序编译执行,所以调用的方法需要放在调用者的上面;
/**
* TODO 替换两个数的函数
* @param n1 传入n1的内存地址(指针)
* @param n2 传入n2的内存地址(指针)
*/
void doMethod(int *n1,int *n2){
printf("doMethod num1内存地址:%#x====num2:%#x\n",n1,n2);
// TODO *是取内存地址的值 n1、n2是个内存地址
//用一个临时变量 temp 来存放 n1这个内存地址的值 *是取内存地址的值
int temp = *n1;
//将 n2的内存地址的值 赋值到n1的内存地址的值上面
*n1 = *n2;
//将 临时变量的值 赋值到n2的内存地址的值上面
*n2 = temp;
}
int main() {
// 指针的定义
int* p;
int * p2;
int *p3;
//指针的使用
int value1 = 1233;
//定义一级指针 *z (*指针名称)
//把这个value1的内存地址获取到 赋给一级指针z; &:取地址符号
int *z = &value1;
// 输出z指针对应的值 * 取出指针内存地址对应的值
printf("输出value1的值%d\n",*z);
// 输出z指针的内存地址
printf("输出value1的值%d\n",z);
// TODO 多级指针
int value2 = 2344;
//把这个value2的内存地址获取到 赋给一级指针z01; &:取地址符号
int *z01 = &value2;
// 取出 一级指针的内存地址
int **z02 = &z01;
// 取出 二级指针的内存地址
int ***z03 = &z02;
// 取出 二级指针的内存地址
int ****z04 = &z03;
// 需求:操作4级指针,取出值 2344
printf("取值:%d\n",****z04);
// TODO 指针实战
//替换两个数
int num1 = 10000;
int num2 = 20000;
printf("Main num1内存地址:%#x====num2:%#x\n",&num1,&num2);
//调用自己写的替换函数
// TODO 由于函数的参数是 int *n1,int *n2 需要指针,所以这里穿的是内存地址
// TODO 因为不同方法体里面 会是不同的内存地址 , 需要修改值就需要修改内存地址所对应的值
printf("doMethod之前===num1:%d====num2:%d\n",num1,num2);
doMethod(&num1,&num2);
printf("doMethod之后===num1:%d====num2:%d\n",num1,num2);
}
可变参数的函数
#include <stdarg.h> //可变参数暴露的头文件
//TODO 为了 学习 函数
/**
* 可变参数的函数
* 可变参数 需要导入 #include <stdarg.h> 这个头文件
* @param flag
* @param ... 表示可变参数
*/
void add(char * flag,...){
//等于开始
va_list changeList;
// flag 必须要传的参数,如果没有可以传NULL
va_start(changeList,flag);
//for遍历 可变参数
for (int i = 0; i < 6; ++i) {
//表示可变参数,需要传入int类型 va_arg表示往下取
int item = va_arg(changeList , int);
printf("可变参数有%d\n",item);
}
va_end(changeList); //等于结束 和开始需要一起出现
}
int main() {
//TODO 调用函数 使用可变参数
add(NULL,1,2,3,4,5,6);
}
函数指针
指向函数的指针 就是函数指针;
有点像java中传入接口回调,然后通过接口进行回调实现的方法;
// TODO 函数指针=======================start============
/**
* 函数指针
* 整体 void(*onShowAction)(char*):
* void==函数的返回
* (*onShowAction)== 函数的名称
* (char*)==函数的参数
*
* @param tt
* @param msg
*/
void say(void(*onShowAction)(char*) , char * msg){
onShowAction(msg);
}
// TODO 理解java的实现
void * myPrintln(char *content){
printf("函数myPrintln content:%s\n",content);
}
// TODO 函数指针 实战(登录) ====start==============
void login(void(*loginSuccess)(int64_t resCode,char * resultInfo),
void(*loginError)(int64_t errorCode,char * errorInfo)){
//TODO 非0 就是true ,等于0就是false
//因为这里是非0 所以为true,这里就会调用loginSuccess这个函数指针
bool isLoginOk = 9;
if(isLoginOk){
loginSuccess(1000,"欢迎回来\n");
}else{
loginError(999,"请重新登录\n");
}
}
/**
* 登录成功的处理
* @param resCode
* @param resultInfo
* @return
*/
void * loginSucceesAction(int64_t resCode,char * resultInfo){
printf("登录成功,resCode:%d;resultInfo:%s",resCode,resultInfo);
}
/**
* 登录失败的处理
* @param errorCode
* @param errorInfo
* @return
*/
void * loginErrorAction(int64_t errorCode,char * errorInfo){
printf("登录失败,resCode:%d;resultInfo:%s",errorCode,errorInfo);
}
// TODO 函数指针 实战(登录) ====end==============
// TODO 函数指针=======================end============
int main() {
//void(*test01)(char*) 与函数指针的参数定义一样,然后这个就用 myPrintln这个方法实现
//将这个方法实现传入到say函数中
//第一种写法
void(*test01)(char*) = myPrintln;
say(test01,"第一种写法==测试下函数指针\n");
//第二种写法
say(myPrintln,"第二种写法==测试下函数指针\n");
// TODO 函数指针的实战 (登录)
login(loginSucceesAction,loginErrorAction);
}
预处理器
预处理器: 指向流程,并不是在编译时期;
// TODO 第一种写法
#if 0
printf("写法一\n");
#elif 9
printf("写法二\n");
#endif //必须要写的
printf("一定会执行的\n");
// TODO 第二种写法 可以配合宏
//定义一个宏
#define NAME 'Kaizi' //先理解为 java的常量
char * name = NAME;
#define DEBUG_MODE //定义一个宏
// TODO ifdef 和 ifndef 不能同时存在
//#ifdef DEBUG_MODE; //可以理解为 有没有定义 DEBUG_MODE 这个宏 如果有定义的话,会执行这里,如果没有会走else
// printf("配合宏,当前模式为Debug模式\n");
#ifndef DEBUG_MODE //是否没有定义 DEBUG_MODE 这个宏 如果没有定义的话,会执行这里
printf("配合宏,当前模式为Debug模式\n");
#else
printf("配合宏,当前模式为Relase模式\n");
#endif
printf("一定会执行的\n");
结构体
结构体 可以理解为 java的 class;但是C里面不是对象,不需要new,用 struct 关键字 ;
结构体的使用,在栈中就定义了 ;
结构体里面所有的成员,默认都是public;
结构体所占的字节数 == 结构体里面所有成员的字节数相加;
// TODO 并不是等于java中的 import 导入
// TODO 是预处理器的时候完成的 等于 文本替换 将Main.h里面的东西全部复制过来
// TODO 不使用的头文件 不要导入进来 因为会占用体积
#include "Main.h"
// TODO 结构体 ================================start====================
// TODO 结构体 可以理解为 java的 class
// 第一种
struct Student{
// TODO 结构体里面所有的成员,默认都是public
char *name; //这里是字符串 char *
int age;
char sex
};
// TODO 结构体 后面跟着的s1和s2的标识 可以在使用的时候 直接拿着用
// 第二种
struct Worker{
// TODO 结构体里面所有的成员,默认都是public
char *name; //这里是字符串 char *
int age;
char sex
} s1 , s2;
// TODO 结构体 typedef是使用别名 后面跟着 DOG 别名就是DOG
// 第三种
typedef struct {
char * dogName;
int dogAge;
char dogSex;
} DOG;
//#pragma pack(2); //内部使用对其的算法 为了节约内存 一般我们不会操作 源码中会有,所以理解就好
// TODO 结构体
struct Person{
// TODO 结构体里面所有的成员,默认都是public
int age1;
int age2;
int age3;
};
//#pragma pack(); //还原操作
// TODO 结构体 ================================end====================
int main() {
// TODO 结构体,之前我们操作的,都是面向过程的,代表的就是结构体
//第一种使用
struct Student student; //在栈中就定义了 这样就等于初始化了
student.name = "凯子";
student.age = 18;
student.sex = 'M';
printf("name:%s;age:%d;sex:%c\n",student.name,student.age,student.sex);
//第二种使用
// TODO 结构体,这里用 s1 和 s2 这两个标识
// TODO 结构体,s1 和 s2 就等于上面的 struct Student student; 就不需要这样初始化了
s1.name = "凯";
s2.name = "子";
printf("s1.name:%s;s2.name:%s;\n",s1.name,s2.name);
//第三种使用
DOG dog;
dog.dogName="旺财";
dog.dogAge=2;
dog.dogSex='M';
struct Person person;
//里面是 3个int 一个int是4个字节 所以这里是 12
printf("person结构体 占用的字节数:%d\n", sizeof(person));
}
共用体(联合体)
共用体(联合体):在相同的内存位置当中,存储不同的数据;
共用体(联合体):所占大小是最大成员字节大小,在共用体中只有一块内存空间,共用体 共用内存;
使用的时候,需要用关键字 union
共用体(联合体):相同类型下,会保证最新的数据;
举例:有这样一个需求,很多的扩展成员属性,会被使用,我们要保证最最新的值信息
// TODO 共用体(联合体) ================================start====================
// TODO 共用体(联合体):在相同的内存位置当中,存储不同的数据
// TODO 共用体 最大成员字节大小,在共用体中只有一块内存空间,共用体 共用内存
union MyCount{
int countValueInfo;
int countValueInfo2;
int countValueInfo3;
int countValueInfo4;
int countValueInfo5;
int countValueInfo6;
int countValueInfo7;
};
// TODO 共用体(联合体) ================================end====================
int main() {
union MyCount myCount; //在栈中已经自己初始化好了
myCount.countValueInfo = 10;
printf("myCount.countValueInfo:%d\n",myCount.countValueInfo); //10
myCount.countValueInfo2 = 200;
printf("myCount.countValueInfo:%d\n",myCount.countValueInfo); //200
myCount.countValueInfo7 = 3;
printf("myCount.countValueInfo:%d\n",myCount.countValueInfo); //3
printf("myCount字节数:%d\n", sizeof(myCount)); //4个字节 共用内存
}
辛苦各位童鞋观看到最后,如果博客中有不对的地方望指出,大神勿喷,谢谢~~