基本数据类型
* 和java类似,不做记录
* sizeof(int)->获取int数据类型所占大小->其他已此类推
可变参数
/**
* 可变参数
* @param count
* @param ...
* @return
*/
int sum(int count, ...) {
va_list varList;
int sumNum = 0;
//指向第一个可选参数,第二个参数应该传递可变参数的前面一个参数,目的是定位知道可变参数在哪里
va_start(varList, count);
for (int i = 0; i < count; ++i) {
sumNum += va_arg(varList, int);
printf("sumNum is:%d\n", sumNum);
}
//清空varList指针
va_end(varList);
}
宏定义
#define LOG_I(FORMAT,...) printf(FORMAT,__VA_ARGS__);
`__VA_ARGS__`为固定写法
调用:LOG_I("%s","这是一个宏定义");
宏定义相当于是一个替换
LOG_I("%s","这是一个宏定义")替换后printf("%s","这是一个宏定义")
结构体
定义:
struct Man {
char *name;
int age;
};
使用:
int main() {
struct Man man;
man.name = "tsimeon";
man.age = 1;
LOG_I("%s %d",man.name,man.age);
return 0;
}
变量使用:
struct Man {
char *name;
int age;
} simeon;
int main() {
simeon.name = "my name is simeon";
simeon.age = 18;
LOG_I("%s %d",simeon.name,simeon.age);
return 0;
}
结构体大小:注意字节对齐,不指定按照默认的对齐
* 自然对齐,定义的时候尽量将小数据定在前面
1、某个变量存放的起始位置相对于结构的起始位置的偏移量是该变量字节数的整数倍;
2、结构所占用的总字节数是结构中字节数最长的变量的字节数的整数倍。
自然对齐举例:
struct Struct1
{
short a;
int b;
short c;
};
结果:
short = 2 补 2
int = 4
short = 2 补 2
sizeof(Struct1) = 12
struct Struct2
{
short a;
short c;
int b;
};
结果:
2个short在一起组成一个 4
sizeof(Struct2) = 8
* 指定对齐
#pragma pack(2) //指定以2字节对齐
struct Struct1
{
short a;
int b;
short c;
};
sizeof(Struct1) = 8
* 取消对齐
#pragma pack()
struct Struct1
{
short a;
int b;
short c;
};
sizeof(Struct1) = 12
合理的利用字节可以有效地节省存储空间
不合理的则会浪费空间、降低效率甚至还会引发错误。(对于部分系统从奇地址访问int、short等数据会导致错误)
联合体[和结构体类似,成员共占一块空间,数据大小根据最大的数据类型确定]
union Value {
jboolean z;
jbyte b;
jchar c;
jshort s;
jint i;
jlong j;
jfloat f;
jdouble d;
jobject l;
} value;
上面这份代码复制的jni.h的jvalue的定义
使用:
value.f = 3.1415926;
value.j = 10000;
LOG_I("f的值:%f j的值:%d",value.f,value.j);
结果:
f的值:0.000000 j的值:10000
解释:因为公用一块空间,所以f的值被j覆盖所以输出为0
指针
基本理解:指向内存中的一块地址,操作就是移动指针
int i=0;
//输出的是i的地址,#x表示用16进制输出
LOG_I("%#x\n",i);
//输出的是i的值0,*表示取指针的内容
LOG_I("%#x\n",*i);
//&表示取地址符,将i的地址赋值给指针p
int *p = &i;
数组指针:
int main() {
//二维数组
int array[2][3] = {{1, 2, 3},
{4, 5, 6}};
//数组指针
int (*arr)[3] = array;
//获取数组的最后一个元素,解释第一步取第二个数组内容[*(array + 1)]指针指向4,然后+2移动到最后取内容
int lastEle = *(*(array + 1) + 2);
printf("%d", lastEle);
return 0;
}
指针数组:
int i = 0;
int *p[] = {&i, &i, &i};
说明:指针数组和数组指针不要弄混淆,一个是数组一个是指针
* 函数指针:
/**
*
* 参数列表代表一个函数指针
* void 代表返回值
* (*mp)是一个参数变量
* (char *)代表方法参数
* @param mp
*/
void proxyPrint(void (*mp)(char *)) {
printf("%s", "这是一个函数指针的掉用");
}
int main() {
void (*mp)(char *) = printf("来打印数据吧");
proxyPrint(mp);
return 0;
}
动态分配内存
1.使用malloc
int main() {
int *data = malloc(sizeof(int) * 5);
//初始化所有数据为0,防止脏数据出现
memset(data, 0, sizeof(data));
for (int i = 0; i < 5; ++i) {
*data = i;
LOG_I("%d\n",*data);
data++;
}
//释放指针
free(data);
return 0;
}
2.使用calloc->calloc默认将元素初始化了所以不需要再次初始化,不会读取到脏数据
int main() {
int *data = calloc(5, sizeof(int));
for (int i = 0; i < 5; ++i) {
*data = i;
LOG_I("%d\n", *data);
data++;
}
//释放指针
free(data);
retrun 0;
}
常量
const 和 java final类似
//从右往左读 const修饰哪个哪个就不能改变
char *str = "apple";
//情况一
const char *p = str;//这里不能修改char
所以:
p[0]='A';//错误
p = "banana";//正确
//情况二[情况二和情况一是一样的,因为const不能作用于*所以往前就作用于char]
char const *p = str;
//情况三
char * const p = str;
p2[0] = 'A'; //正确
p2 = "12345"; //错误
//情况四 都不能修改
const char * constp= str;
预处理器
- 预处理器不是编译器,但是它是编译过程中一个单独的步骤。
- 预处理器是一个文本替换工具
- 所有的预处理器命令都是以井号(#)开头
常用预处理器
预处理器 |
说明 |
#include |
导入头文件 |
#if |
if |
#elif |
else if |
#else |
else |
#endif |
结束 if |
#define |
宏定义 |
#ifdef |
如果定义了宏 |
#ifndef |
如果未定义宏 |
#undef |
取消宏定义 |
使用:
#define DEBUG
#ifdef DEBUG
#include <strings.h>
#endif
todo 其他使用用的时候补充查文档,多看标准库函数