JNI所需的C语言知识小结

介绍

作为Android开发人员,会java是必须的,但是一般从事android业务逻辑开发的对C/C++的了解估计仅限于大学里不走心的课程。。。所以参考视频和资料小结一下JNI所需的c语言知识~

基本数据类型

数据类型

boolean

byte

char

short

int

long

double

float

void

signed

unsigned

java

1

1

2

2

4

8

8

4

C

1

2

4

4

8

4

有符号

无符号

sizeof()函数是用来测量某个类型所占的字节长度,参数是某种数据类型。 c语言中0为假,非0表示真。

输入输出

输入

int i; // 可以不初始化
scanf("int i = %d \n",&i);   //&i  取i变量的地址

c语言中没有String类型,通过字符串数组来实现

 // 利用scanf %s 的方式 可以从键盘获取一个字符串
 char arr[10]={'h','e','l','l','o'};   
 printf("s = %s\n",arr);   //打印字符数组  
 scanf("%s",arr);   //利用字符数组接收一个字符串 

字符数组最后一位通常为’\o’,用来表示数组已经结束。

输出

int i = 0;
printf("int i = %d \n",i);//输出的通常格式

符号

代表的数据类型

%d

int

%ld

long int

%c

char

%f

float

%u

无符号数

%hd

短整形

%lf

double

%x

十六进制输出int或long或short

%o

八进制输出

%s

字符串

值得注意的是,如果把字符‘A’按照%d格式 输出那么就是:65 如果把int型的354353453用short型输出,结果为301,分析如下: 354353453为int类型,长度4个字节,其二进制数为: 10101000111110000000100101101 输出的结果为: 0000000100101101 与原来的二进制数后16位相同,实际上就是截断了后两个字节。

指针入门

什么是指针

指针(Pointer)就是内存的地址,C语言允许用一个变量来存放指针,这种变量称为指针变量。指针变量可以存放基本类型数据的地址,也可以存放数组、函数以及其他指针变量的地址。 程序在运行过程中需要的是数据和指令的地址,变量名、函数名、字符串名和数组名在本质上是一样的,它们都是地址的助记符:在编写代码的过程中,我们认为变量名表示的是数据本身,而函数名、字符串名和数组名表示的是代码块或数据块的首地址;程序被编译和链接后,这些名字都会消失,取而代之的是它们对应的地址。 以下为常用指针变量的含义:

定义

含义

int *p

p 可以指向 int 类型的数据,也可以指向类似 int arr[n] 的数组。

int **p

p 为二级指针,指向 int * 类型的数据。

int *p[n]

p 为指针数组。[ ] 的优先级高于 ,所以应该理解为 int (p[n]);

int (*p)[n]

p 为二维数组指针。

int *p()

p 是一个函数,它的返回值类型为 int *。

int (*p)()

p 是一个函数指针,指向原型为 int func() 的函数。

使用指针的注意事项

  1. 指针变量可以进行加减运算,例如p++、p+i、p-=i。指针变量的加减运算并不是简单的加上或减去一个整数,而是跟指针指向的数据类型有关。
  2. 使用指针变量之前一定要初始化,否则就不能确定指针指向哪里,如果它指向的内存没有使用权限,或者是程序运行所需的某个重要的值,修改之后,程序就崩溃了。对于暂时没有指向的指针,被成为“野指针”建议赋值NULL。
  3. 数组也是有类型的,数组名的本意是表示一组类型相同的数据。在定义数组时,或者和 sizeof、& 运算符一起使用时数组名才表示整个数组,表达式中的数组名会被转换为一个指向数组的指针。
  4. 指针的长度是4个字节,因为不管什么类型的指针,其本质都是地址,只要长度足够存放地址就可以了。

为什么要使用指针

  • 直接访问硬件 (opengl 显卡绘图)
  • 快速传递数据(指针表示地址)
  • 返回一个以上的值(返回一个数组或者结构体的指针)
  • 表示复杂的数据结构(结构体)
  • 方便处理字符串
  • 指针有助于理解面向对象

内存分配

静态内存分配

静态内存是系统程序编译执行后系统自动分配,由系统自动释放,静态内存是栈分配的,动态内存是堆分配的.

void function(int *p){
    int j = 0;
    p = &j;
    printf("p=%#X\n",p);
}

main(){
    int *p1;
    function(p1);
    printf("p1=%#X\n",p1); 
    system("pause"); 
}

把函数中的变量i的地址保存到main函数中的p1指针中,上面的代码是无法做到的,因为hanshu 中把i的地址赋值给了p指针,而这个指针是个局部变量了,fun方法一结束该指针就销毁了。并没有把i的地址赋值给p1。

动态内存分配

