终于到了精髓的地方了,这确实有点懵,总感觉这太麻烦了,而且写着也不爽,还是怀念py或者java,但也没办法,还是要继续学下去。
一、运算符&
- scanf("%d" , &i); 里的&
- 获取变量的地址,它的操作数必须是变量
- 地址的大小是否与int相同取决于编译器
#include <stdio.h>
int main(void)
{
int i = 0;
printf("0x%x\n", &i);
// 0x62fe4c
return 0;
}
&不能取的地址
&不能对没有地址的东西取地址
- &(a+b) ?
- &(a++) ?
二、指针
- 如果能够将获得变量的地址传递个一个函数,能否通过这个地址在那个函数内访问这个变量?
- scanf("%d" , &i);
- scanf()的原型应该是怎样的?我们需要一个参数保存别的变量的地址,如何表达能够保存地址的变量
指针
就是保存地址的变量 , *p
// p是一个指针,现在把i的地址交给了p
int i;
int* p = &i;
// 下面两种形式一样,p是一个指针,而q是一个普通的int变量
int* p , q;
int *p , q;
指针变量
- 变量的值是内存的地址
- 普通变量的值是实际的值
- 指针变量的值是具有实际值的变量的地址
作为参数的指针
- void f(int *p);
- 在被调用的时候得到了某个变量的地址
- int i = 0;f(&i);
- 在函数里面可以通过这个指针访问到外面的的这个i
#include <stdio.h>
void f(int *p);
int main(void)
{
int i = 6;
printf("&i=%p\n", &i);
f(&i);
return 0;
}
void f(int *p)
{
printf(" p=%p\n", p);
}
// 可以看到这里获取的地址是相同的
// &i=000000000062FE4C
// p=000000000062FE4C
访问那个地址上的变量*
- *是一个单目运算符,用来访问指针的值所表示的地址上的变量
- 可以是右值也可以是左值
- int k = *p;
- *p = k + 1;
*左值之所以叫左值
- 是因为出现在赋值号左边的不是变量,而是值,是表达式计算的结果
- a[0] = 2;
- *p = 3;
- 是特殊的值,所以叫左值
#include <stdio.h>
// 声明两个函数
void f(int *p);
void g(int k);
int main(void)
{
int i = 6;
printf("&i=%p\n", &i);
f(&i);
// 此时i的值已经发生了变化
g(i);
return 0;
}
// 传入的是地址
void f(int *p)
{
printf(" p=%p\n", p);
printf("*p=%d\n", *p);
*p = 66;
}
// 传入的普通int
void g(int k){
printf("k=%d\n", k);
}
// &i=000000000062FE4C
// p=000000000062FE4C
// *p=6
// k=66
三、指针的使用
指针应用场景一
交换两个变量的值
#include <stdio.h>
void swap(int *pa , int *pb);
int main()
{
int a = 5;
int b = 10;
swap(&a , &b);
printf("a=%d , b=%d\n", a , b);
return 0;
}
void swap(int *pa , int *pb){
int t = *pa;
*pa = *pb;
*pb = t;
}
指针应用场景二
- 函数返回多个值,某些值就只能通过指针返回
- 传入的参数实际上是需要保存带回的结果的变量
#include <stdio.h>
void minmax(int a[] , int len , int *min , int *max);
int main(void)
{
int a[] = {1,2,3,4,5,6,7,8,9,12,13,14,15,34,35,66,};
int min , max;
minmax(a , sizeof(a)/sizeof(a[0]) , &min , &max);
printf("min = %d , max = %d \n", min , max);
return 0;
}
void minmax(int a[] , int len , int *min , int *max)
{
int i;
*min = *max = a[0];
for (i = 0; i < len; i++)
{
if (a[i] > *max)
{
*max = a[i];
}
if (a[i] < *min)
{
*min = a[i];
}
}
}
指针应用场景二b
- 函数返回运算的状态,结果通过指针返回
- 常用的套路是让函数返回特殊的不属于有效范围内的值表示出错
- -1 或 0
- 但是当任何数值都是有效的可能结果时,就得分开返回了
#include <stdio.h>
// 如果成功就返回1,否则就是0
int divide(int a , int b , int *result);
int main(void)
{
int a = 5;
int b = 2;
int c;
if (divide(a,b,&c))
{
printf("%d/%d = %d\n", a, b, c);
}
return 0;
}
int divide(int a , int b , int *result)
{
int ret = 1;
if ( b== 0)
{
ret = 0;
}else{
*result = a/b;
}
return ret;
}
指针常见的错误
定义了指针变量,还没有指向任何变量,就开始使用了
四、指针与数组
传入函数的数组成什么了?
- 函数参数表中的数组实际上是指针
- sizeof(a) == sizeof(int*)
- 但是可以用数组的运算符[]进行运算
下面的四种函数原型是等价的
int sum(int *ar , int n);
int sum(int* , int);
int sum(int ar[] , int n);
int sum(int[] , int);
数组变量是特殊的指针
数组变量本身表达地址,所以
- int a[10]; int*p = a; // 无需用&取地址
- 但是数组的单元表达的是变量,需要用&取地址
- a == &a[0]
[]运算符可以对数组做,也可以对指针做
- p[0] <===> a[0]
*运算符可以对指针做,也可以对数组做
- *a = 25
数组变量是const的指针,所以不能被赋值
五、指针与const
- 表示一旦得到了某个变量的地址,不能再指向其他变量
// q内写的地址不能被改变
int *const q = &i