Android JNI--C语言基础

这篇具有很好参考价值的文章主要介绍了Android JNI--C语言基础。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1,  #include

相当于java的导包操作 例如:#include <stdio.h>

<> 代表寻找系统的资源
“” 代表寻找我们自己写的资源
.h .hpp(声明文件 头文件)
.c  .cpp (实现文件)

2,代码结构

int main() {  // 函数的主入口
    printf("哈喽!");//打印

    getchar(); // 阻塞程序
    return 0;
}

3,基本数据类型

 int i = 100;
 double d = 200;
 float f = 200;
 long l = 100;
 short s = 100;
 char c = 'd';
上面这些基本数据类型与java一致
需要注意的是 字符串类型 java中是String  而C语言中是  char * str = "我是字符串";
sizeof获取字节数 下面是每个基本类型所占用的字节数 可以通过此api获取
sizeof(int)//int 占几个字节  == 4
sizeof(double)//double 占几个字节 == 8
sizeof(char)//char 占几个字节 ==1
sizeof(long)//long占几个字节 == 4
sizeof(short)//short占几个字节 == 2
sizeof(float)//float占几个字节 == 4


 bit——计算机的最小单位

          byte——1byte = 8bit       (byte就是字节)

          kb——1kb = 1024byte

          mb——1mb = 1024kb

          gb——1gb = 1024mb

          tb——1tb = 1024gb

          pb——1pb = 1024tb

4,打印

打印需要注意的是,不和java一样随便打印的,需要占位符

    printf("i的值是:%d\n", i); // d == 整形
    printf("d的值是:%lf\n", d); // lf == long float
    printf("f的值是:%f\n", f); // f == float
    printf("l的值是:%d\n", l); // d == 整形
    printf("s的值是:%d\n", s); // s == short
    printf("c的值是:%c\n", c); // c == char
    printf("字符串:%s\n", str); // s == String

5,指针地址

在java中,万物皆对象。

在Linux中,万物皆文件

在C 语言中,万物皆指针

指针其实可以理解为地址

  & 代表取出地址 例如:

int number = 10;
printf("此number变量的地址是:%p\n", &number); // 地址 == 00B3FE90
* 代表取出地址所对应的值 例如:
int number = 100;
printf("number的值是:%d\n", *(&number));//100 

&number代表number所对应的地址  *(&number)代表取number地址所对应的值 所以输出100
int * 代表int类型的指针 说明定义的是一个指针变量,就是一个变量而已,只不过是指针的变量而已

例如:

int a = 100;
int * b = &a;
printf("a的值是:%d\n", *b);

输出100  因为b是a的指针,也就是a地址,
*b代表取地址所对应的值,也就是取a的地址所对应的值100

只要记住一句话,内存地址就是指针,指针就是内存地址

下面看一个错误的用法:

int i = 100;
int * p = i;

这种写法是错误的,因为p只能接收指针,给它传一个100,显然是不行的

正确的写法应该是:

int i = 100;
int * p = &i;
指针变量 只能接收指针

如何通过指针修改变量值呢?举个例子:

int i = 100;
int * p = &i;
i = 200;
printf("*p的值是:%d\n", *p);

输出200,因为i变为了200,p指向i,*p取得是i的值


*p = 300;

printf("i的值是:%d\n", i);


输出300,因为*p代表i的地址所对应的值修改成300

6,函数

C语言不允许函数重载,Java可以,C++可以

函数需要先声明,再实现。 函数不能写在main函数的下面,会报错

下面来看一个简单的函数例子:

#include <stdio.h> //引入标准库

void change(int * i); // 先声明  参数为指针变量

int main() {

    int i = 100;

    change(&i);//传入指针

    printf("%d\n", i);//输出666

    return 0;//main函数返回值 也可以写为NULL
}


// 再实现
// 使用指针 来修改
void change(int * i) {

    *i = 666;
}

由于C语言不支持函数重载,所以声明的函数,不需要写参数

例如:

void change();//不需要填写参数

int main() {
    int a = 100;
    int b = 200;

    change(&a, &b);

    printf("交换完成后的效果:%d,%d\n", a, b);//200  100

}

