首页 技术 正文
技术 2022年11月20日
0 收藏 632 点赞 4,058 浏览 2890 个字

  在上一个blog学习了&运算符,使用&取了变量、数组等地址,有什么用那?如果能够将取得的变量的地址传递给函数,能否通过这个地址在函数内访问到外部这个变量?答案是肯定的,scanf(“%d”,&i)就是一个C语言的函数,另外我们试了,将地址交给一个整数,这个事情不靠谱,因为整数和地址不见得总是类型一致,那么什么样的类型可以接收取地址得到的地址那?指针!

指针的定义

  指针类型的变量就是保存地址的变量,就是保存&运算符取得的其他变量的地址的一个变量:有int i,就可以做出一个int *p,这个*星号表示p是一个指针,(通常使用p表示指针,因为p是pointer指针的第一个字母),int *是说p是一个指针,它指向的是一个int,现在把i的地址交给p。

int i;
int *p = &i;

  也就是说我们原本有个变量i,现在我们又有一个变量p,变量p是一个指针,它里面的值是i的地址,比如说i的地址是0x2000,那么p的值就是2000,在这种情况下我们可以说,p指向了i。所以我们在说p指向了i,也就是再说变量p里的值是i的地址。

  指针变量中*的位置。在定义指针的时候,有下列两种写法:*靠近int或者*靠近p。第一种,虽然*靠近int,但是并不是把*加给了int,而是把*加给了p,*p是一个int,于是p是一个指针了,而并不是说p是int*类型的,在C语言中没有int*这个类型,只是说*p是一个类型,不管*是靠近int还是靠近p,意思都是一样的。

int* p;
int *p;

  在看一个例子:通过上一个例子,我们知道int *和int*意思是一样的,都是说p是一个指针,那么q是什么?q只是一个普通类型的int类型的变量,换句话说并不是说把*加给了int,是把*加给了p。如果想要表达p和q都是指针,应该在q前也加一个*。

int* p,q;
int *p,q;

  所以我们有了指针变量,变量里值是内存的地址,这个地址会指向另外一个变量,普通变量里面放的内容是一个实际的值,在指针里面不会放实际的值,只会放别的变量的地址,int *p,p里只会有别的整数的地址。

作为参数的指针

  当将一个指针作为一个函数参数的时候,就可以这么写:void f(int *p),当调用时则需要交给它一个地址:int i=0,f(&i),而不能传递给它这个变量本身或者这个变量的值,我们需要使用&运算符将这个变量的地址传给这个指针,让我们编程试一试这件事情:

 #include <stdio.h>
void f(int *p); int main(void) {
int i=6;
printf("&i=%p\n",&i);//在main里有一个i的变量,在main里打印出i的地址,看下地址是多少
f(&i); //然后把i的地址取出来交给f函数
return ;
} void f(int *p){
printf(" p=%p\n",p); //在f函数里,打印出p的值看下是多少
}

  看下结果:i的地址是4c,取出来传给f函数,在f函数里这个函数也是4c。这就意味着在main里有个变量i的值是6,地址是4c,然后我们把这个地址取出来交给了f函数里变量p,p的值是4c,于是我们可以说p是一个指针,指向i这个变量。

听翁恺老师mooc笔记(3)–指针的定义

  这就意味着在f函数里面,有外面的main里面的变量i的地址,我们不知道它叫做i,但是我们有它的地址,如果不是这样子传一个地址进去,可能只能得到它的一个值,比如再加入一个g函数,输入是一个int数,将i的值传进去:

 #include <stdio.h>
void f(int *p);
void g(int k); int main(void) {
int i=;
printf("&i=%p\n",&i);
f(&i);
g(i); //再main里调用g函数,将i传递过去给g函数
return ;
} void f(int *p){
printf(" p=%p\n",p);
} void g(int k){ //g函数,输入是一个整型数k
printf(" k=%d\n",k);
}

听翁恺老师mooc笔记(3)–指针的定义

  在这个过程当中,在函数g里得到只是i的值,和外面main里的变量i之间没用直接的关系。这是我们之前学函数的时候学到的。现在我们通过这个指针变量p得到了变量i的地址,这使得f函数里拥有可以访问外面这个这个变量的能力了,怎么访问?访问意味着读或者写,读是访问,我们可以读到这个值,写那?写是修改i变量的值,怎么写?如果有一个地址,你想访问这个地址上的变量,那么需要用到一个运算符,*。

*运算符

  *不是一个新的运算符,在做乘法的时候我们使用*进行乘法。现在需要把这个*当作一个新的运算符,一个单目的运算符,只有一个操作数,我们用它来访问指针的值所表示的地址上的变量。那么我们使用*号加上指针得到的变量的值之后那,这个变量可以拿来做左值,也可以用来做右值,也就是我们既可以拿来放在等号左边去写这个值,也可以放在等号的右边去读这个值。下面来试一试这个值该怎么做:

 void f(int *p){
printf(" p=%p\n",p);
printf("*p=%d\n",*p);//在f里打印*p的值,这里一定要有个概念就是说,*号和p放在一起,那么*p这个整体可以看成一个整数
}

  将*p当成一个整数,和之前讲数组时,可以将一个数组a[10]当成一个整体也就是一个整数来看一样。现在输出这个整数的值,运行的结果是*p=6,所以这就意味着,通过p这个指针我们得到了f函数外面变量i的值,也就是读除了这个变量的值。那么我们试下写入:

 void f(int *p){
printf(" p=%p\n",p);
printf("*p=%d\n",*p);
*p = ;
}

  在f函数里往*p=26,那么这样能否修改main里i的值那,如果i的值改变了,那么g函数中的k的值也应该改变了,运行程序发现确实如此。这就意味着,经过f函数调用之后,i的值改变了。我们在讲函数的时候一再说,c语言的函数在调用时发生的参数的转移是一种值的传递,我们把值传进了函数,所以函数和调用它的地方没用任何的联系,现在情况有点不一样了,但是我们仍然坚持说,现在这个传递依然是值的传递,地址值被传进了函数,但是因为传进来的是地址,所以通过这个地址在函数内部可以以*p的方式访问到外面的变量的值:p是i的地址,*p就是i的值。我们在对*p赋值的时候,实际上是在做左值。

  左值之所以叫左值,是因为出现在赋值号左边的不是变量,而是值,是表达式计算的结果,*p=3,*p是取得地址表示得变量得值,这是表达式运算得结果,可以放在赋值号左边作为一个左值进行赋值。数组a[0]=10,中括号也是一个运算符,取下标的运算符,赋值号左边也是一种运算,运算的结果放在赋值号的左边,可以接受值。所以这是为什么我们叫左值,而不是在赋值号的左边就叫做变量,因为a[0]不是变量,*p也不是变量,他们是表达式运算的结果,所以说再赋值号的左边是左值,在赋值号的右边是右值,这是值,这不是变量。

  目前为止我们看了指针的两个运算符,一个是取地址运算符,一个是取地址所代表变量的值,这两个运算符是相互反作用的。 

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,961
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,485
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,330
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,113
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,746
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,780