基础知识
C语言中,*
和&
是操作指针的符号。什么是指针呢,首先我们先要了解内存的概念。
一台基本的电脑是由:输入输出设备(键盘、鼠标、显示屏,但是没有他们电脑也是可以工作的)、CPU、内存、硬盘、显卡组成的。
- CPU:大家都知道它是中央处理器,是电脑的核心,是计算机的大脑。
- 硬盘:它是记录数据用的,它是一种储存器,准确的说是非易失性储存器,简而言之就是我们的数据能在硬盘中长期保存,不会因为断电而丢失。
- 内存:其用处和硬盘差不多,但是区别在于它是一种易失性储存器,一旦断电,储存在里面的数据就都将丢失,不过它的速度却比传统的机械硬盘快20多倍,因此存放一些程序要临时用到的变量就非常合适。
我们知道,C语言的变量是存在内存里面的,而内存被分为了好多个基本单位,地址
就是赋予每个基本单位的唯一标号。简单的说,一个地址对应了一块小内存。
当我们定义变量时
int a = 10;
这样我们就在内存中开扩了一块空间,并把这块内存中存入数据10。
有前面关于地址
的概念之后,我们就能想到,如何读取到该变量的地址呢?
而符号&
便是这个含义。
&
取址符号:用于将一个变量的地址取出来。
例子:
#include <stdio.h>
int main()
{
int a = 10; // 定义一个变量,并赋值为10
printf("%p",&a); // %p用于打印地址,而后面的&a就是用来取出a的地址的。
}
根据例子,我们便能理解&
(取址符号)的含义了。
但是&
还有另一个含义,那便是引用。
引用,其实我们可以这么理解,它可以是一个变量的别名,也就是说一块内存有两个名字(不是地址,地址只能有一个,我指的是变量名字)。下面的那个例子很好的说明了这一切:
#include <stdio.h>
int main()
{
int a = 10; // 先定义a变量
int &b = a; // 把a引用到b来
// int &c; // 这句话错误,使用引用是必须初始化,指定其引用的对象。
printf("a = %d, b = %d\n", a, b); // 很显然,他会输出a = 10, b = 10
a = 20; // 我们对a进行赋值操作
printf("a = %d, b = %d\n", a, b); // 他输出了a = 20, b = 20
b = 30; // 同样的,我们在对b进行赋值操作
printf("a = %d, b = %d\n", a, b); // 他输出了a = 30, b = 30
/// 这也就说明,a和b是绑定的,动其中的一个,那么另一个一定也会随之改变。
/// 那么也就可以说b是a的一个别名,另一个名称。
printf("&a = %p, &b = %p\n", &a, &b); // 输出的地址是一样的
return 0;
}
注释已经写的很详细了,相信大家一定能看懂的。
而实际上,我们也能这么理解。通过上面的例子的最后一句输出可以看出a变量和b变量同时指向了同一块内存,他们的地址实际上是相同的,所以,我们在对a变量进行更改的时候就是指操作了这块内存的内容,而操作b时,我们动的也是这块内存,所以他们才会表现出这样的效果。
*
取值符号:当我们有了一个地址的时候,我们又想知道这个地址对应的内存里存的是什么呢,那么取值符号就可以达到这个目的了。
下面的例子就能解释这个意思了:
#include <stdio.h>
int main()
{
int a = 10;
printf("%d",*&a); // 我们先用&a将a变量的地址取出来,然后我们再在最前面加上*取值符号,这时候输出的便又是我们的数字了。
return 0;
}
但是这样是不是很没用,感觉特别鸡肋?
所以我将介绍*
的另一个用法。
int a = 10;
int* b = &a;
我们之前了解了地址的概念,但是地址本身也是可以存到变量当中的,而b变量便是一个指针变量,用于存放指针(地址)。
这样说不好理解,不如这样讲吧。学过变量类型我们知道有char
, int
, long
, float
, double
等几种常见的类型,那么定义变量时就会开启一块内存空间来储存。那么每种类型也对应着一种类型的内存空间,而int
对应的指针变量类型便是int*
,double
对应的则是double*
,其实就是在每种类型后面加一个*
就行了。
而指针类型的变量存的就是地址
,所以我们定义指针变量便可以像例子中那么写了。
不过,定义指针变量的方法还有一个,并且我更推荐大家这么写,因为区分度较高:
int a = 10;
int *b = &a; // 推荐使用这种写法
int* c = &a;
其实就是空格的位置变了下。
这样一来,*&就便有了意义。
由于b和c变量存的是a的地址,那么我们用b和c去对啊进行赋值的时候也有些不一样,先要用*
对b或c变量进行取值,把a取出来之后才能对a进行赋值操作。详情请看例子。
printf("%p",b); // 由于b存的是a的地址,所以这边就打印了a的地址
*b = 20; // 这句话相当于进行了a = 20;操作
printf("%d",*b); // *b是读取b地址里存的值,也就是a的数值
顺便题下,初学者在学输入语句scanf("%d",&a);
时往往无法理解&
的含义,而现在应该能懂了吧,人家是取出a的地址,然后用*
取出值来修改啊。
在函数中的应用
首先我们先来看个例子吧:
#include <stdio.h>
void func1(int num)
{
num = 1;
}
void func2(int *num)
{
*num = 1;
}
void func3(int &num)
{
num = 1;
}
int main()
{
int a = 0, b = 0, c = 0;
func1(a);
func2(&b);
func3(c);
printf("a = %d, b = %d, c = %d\n",a, b, c);
return 0;
}
咋一看,这个例子想实现的应该是同一个功能,那就是通过函数,把数字变成1。
但实际运行时,他却输出了a = 0, b = 1, c = 1
的结果,和预期并不一样啊,在这是为什么呢。
其实,我们观察每个函数的定义时就能发现略有不同了。
首先,我们先看func1
的定义:
void func1(int num)
{
num = 1;
}
它的参数是int num
,也就是说它传入的是数值,并把它赋值给了变量num,简单地讲就是我们在main函数传入的a,会把它复制给num,彻彻底底的两个变量啊!
所以说,这个函数并不会改变a的值,顶多也是改变了num这个形式参数的值罢了,并没有动到传入的a这个实际参数。
我们再看看第二个函数:
void func2(int *num)
{
*num = 1;
}
根据之前学习的*
的用法我们知道,这里的num变量是用来存储地址的,也就是说这个函数传入的参数是一个地址。
在main方法中,我们传入的是&b,也就是将b进行取址之后传入的。
那么num就便是b的地址了,我们再进行*num = 1;
的操作时相当于把在num里的地址进行*
取值运算,把b取了出来,在对它进行赋值为1。
这样一来,b的数值就发生了实质性的变化,且num并没有变化。
最后一个函数:
void func3(int &num)
{
num = 1;
}
这边其实就和之前的引用是一样的了。我们引用main中传入的c,并让num变量也指向c的地址,所以我们再进行num = 1;
操作的时候。就把num所指向的地址里的数值进行了修改,也就是修改了c的值。
总结
读完本文大家应该能对C语言里*
和&
有了一个新的理解了,同时我也希望本文能帮助到之前对指针一脸懵逼的初学者。