// 只接收指针(内存地址)
void change(int * a, int * b) {

    int temp = *a;

    *a = *b;

    *b = temp;
}

7,多级指针:

直接看例子:

int num = 20;

int * num_p = &num; // 取出num的内存地址给 num_p(一级指针)

int ** num_p_p = &num_p; // 取出num_p的内存地址给  num_p_p(二级指针)

int *** num_p_p_p = &num_p_p;//取出num_p_p的内存地址给 num_p_p_p (三级指针)

printf("获取最终的值:%d\n", **num_p_p);//输出20

printf("获取最终的值:%d\n", *** num_ppp);//输出20

是几级指针,取值时,前面就加几个*

8,数组与数组指针

 定义数组
 int [] arr = {1,2,3,4}; 错误的写法
 int arr[]  = {1,2,3,4}; 正确写法
遍历数组
int i = 0;
for (i = 0; i < 4; ++i) {
   printf("%d\n", arr[i]); // 取值
}

数组的内存地址 等于第一个元素的内存地址,不是其他元素的地址

上面数组的内存地址可以写为:arr    &arr   &arr[0]

既然数组就是一个内存地址,那么

int * arr_p = arr;

数组可以用地址变量赋值

操作数组,就是对数组的指针进行操作。

int arr[]  = {1,2,3,4};

将数组地址赋值给指针变量arr_p  此时指针默认指向第一个元素
int * arr_p = arr; 

printf("%d\n", *arr_p); //输出1 因为此时指针指向第一个元素的内存地址

arr_p ++; // 指针挪动   此时指向元素二的内存地址了

printf("%d\n", *arr_p); // 输出2 因为此时指针指向第二个元素的内存地址

arr_p += 2;

printf("%d\n", *arr_p); // 输出4 因为此时指针指向第四个元素的内存地址

数组是连续的内存空间,数组每次挪动4个字节

通过循环给数组赋值:

定义数组
int arr[4];

赋值给指针变量arrP
int * arrP = arr;

循环赋值操i作
int i = 0;
for (i = 0; i < 4; ++i) {
  // 1.拿到 元素一 元素二 元素三 元素四 的内存地址   (arrP + i)
  // 2.取出 元素一 元素二 元素三 元素四 的内存地址 所对应的值 * (arrP + i)
  * (arrP +i) = (i + 10001);
}

9,函数指针

void(*methid)(int,int) 函数指针 

void 返回值

(*methid) 函数名

(int,int)参数  可以随便写 这里只是举个例子

下面来看具体用法:

void add(int num1, int num2); // 先声明


void opreate(void(*method)(int,int), int num1, int num2) {
    method(num1, num2);
}


int main() { 

    opreate(add,  10, 10);
   
    printf("main函数的 add指针是多少:%p\n", add);

    // &add和add是一样的值吗
    printf("%p, %p\n", add, &add); //  一样的

    return 0;
}

// 再实现 使用
void add(int num1, int num2) {
    printf("num1 + num2 = %d\n", (num1 + num2));
}

10,C语言中的布尔类型

C语言和Java的不同就是,C语言没有true和false  只有0和非0

只要记住一句话即可,非0即true  0就是false

11,静态开辟

在函数局部内,创建的数据,在执行函数的时候会进栈操作,函数执行完毕,会执行弹栈。因此会释放栈内的成员,栈内的数据也称之为栈内成员,这种方式开辟的内存,称为静态开辟,执行完会弹栈。不会占用内存空间。

静态开辟,即在栈区开辟内存 
int a;
int arr[6];
char 'c';
等等操作都属于静态开辟内存
进栈
void staticAction() {
    int arr[5]; // 静态开辟 栈区 (栈成员)
} 
函数的末尾会弹栈(隐士):执行完毕会弹栈  会释放所有的栈成员
栈区:占用内存大小 最大值: 大概 2M  大于2M会栈溢出  平台有关系的
堆区:占用内存大小 最大值: 大概80%  40M没有任何问题,基本上不用担心 堆区很大的
大概80%: Windows系统 给我们的编译器给予的空间  的 百分之百八十

12,动态开辟

使用malloc函数,可以动态开辟内存,这种方式的空间属于在堆中开辟,函数执行完毕之后,不会释放堆空间,因此我们一定要手动释放free,并把指针指向NULL。避免悬空指针。

