(三)JNI学习之C语言基础,指针

来源:互联网 发布:在淘宝怎么设置优惠券 编辑:程序博客网 时间:2024/05/01 08:07

指针 这个名词对大家来说一定不陌生,虽然可能具体是怎么回事,但多少身为程序员的我们一定是听说过,而且对于我们孤傲高冷的程序猿,在还是单身狗的情况下往往会被人戏说:你这个没有对象的野指针。哈哈,总之,指针对于C语言来讲是最基本的,但运用起来也是有难度的,下面我们就简单说一下C语言指针。

我们知道,C语言是面向过程的,没有类对象之分,对于指针来说,我们通俗的可以这么去给它一个定义。

1、指针:就是用来存放其他变量的内存地址的。这里需要记住的是,指针变量仅仅是用于存放其他变量的地址的。

下面我们还是通过代码,先来观察指针的一个基本用法:

#include<stdio.h>//引入头文件void main(){int a = 1;int* ap = &a;//定义指针变量ap,int*的意思是声明一个指向int型变量的指针变量,&的意思是取a的地址 printf("%p\n",ap);//打印变量a的地址 printf("%p\n",&ap);//打印指针变量ap的地址 /*分别声明不同类型的指针变量,用于指向特定类型的变量的地址分别打印这些不同类型的指针变量的所占内存的大小,即长度 */char* cp;float* fp;double* dp;short* sp;printf("%d\n",sizeof(ap));printf("%d\n",sizeof(cp));printf("%d\n",sizeof(fp));printf("%d\n",sizeof(dp));printf("%d\n",sizeof(sp));//拿到一个变量的指针就可以修改该变量的值*ap = 60;printf("%d\n",a); } 
输出结果是:

0060FF0C
0060FF08
4
4
4
4
4
60
我们现在简单讲解一下上面的代码,其实上面的注释已经写的很清楚了,指针变量也是变量,md这是在说什么。我们在是用之前要声明,如果该指针变量指向的int型的变量,那该指针变量就声明称int*,指向char类型的变量就声明成char*,这个很好理解,然后我们说过,指针变量存放的一定是某个变量的地址,因此我们取a的地址,也就是&a,然后赋值给指向int型变量的指针变量ap,最后我们打印出了int变量a的地址,也就是ap,也打印出了该指针变量ap的地址(ap也是变量,要存放在内存的某个区域,当然有地址。)另外打印输出地址的格式化符号是%p。

后来我们分别检测了各种类型指针变量的长度,长度都是4,这也不难理解,指针变量无论是指向了什么数据类型,最终还是用来存放地址的,与数据类型无关。

再看,我们通过改变ap变量指向内存地址的具体值,也就是改变a的值来进行输出。其中需要注意的是*ap指的是ap记录地址所指向的变量的值。

接下来,我们要做的事是,利用指针来交换两个数的值。在这之前,我们先来回忆一下我们在使用java的时候是怎样进行两个值的交换的。看代码:

#include<stdio.h>//引入头文件void  main(){int a = 1;int b = 2;int temp;//方法一:/* temp = a; a = b; b = temp; printf("交换后的结果是:a = %d b = %d\n",a,b); */  //方法二: a = a ^ b; b = a ^ b;//b = a ^ b ^ b,也就是:b = a;我们知道一个数异或同一个数两次还是同一个数  a = a ^ b; //a = a ^ b ^ a,也就是:a = b;  printf("交换后的结果是:a = %d b = %d\n",a,b);
也就是说,利用java常用的做法,通过代码中的方法一和方法二,在C中我们都能实现两个数值的交换。但是通常在java中我们不这么写,往往将交换的行为抽成一个方法,然后在用到的时候来调用它即可,写法是这样的:

#include<stdio.h>//引入头文件void exchange(int x,int y);/*实现两个数的交换 */void  main(){int a = 1;int b = 2;exchange(a,b);        printf("交换后的结果是:a = %d b = %d\n",a,b);}void exchange(int x,int y){x = x ^ y;y = x ^ y;x = x ^ y;}
这是我们java中的思想,抽取某一个方法,为了复用,但是这种方法真的能交换a和b的值吗?我们先来看下执行结果:

