(三)JNI学习之C语言基础,指针
2017-08-04 09:56
387 查看
指针 这个名词对大家来说一定不陌生,虽然可能具体是怎么回事,但多少身为程序员的我们一定是听说过,而且对于我们孤傲高冷的程序猿,在还是单身狗的情况下往往会被人戏说:你这个没有对象的野指针。哈哈,总之,指针对于C语言来讲是最基本的,但运用起来也是有难度的,下面我们就简单说一下C语言指针。
我们知道,C语言是面向过程的,没有类对象之分,对于指针来说,我们通俗的可以这么去给它一个定义。
1、指针:就是用来存放其他变量的内存地址的。这里需要记住的是,指针变量仅仅是用于存放其他变量的地址的。
下面我们还是通过代码,先来观察指针的一个基本用法:
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的时候是怎样进行两个值的交换的。看代码:
交换后的结果是:a = 1 b = 2
显然,并没有完成a与b的交换,那么是为什么呢?这里,其实我们的话题偏转了啊,引出了java中的值传递问题。我们知道,exchange方法接收两个参数,在这里,a与b分别传递给这个函数的两个参数,确是如此,但是它的传递过程我们应该画个图来讲解:
我想上面的图写的已经很明确了,这里就不多做解释了。另外还有一点就是,在上一段代码的开始我们先声明了一个类似于java接口一样的exchange方法,然后才可以调用,那是因为,在C语言中,代码的执行逻辑是从上往下执行的,在main中我们调用了exchange方法在没声明之前会找不到方法,所以可以把exchange方法写到开头,也可以像我写的那样,先通过定义一下(像java声明一个接口),然后在调用的时候会自动去找它的实现。
好了,外传拉了这么多,我们终于要通过指针的操作来实现我们的数据交换了,依然看代码:
实现起来依然是那么简单,在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);
4000
//指针函数的定义 ,指针函数其实就是指向函数的指针,这个指针里面记录的是函数的地址
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所不能的。
我们知道,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);
4000
//指针函数的定义 ,指针函数其实就是指向函数的指针,这个指针里面记录的是函数的地址
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所不能的。
相关文章推荐
- C语言基础学习3:指针
- C语言基础学习——第5天(指针)
- (二)JNI学习之C语言基础,控制语句
- C语言基础学习之指针操作字符串反转
- C语言基础学习6: 指向函数的指针
- 奶爸业余单片机学习之:C语言基础——指针(指针变量)学习笔记
- (一)JNI学习之C语言基础,基本数据类型
- c语言基础学习07_指针
- 黑马程序员——C语言基础学习(四)---数组和指针的总结学习
- C语言基础学习5:字符串与指针
- 从Android/Java基础之上学习C/C++语言(2)--C语言基础--指针
- C语言基础学习8:指针数组
- (五)JNI学习之C语言基础,typedef与宏定义
- 奶爸业余单片机学习之:C语言基础——指针(指针变量)学习笔记之二
- C语言基础及指针⑩预编译及jni.h分析
- C语言基础学习4:数组与指针
- C语言基础学习7:返回指针值的函数
- 【C/C++语言基础学习】在主函数的定义的指针数组、二维数组通过三级指针在被调用函数分配内存
- C语言基础学习9:指向指针的指针
- (四)JNI学习之C语言基础,构造类型