悬空指针:指针指向一块内存,如果这块内存稍后被操作系统回收(被释放),但是指针仍然指向这块内存,那么,此时该指针就是“悬空指针”

void *p = malloc(size);
assert(p);
free(p); 
// 现在 p 是“悬空指针”

正确的写法

void *p = malloc(size);
assert(p);
free(p); 
// 避免“悬空指针”
p = NULL;

野指针:是没有被初始化过的指针,所以不确定指针具体指向

void *p;  // 此时 p 是“野指针”

因为“野指针”可能指向任意内存段,因此它可能会损坏正常的数据,也有可能引发其他未知错误。在实际的C语言程序开发中,定义指针时,一般都要尽量避免“野指针”的出现,可通过赋初值方式解决:

void *p = NULL;
void *data = malloc(size);

下面再来讲讲动态开辟:

 int * arr = malloc(1 * 1024 * 1024); // 堆区开辟 4M

 free(arr); // 释放掉
 arr = NULL; // 重新指向一块内存地址00000
realloc:前面已经开辟的空间,使用realloc可以扩展空间大小,举例如下:
动态开辟一个大小为5的数组
int * arr = (int *) malloc(5);
for (int i = 0; i < 5; ++i) {
  arr[i] = (i + 10001); 
}

//使用realloc 将arr扩展为大小为11的数组
int * new_arr = (int *) realloc(arr, 5+6);

int j = 5; // 5开始
for (; j < (5+ 6); j++) { 
   arr[j] = (j + 10001);
}

别忘了释放
free(new_arr);
new_arr = NULL;

13,结构体

在C语言中,结构体相当于 java中的类

结构体的定义形式为


struct 结构体名
{
   成员列表(可以是基本的数据类型,指针,数组或其他结构类型)
};

例如:

struct Dog {
    // 成员
    char name[10];
    int age;
    char sex;

};
必须要在最后写;
struct Dog dog;
这样写完,成员是没有任何初始化的,成员默认值 是系统值,乱码

赋值操作
  
strcpy(dog.name, "旺财");
dog.age = 3;
dog.sex = 'G';

第二种写法:

struct Person {
    // 成员
    char * name; // 字符指针 = "赋值"
    int age;
    char sex;
} ppp = {"zhangsan", 33, 'W'};

结构体指针

struct Cat {
    char name[10];
    int age;
};

int main() { // 栈

    // 结构体
    struct Cat cat = {"小花猫", 2};

    // 结构体 指针    -> 调用一级指针成员
    struct Cat * catp = &cat;
    catp->age = 3;
    strcpy(catp->name, "小花猫2");
    printf("name:%s, age:%d \n", catp->name, catp->age);

    return 0;
}

结构体指针与动态内存开辟文章来源地址https://www.toymoban.com/news/detail-633592.html

struct Cat {
    char name[10];
    int age;
};

int main() { // 堆

    // VS的写法:Cat * cat = (Cat *) malloc(sizeof(Cat));
    struct Cat *cat = malloc(sizeof(struct Cat));

    strcpy(cat->name, "金色猫");
    cat->age = 5;

    printf("name:%s, age:%d \n", cat->name, cat->age);

    // 堆区的必须释放
    free(cat);
    cat = NULL;

    return 0;
}

14,结构体取别名

struct Student_{
    char name[10];
    int age;
    char sex;
};

typedef struct Student_Student_; // 给结构体取别名

typedef Student_* Student; // 给结构体指针取别名

