其他基本数据类型java有这里就不介绍了 ide:visual studio2013 操作系统:win10 64 bit 从这篇开始 我会记录下我每天学习jni的过程。
ide下载地址:visual studio2013百度云连接
我只是一个初学c(大学学过忘了差不多)Android开发者 想学习jni中。。。文章仓促而成加上自己不成熟错漏在所难免。还请您多多海涵和指明
union 介绍enmu介绍字符串指针指针与数组方法指针多级指针输出方法输入方法逻辑判断struct结构体外挂原理
内部定义一组数据,大小为数据中最大的内存变量决定
代码 :
union MyUnion{ int a; double c;};那么如果我们定义Myunion大小为double
案例:
#include <stdio.h>#include <Windows.h>union MyUnion{ int a; double c;};void main(){ union MyUnion data; data.a = 1; PRintf("double 大小%d/n", sizeof(double)); printf("union MyUnion 大小 %d/n", sizeof(data)); system("pause");}运行结果:
方法说明: 1. void main() 方法启动入口 和java 差不如理解 2. # include 导入头文件XXX.h (相当于java的import 导入包) 但不是不导入实现类 3. # include<stdio.h >
导入标准 输入输出流 std标准的意思 ,io输入输出 ;导入后可以使用 printf 和scanf等函数(后面介绍); 4. # include <Windows.h>
windows操作系统头文件 导入后可以使用dos命令;使得其调用system(“pause”);(让其黑窗口不是一闪而过) 5. sizeof() 返回对应变量的字节数 ,编译环境不同返回的大小也不一样
和java很类似但是也有不同点 感觉比java好用的多
enum MyEnum{ RED, BLUE, WHITE};注意:RED默认代表0 其余的默认递增 也就是说 BLUE 代表1 ,WHITE代表2;
enum MyEnum{ RED, BULU, WHILTE};void main(){ enum MyEnum a = BULU; printf("%d/n",a); system("pause");}输出:
当然也可以修改枚举默认值
enum MyEnum{ RED =3 , BLUE, WHITE};RED=3 之后的枚举默认递增 BLUE = 4 ,WHITE = 5
C没有java中的String变量 一般用char[] 表示 和char * (指针)表示;注意char 在c里面一个字节。
char[]使用方法void main(){ char astring[3] = { 'a', 'b', '/0' }; printf("%s/n",astring); system("pause");}解释:必须要加一个’/0’否则程序不知道字符串在哪里结束 输出:ab
看一下另一个案例:
void main(){ char astring[] = "asdasd"; printf("%s/n",astring); system("pause"); }解释:上面默认会自动加上‘/0’
注意字符数组存字符串 不能直接二次赋值
如下代码汇编错误:
void main(){ char astring[] = "asdasd"; printf("%s/n",astring); astring = "asd";//报错 system("pause");}赋值方法:
void main(){ char astring[] = "asdasd"; printf("%s/n",astring); strcpy(astring, "新的字符串"); printf("%s/n", astring); system("pause");}strcpy函数需要导入#include <string.h>
虽然 char[]不支持二次赋值 但支持 单个字符修改
#include"stdio.h"void main(){ char string[] = "asd"; string[0] = 's'; printf("%s",string ); getchar();}输出:ssd
2 char* 使用方法
指针 比较灵活的一个方式 且可以直接赋值
#include"stdio.h"void main(){ char * string = "asd"; string = "met"; printf("%s",string ); getchar();}解释:getchar();接收一个字符串这里写的目的是不让黑窗口消失
没有指针就没有c
指针 分很多种 如 int * ,byte * ,struct* 。。。。。
指针的含义:指向某个内存区域
int * 断点案例:
我们先让程序执行到 printf(“”);//此时int a = 3 执行完毕
我们观察下 a 的变量地址
可以看到 a内存地址为 0x0117fae0
然后执行后面全部代码 查看输出
指针访问
修改对应内存数值
void main(){ int a = 3; printf("");//断点到这 让程序执行 a = 3; //获取 a 的地址 保存到p种 int * p = &a; printf("a变量地址 %#x/n",p); *p = 5; printf("a的数值: %d/n", a); getchar();}输出:a :5
*p 表示对应指针保存内存的数值 通过修改其值 可以间接修改变量数值
请看如下代码:
#include"stdio.h"void main(){ int a[] = {1,23,45,6}; printf("数组a的内存地址 %d/n", &a); printf("数组a[0]的内存地址 %d/n", &a[0]); printf("a变量的值 %d/n", a); printf("*a保存的数值 %d/n", *a); printf("a[0]保存的数值 %d/n", a[0]); getchar();}输出结果:
结果分析: a完全可以当成一个指向数组第一个元素a[0] 内存地址,a就是一个指针. 那么 *(a+1) = a[1] tip: a+1 自定偏移四个字节 因为a是int * 类型 加1 偏移int的字节数
所以验证案例如下:
#include"stdio.h"void main(){ int a[] = {1,23,45,6}; printf("*(a+1)= %d/n",*(a+1)); printf("a[1] 内存地址= %#x/n", &a[1]); printf("(a+1)指向 内存地址= %#x/n", (a + 1)); getchar();}输出结果:
不知道是不是java中接口回调的机制原理
#define _CRT_SECURE_NO_WARNINGS //宏定义让其可以使用scanf#include"stdio.h"#include <stdlib.h>#include <string.h>int add(int a,int b){ return a + b;}void main(){ //int(*fun)(int, int) = add;//方法一 int(*fun)(int, int) =&add;//方法二 int result = fun(3,3); printf("%d",result); getchar();}多级指针 包含2级以上指针,这里写下2级指针 其他3级指针大家可以自己尝试下 请看以下案例
# include <stdio.h>void main(){ int a = 100; printf("变量a的地址%#x/n",&a); //定义一个一级指针 int *p = &a; printf("一级指针p的地址%#x/n",&p); printf("一级指针p保存的变量地址%#x/n", p); printf("一级指针p保存的变量内存地址对应的字面量为%d/n", *p); //定义一个二级指针 存一个1级指针的地址 int **p2 = &p; printf("/n"); printf("二级指针p2的保存地址%#x/n", p2); printf("二级指针p2保存的一级指针指保存的对应的字面量为%#x/n", *p2); printf("二级指针p2保存的一级指针指向内存地址对应的字面量为%d/n", **p2); getchar();}输出:
结论: 2级指针是用来保存1级指针的内存地址,p2 输出对应保存对应内存的字面量 (1级指针p保存的内存地址 本例是保存int a地址),**p2输出1级变量保存内存的字面量即 int a的数值大小100;因为*p2可以当成p ,所以*p=(*p2); 数学等量代换
我们在java中输出文字在控制台一般是System.out.println方法,而在c中输出方法printf,且需要占位符;
如下:
#include"stdio.h"void main(){ char * string = "hello Word"; char p[] = "hello word"; printf("%s/n", string); printf("%s/n", p); getchar();}上面的代码输出了两个字符串 。%s就时一个暂未符
那么我们看看c语言的暂未符把 以下列举常用类型
符号 | 意义 |
---|---|
%d | 带符号int类型 |
%s | 字符串类型 |
%c | char类型 |
%f | float类型 |
%lf | double类型 |
%o | 八进制 |
%x | 十六进制 |
%#x | 十六进制且开头带有0x |
%u | 无符号10进制整数 |
tip:和java一样的格式化输出 %0.2d (保留两位小数 四舍五入)等等
从控制台输入数据。 和c语言的输出方法一样 都需要占位符 注意:在visual 2013中 scanf需要加宏定义去取消警告去使用这个API(老API嘛)
#define _CRT_SECURE_NO_WARNINGS //宏定义让其可以使用scanf#include"stdio.h"void main(){ printf("请输入一个数:/n"); int a =1 ; scanf("%d", &a); printf("输入结果为%d/n",a); getchar();//取消回车键影响 getchar();}scanf(“%d”, &a); 注意这里有个取地址&
其他输入方法类似:
#define _CRT_SECURE_NO_WARNINGS //宏定义让其可以使用scanf#include"stdio.h"void main(){ printf("请输入一个字符串:/n"); char a[100] ; scanf("%s",&a); printf("输入结果为%s/n",a); getchar();//取消回车键影响 getchar();}上面这个不需要取地址符号也行 ,原因:数组符号是个指针 保存内容就时数组首地址
在java中if()判断依据是boolean 而 c中NULL和0都是false 如:
void main(){ if (0){ printf("是真"); }else{ printf("是假"); } getchar();}输出 : 是真
给我感觉和java的类一样
初始化方式1:
#define _CRT_SECURE_NO_WARNINGS //宏定义让其可以使用scanf#include"stdio.h"#include <stdlib.h>struct MyStruct{ int age; char * name;};void main(){ struct MyStruct test1 = {12,"里斯"}; printf("我的年龄%d,我的名字%s",test1.age,test1.name); getchar();}初始化方式2:
#define _CRT_SECURE_NO_WARNINGS //宏定义让其可以使用scanf#include"stdio.h"#include <stdlib.h>struct MyStruct{ int age; char * name;};void main(){ struct MyStruct test1 ; test1.age = 1; test1.name = "金额"; printf("我的年龄%d,我的名字%s",test1.age,test1.name); getchar();}假如结构体内部字符串是 char[100]的不能用方式2初始化 需要使用strcopy函数 如下:
#define _CRT_SECURE_NO_WARNINGS //宏定义让其可以使用scanf#include"stdio.h"#include <stdlib.h>#include <string.h>struct MyStruct{ int age; char name[100];};void main(){ struct MyStruct test1 ; test1.age = 1; strcpy(test1.name,"asd"); printf("我的年龄%d,我的名字%s",test1.age,test1.name); getchar();}结构体可以嵌套
如下:
#define _CRT_SECURE_NO_WARNINGS //宏定义让其可以使用scanf#include"stdio.h"#include <stdlib.h>#include <string.h>struct MyStruct{ int age; char name[100]; struct MyStruct2 { int aa; };};void main(){ struct MyStruct2 test2; test2.aa = 3; struct MyStruct test1; test1.aa = 232; printf("%d/n", test2.aa);//输出3 printf("%d", test1.aa);//输出232 getchar();}假设我们又一款游戏(单机) ,生命值应该是一个变量,我们只需要获取到这个生命值的内存地址,在用指针指向然后修改指针数值即可完成。但是不同程序是不允许直接访问的(win98之前听说可以)。。所以我们只需要把程序生成dll(动态链接库即可),在用注入器注入dll即可
#include <stdlib.h>#include <stdio.h>__declspec(dllexport) void update(){ //修改血量内存地址 这里假设地址是这个 int *p = 0x99999999; *p = 999999;}//__declspec(dllexport) 固定写法让其动态库能被调用
最后生成dll文件,然后利用dll注入某个游戏 调用我们写的update方法即可
新闻热点
疑难解答