void fun(int** p2){ 
     int* p = (int*)malloc(4);
     /*malloc()接受一个参数 int 代表申请多少个byte的空间,该函数返回该空间的首地址。如果想保存一个int型数据,那么就可以申请4个字节来保存int。(int*)强转,是为了说明这个空间返回的地址是保存int型指针类型的。 */ 
     printf("&i=%#X\n",p);
     *p = 5;
     *p2 = p; 
} 

main(){ 
     int* p1;
     fun(&p1); 
     printf("p1=%#X\n",p1);  
     printf("p1保存的地址保存的值为%d\n",*p1); 
     /*结果为5,因为这个5是在堆内在中申请的,自组织系统不会自动释放,需要我们手动释放。在fun方法的代码最后加上:free(p);  则这时main方法中就打印不出正确的5了。*/
     system("pause");       
     //free(p);
} 

注意: char* p1 = (char *)malloc(10) 这句代码其实是分两部分执行的,这一整句代码总共申请了14个字节,左边申请了一个4个字节大小的指针变量,右边申请了10个字节用于保存字符。

杂项

函数指针

函数名在表达式中有时也会被转换为该函数所在内存区域的首地址,我们可以把函数的这个首地址(或称入口地址)赋予一个指针变量,使指针变量指向函数所在的内存区域,然后通过指针变量就可以找到并调用该函数。这种指针就是函数指针。 定义形式:

returnType (*pointerName)(param list);

使用范例:

#include <stdio.h>
//返回两个数中较大的一个
int max(int a, int b){
    return a>b ? a : b;
}
int main(){
    int x, y, maxval;
    //定义函数指针
    int (*pmax)(int, int) = max;  //也可以写作int (*pmax)(int a, int b)
    printf("Input two numbers:");
    scanf("%d %d", &x, &y);
    maxval = (*pmax)(x, y);
    printf("Max value: %d\n", maxval);
    return 0;
}

结构体

类似java里面的类,形式为:

struct 结构体名{
    结构体所包含的变量或数组
};//记得加分号

比如一个学生结构体

struct stu{
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    char group;  //所在学习小组
    float score;  //成绩
};

//写法二,定义了一个别名
struct stu{
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    char group;  //所在学习小组
    float score;  //成绩
} stu1, stu2;

//写法三
struct{  //没有写 stu
    char *name;  //姓名
    int num;  //学号
    int age;  //年龄
    char group;  //所在学习小组
    float score;  //成绩
} stu1, stu2;

结构体使用点运算符获得成员变量。

联合体

定义格式为:

union 共用体名{
    成员列表
};

结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。 共同体的定义与结构体类似:

union data{
    int n;
    char ch;
    double f;
};
union data a, b, c;

typedef

声明自定义数据类型,配合各种原有数据类型来达到简化编程的目的的类型定义关键字。

typedef struct stu{
    char name[20];
    int age;
    char sex;
} STU;

STU body1,body2;
//等价于:
struct stu body1, body2;

枚举

enum WeekDay { 
    Monday=8,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday }; 

int main(void) { 
  enum WeekDay day = Sunday; 
  printf("%d\n",day);   //打印结果为14,因为Monday为8,Tuesday就是9,一直到Sunday是14  
  system("pause");
  return 0;
} 
//如果需要定义连续的一串数据就可以使用枚举

枚举类型大小和int型一样,都占用4个字节。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据科学学习手札

(数据科学学习手札48)Scala中的函数式编程

  Scala作为一门函数式编程与面向对象完美结合的语言,函数式编程部分也有其独到之处,本文就将针对Scala中关于函数式编程的一些常用基本内容进行介绍;

1104
来自专栏Java帮帮-微信公众号-技术文章全总结

【Java提高三】三大特性-多态

【Java提高】三大特性-多态 面向对象编程有三大特性:封装、继承、多态。 封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构...

3579
来自专栏企鹅号快讯

轻松学习Python:基础知识汇总

Python基础01 Hello World! Python命令行 假设你已经安装好了Python, 那么在命令提示符输入: python 将直接进入pytho...

1728
来自专栏LanceToBigData

JavaSE(一)之类与对象

终于到了要学习面向对象程序设计了,其中可能很多东西以前都知道怎么去用,但是却不知道怎么来的,或者怎么样写会出错,所以今天总结起来。 一、OOP概述   Java...

1855
来自专栏塔奇克马敲代码

第2章 变量和基本类型

1874
来自专栏赵俊的Java专栏

合并排序数组

1571
来自专栏微信公众号:Java团长

理解Java的三大特性之多态

封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方...

621
来自专栏我爱编程

Day5函数式编程1/3

高阶函数 map map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返...

2788
来自专栏彭湖湾的编程世界

【数据结构】实现字典API:有序数组和无序链表

参考资料 《算法(java)》                           — — Robert Sedgewick, Kevin Wayne 《数据结...

2665
来自专栏Python爱好者

Java基础笔记17

1246

扫码关注云+社区