1.指针作为函数参数
调用函数时,传递参数的形式决定了是否可以修改这些参数。
- 传值方式:传递了参数给函数,并且这个参数是基本数据类型,如(int,float),那么函数内对参数的任何操作都不会改变这个原始变量的值。因为实际上传入函数的参数是一份copy,在函数内的操作只会影响到copy。
#include <stdio.h>
void increase(int a)
{
a++;
}
int main()
{
int num = 9;
increase(num);
printf("%d", num);
return 0;
}
打印的结果还是9,并未改变原始参数num的值
- 传址方式:可以做到在函数内真正修改参数的值,需要通过传递指向参数的指针,函数可以直接访问参数所处的内存地址,并修改其内容。
#include <stdio.h>
void increase(int *a)
{
(*a)++;
}
int main()
{
int num = 9;
int *p = #
increase(p);//传的是num的地址
printf("%d", num);
return 0;
}
2.指针的使用
- 应用场景一:交换两个变量的值
函数内部的参数为 指针 的时候,调用函数的时候要传入 变量的地址!
函数要返回多个值,那某些值就只能通过指针返回。既要返回a,又要返回b。传入的参数实际上是需要保存带回的结果的变量。
- 应用场景二:函数的返回结果有多个(需要保存改变值后的多个变量)
可以看到这种指针操作其实都是没有return值的,因为函数的返回值只能有一个!所以直接通过指针访问变量,对多个变量的值进行更改。
之前讲过,如果不用指针的话,在一个函数内部是不能改变外部变量的值的:如果函数内没有返回值并且给到变量进行接收,而是单纯地传入一个变量的值(例如只是单纯执行操作increase(a);
)那么传入函数的变量的值不变。但是如果使用指针,并且传入变量的地址,那么即使函数没有返回值,在函数内部仍然可以做到对变量值的修改。 - 应用场景三:函数返回运算的状态,结果通过指针返回
这种情况,程序可能会出错,那么我将会使用return返回函数执行的状态,用指针改变变量的值。
- 常见错误
定义了指针变量,但是没有让他指向任何变量就开始使用指针(未初始化指针)
3.指针和数组
将数组作为函数参数传入,数组此时实际上是指针
(以前文章有整理)
4.指针和const
int const *p = &i;
不能变的是 指向的变量
q是const指针,指向了变量i。那么q只能指向i而不能指向其他变量了。对*q进行赋值是可以的,因为i不是const变量。
不能变的是不能通过p去做修改:
*p = 10;
这时可以让p指向别的变量,也可以修改 i 的值:*p = &j; i = 10;
。
-
要么指针指向不可修改,要么不可通过指针修改
const在星号前面,不可通过指针修改;
const在星号后面,指针指向不可修改。
能用比较小的字节数传递值给参数:例如,一个超级大的数组,但是他传入函数的时候其实是一个指针的大小。
这表明a[0],a[1]…a[5]全部都是const类型,不可改变。
那么这种操作可以保证传入函数的数组不会被修改。
5.指针运算
- 指针加法运算
可以看到,对指针的值+1,不是在地址值上 +1,而是在地址值上 +sizeof(类型)
对指针 +1,是让指针指向下一个单元,根据具体的数据类型进行地址值的改变。
关于指向下一个单元的操作:
在这里,*(p+n) 和 a[n] 以及 p[n] 是等价的
- 指针的值之间相减
得到的结果是 地址相减/sizeof(类型)
- 关于
*p++
*p++ 表示先取当前指针指向的值(*p),顺便对指针进行递增(p++)。通常用于对数组的一些操作,例如遍历数组:
- 指针的比较
eg, a[0] < a[5]
- 零地址
如果int *p = 0;
或者写成int *p = NULL;
那么这表示指针p的初始化是0地址,如果再进行p = malloc(1);
这种操作是不被允许的,因为程序会因为向0地址写入而退出。
- 指向不同类型的指针不可以相互赋值
比如int *p = a[0];char *q = b[1];p = q;
不可以执行。 - 指针的类型转换
int i = 9;
int *p = &i;
(void*)q = (void*)p;
在这里把int类型的p强制转换成void类型,交给void*q。但是并没有改变i的类型,i还是int型,只不过q也指向了i,通过q去看i当做void。
6.动态内存分配
- 当不确定数组的大小的时候(或者说只有于运行的时候数组的大小才确定),C99通常可以使用可变数组:
int N;
printf("请输入你所需要的数组的大小");
scanf("%d",&N);
int a[N];
//在这里N是一个变量,它的值在定义数组a之前被确定
- 但是C99之前就得使用动态内存分配:
使用malloc函数 :
int N;
printf("请输入你所需要的数组的大小");
scanf("%d",&N);
int *a;
a = (int*)malloc(N*sizeeof(int));
...
free(a);
注意malloc函数的使用得引用头文件 #include <stdlib.h>
。malloc函数要的不是数组要占据多少个单元,而是要知道占用多少个空间,单位是字节!它返回的结果是 void*
,但是数组a的类型是 int*,那么就得进行强制转换在这里我们需要的类型int *
。OK操作完成,因为数组和指针是近似的,之后所有的事情就拿a当做数组来用。malloc函数为a借来了一块空间,之后要在程序的结尾将内存释放:free(a);
但是空间申请失败了,就会返回0或者叫做NULL。
最好的习惯是,每当使用malloc函数就用free那个变量。
7.总结
//第一周的指针操作,后两节的字符串和字符串操作没学。