指针是C语言最重要(有时也是最复杂的)概念之一,用于存储变量的地址。从根本上看,指针(pointer)是一个值为内存地址的变量。正如 int 类型的值是整数,指针变量的值是地址。
一、两个运算符
1,一元运算符&:
一元运算符&给出变量的存储地址。如果pooh是变量名,那么&pooh是变量的地址。可以把地址看作是变量在内存中的位置。
int pooh = 24;
// 地址通常用十六进制形式来表示
printf("%d %p",pooh,&pooh);
将输出下面的内容(%p是输出地址的转换说明):
24 0060FEFC
假设一个指针变量名是ptr,可以编写如下语句:
prt = &pooh; // 把 pooh 的地址值赋给ptr
对于这条语句,我们说 ptr 指向 pooh。 ptr 和&pooh 的区别是 ptr 是变量,&pooh 是常量。 或者, ptr 是可修改的,而&pooh是不可修改的。还可以把 ptr 指向别处:
ptr = &bah; // 把ptr 指向bah, 而不是pooh
现在ptr 的值是bah 的地址。
2,间接运算符 *
要创建指针变量,先要声明指针变量的类型。假设想把ptr声明为储存int 类型的变量地址的指针,就要用到 * 运算符。
假设已知 ptr 指向了 bah。
然后使用间接运算符 * 找出储存在bah 中的值。
ptr = &bah; // 把ptr 指向bah
val = *ptr; // 找出ptr指向的值
上面两个语句放在一起相当于语句:
val = bah;
小结
① & 后跟一个变量名时,&给出该变量的地址;
② * 后跟一个指针名或地址时,* 给出储存在指针指向地址上的值。
把这两个运算符搞明白就可以看下面的内容了。
二、基本类型的指针
指针就是地址,地址就是指针。
int * p; // p是个变量名字,int * 表示p变量只能存储int类型变量的地址
int i = 10;
int j;
p = &i; // p存放了i的地址,就说p指向 i
j = *p; // 等价于 j = i , 所以 i = j = *p
当p保存了i的地址,p就指向i;修改p的值不影响i的值,修改i的值不影响p的值;*p就是i。
指针变量也是变量,只不过它不能存放内存单元的内容,而是内存单元的地址。
三、函数问题
如何通过被调函数修改主调函数中普通变量的值
(1) 实参为相关变量的地址
(2) 形参为以该变量的类型为类型的指针变量
(3) 在被调函数中通过 *形参变量名 的方式就可以修改 主函数中变量的值
// 形参为int类型的指针变量
void f(int * p) //不是定义一个名字叫*p的形参,而是定义了一个名字叫p的int*类型的形参,p指向了i
{
*p = 100; // 此时*p就是i
}
int main(void)
{
int i = 9;
f(&i); //实参为i的地址
printf("i = %d", i); // 输出 i = 100
return 0;
}
四、指针与数组
一维数组的数组名字,其实是一个指针常量,存放的是一维数组的第一个元素的地址,一维数组名指向数组第一个的元素
int main(void)
{
int a[5] = {1,2,3,4,5}; //一维数组名a是一个指针常量,存放的是a[0]的地址
// a[i] 等价于 *(a+i)
// a[3] == *(a+3);
printf("%d",*a+3); // 4
return 0;
}
如何通过被调函数修改主调函数中一维数组的内容
两个参数:存放数组首元素的指针变量;存放数组元素长度的整型变量
void Show_Array(int *p , int len) // p是一个int*类型的变量(地址), a的值传给了p,p就等价于a
{
//p[2] = -1; // p[2] == *(p+2) == *(a+2) == a[2]
// p[i]就是主函数的a[i]
for(int i=0;i<len;i++)
printf("%d ",p[i]);
}
int main(void)
{
int a[5] = {1,2,3,4,5};
Show_Array(a,5); // a等价于&a[0],&a[0]本身就是int*类型
return 0;
}