交换后的结果是:a = 1 b = 2

显然,并没有完成a与b的交换,那么是为什么呢?这里,其实我们的话题偏转了啊,引出了java中的值传递问题。我们知道,exchange方法接收两个参数,在这里,a与b分别传递给这个函数的两个参数,确是如此,但是它的传递过程我们应该画个图来讲解:


我想上面的图写的已经很明确了,这里就不多做解释了。另外还有一点就是,在上一段代码的开始我们先声明了一个类似于java接口一样的exchange方法,然后才可以调用,那是因为,在C语言中,代码的执行逻辑是从上往下执行的,在main中我们调用了exchange方法在没声明之前会找不到方法,所以可以把exchange方法写到开头,也可以像我写的那样,先通过定义一下(像java声明一个接口),然后在调用的时候会自动去找它的实现。

好了,外传拉了这么多,我们终于要通过指针的操作来实现我们的数据交换了,依然看代码:

#include<stdio.h>//引入头文件void exchange(int* x,int* y);/*实现两个数的交换 */void  main(){int a = 1;int b = 2;exchange(&a,&b); printf("交换后的结果是:a = %d b = %d\n",a,b);}void exchange(int* x,int* y){*x = *x ^ *y;*y = *x ^ *y;*x = *x ^ *y;}

实现起来依然是那么简单,在exchange方法中我们传递的是变量的地址,也就是参数声明为指针变量,然后将对应的指针变量指向的地址里的值进行交换,直接操纵的是变量的地址,实现数据的更改,就是这么直接暴力。下面我们也通过一个简单的内存图来解释一下其中的传递方式:


这里图中也解释了为什么传递地址可以达到预想效果。

2、多级指针:接下来,我们再来说一下C语言的多级指针,看代码:

#include<stdio.h>void main(){int i = 1;int* p1 = &i;int** p2 = &p1;int*** p3 = &p2;int**** p4 = &p3;printf("输出i的值是:%d\n",i);printf("输出i的值是:%d\n",*p1);printf("输出i的值是:%d\n",**p2);printf("输出i的值是:%d\n",***p3);printf("输出i的值是:%d\n",****p4);***p3 = 2;printf("输出i的值是:%d\n",i);}
最后输出结果为:

输出i的值是:1
输出i的值是:1
输出i的值是:1
输出i的值是:1
输出i的值是:1
输出i的值是:2

多级指针就是一级一级的记录指针的地址值,而指针里一层一层的引用着其他的地址值,通过这种方式一层一层的去查找找到也可以起到修改变量的目的.

3、指针函数:其实就是指向函数的一种指针,因为在内存中函数也是占内存的,既然占内存就说明函数有内存地址,有地址了就会有一种类型的指针去记录这种地址。

函数指针就是干这个的。在C中,我们可以通过函数的地址去访问这个函数。

先来一个例子演示:

#include<stdio.h>int add(int a,int b){int i = a + b;printf("相加的结果是:%d\n",i);return a + b;}int minus(int a,int b){int i = a - b;printf("相减的结果是:%d\n",i);return a - b;}int calculate(int a,int b,int(*func)(int,int)){return func(a,b);}void main(){add(5,6);minus(8,6);printf("函数add的地址是:%p\n",add);printf("函数minous的地址是:%p\n",minus);//指针函数的定义 ,指针函数其实就是指向函数的指针,这个指针里面记录的是函数的地址 int(*func)(int,int);func = add;printf("输出结果是:%d\n",func(1,2));func = minus;printf("输出结果是:%d\n",func(6,2));printf("调用结果是:%d\n",calculate(10000,2000,add));}
函数指针的定义方法就是:用一个括号(*名称)(参数1...参数n);

我们定义的这个名称就是一个指向函数地址的变量,看代码发现,我们可以直接通过打印方法名来输出这个方法(函数)的地址。所以我们用定义的名称来引用这些方法。

我们还发现函数指针可以当做参数为一个方法声明参数。这是java所不能的。



原创粉丝点击