到了这里,关于Android JNI--C语言基础的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android-JNI开发概论

    JNI的全称是Java Native Interface,顾名思义,这是一种解决Java和C/C++相互调用的编程方式。 它其实只解决两个方面的问题,怎么找到和怎么访问。 弄清楚这两个话题,我们就学会了JNI开发。 需要注意的是,JNI开发只涉及到一小部分C/C++开发知识,遇到问题的时候我们首先要判断

    2024年02月09日
    浏览(58)
  • Android串口开发之使用JNI实现ANDROID和串口通信

    导语:Android串口通信在物联网、智能家居等领域具有广泛的应用。本文将详细介绍如何使用JNI技术实现Android设备与串口的通信,包括串口的打开、设置参数和读写数据等过程。 在开始介绍Android串口开发之前,我们需要了解以下几个概念: JNI:JNI(Java Native Interface)是一种

    2024年02月07日
    浏览(48)
  • Android音视频开发实战02-Jni

    JNI是Java Native Interface的缩写,是Java提供的一种机制,用于在Java代码中调用本地(C/C++)代码。它允许Java代码与本地代码进行交互,通过JNI,Java应用程序可以调用一些原生库或者操作系统API,以获取更好的性能和更强的功能支持。 使用JNI需要编写一些Native方法,并将其实现在

    2024年02月11日
    浏览(55)
  • 【干货】Android系统定制基础篇:第十四部分(禁止第三方应用调用系统设置、增加TP配置、增加摄像头镜像设置、增加摄像头默认角度设置、修改默认语言)

    修改文件 frameworksbasecorejavaandroidappActivityManagerNative.java 如下: 属性配置: Android 主板定制过程中经常出现客户需要临时适配各种 TP(包括 USB TP),因此在设置菜单中加入 xy 交换,x 反转,y 反转常用配置,以客户多样性需求。 以下修改基于Android 8.1 SDK,如下: 属性配置

    2024年02月10日
    浏览(51)
  • Android Studio中使用cmake开发JNI实战

    JNI学习大纲 一、JNI编程入门 二、Android Studio中使用cmake开发JNI实战 第一章节我们介绍了JNI的开发步骤,那这一章节我们就开始在Android Studio中实战一下吧,Let\\\'s Start。 AS中菜单栏选择ToolsSDK Manager 在Android SDK中选择SDK Tools,安装CMake和NDK。 在项目工程下的src/main创建cpp目录,编

    2024年02月14日
    浏览(56)
  • 安卓Android Studio JNI开发问题澄清与汇总

    AndroidBitmap_lockPixels和AndroidBitmap_unlockPixels的底层逻辑就是在处理bitmap中的数据的时候,把内存锁定,防止像素缓存被改变导致数据变化。 这篇文章有具体介绍相关的机制 下面是Bitmap操作的示例代码: Java端代码: 使用时,可以直接调用NativeUtils中的processImage方法即可。当然,

    2023年04月09日
    浏览(58)
  • Android Java代码与JNI交互基础数据类型转换(三)

    🔥 Android Studio 版本 🔥  🔥 基础类型数据的转换 🔥 定义传递基础数据类型到Native的JNI接口函数 Native层创建callNativeInt 提供给Java调用 CMakeLists.txt 文件下配置动态库名称  添加 target_link_libraries 配置 Java调用Native层函数   运行打印日志 Java调用Native分别打印基础类型数据  下

    2024年02月13日
    浏览(43)
  • Android NDK开发详解之JNI中的库文件

    简介 本部分简要介绍了 NDK 的工作原理。Android NDK 是一组使您能将 C 或 C++(“原生代码”)嵌入到 Android 应用中的工具。能够在 Android 应用中使用原生代码对于想执行以下一项或多项操作的开发者特别有用: 工作原理 本部分介绍了在为 Android 构建原生应用时使用的主要组件

    2024年02月06日
    浏览(43)
  • Android问题笔记四十三:JNI 开发如何快速定位崩溃问题

    Unity3D特效百例 案例项目实战源码 Android-Unity实战问题汇总 游戏脚本-辅助自动化 Android控件全解手册 再战Android系列 Scratch编程案例 软考全系列 Unity3D学习专栏 蓝桥系列 ChatGPT和AIGC 专注于 Android/Unity 和各种游戏开发技巧,以及 各种资源分享 (网站、工具、素材、源码、游戏等

    2024年02月05日
    浏览(51)
  • Android Native Code开发学习(二)JNI互相传参返回调用

    本教程为native code学习笔记,希望能够帮到有需要的人 我的电脑系统为ubuntu 22.04,当然windows也是可以的,区别不大 native code就是在android项目中混合C++或者C语言进行开发,这样的好处是很多底层的东西需要使用C++/C的语言进行操作,而且在android开发中,使用C++和C混合开发能够

    2024年02月11日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包