指针
保存地址的变量
int i;
int *p=&i;
*可以靠近 int 也可以靠近p
指针变量
变量的值是内存的地址
普通变量是实际的值
指针变量的值日具有实际值的变量的地址
作为参数的指针
void f(int *p);
在被调用的时候得到了某个变量的地址:
int i=0; f(&i);
在函数里面可以通过这个指针访问外面的这个i
访问那个地址的变量*,是一个单目运算符,用来访问指针的值所表示的地址的变量
可以做右值也可以做左值
int k=* p
*p=k+1
指针应用场景
一,交换两个变量的值
void swap(int *pa, int *pb){
int t = *pa;
*pa = *pb;
}*pb = t;
二
函数返回多个值,某些值只能通过指针返回
传入的参数实际上是需要保存带回结果的变量
指针应用场景二b
函数返回运算的状态,结果通过指针返回
常用的套路是让函数返回特殊的不属于有效范围内的值来表示出错
指针常见错误
只定义了指针变量,还没指向任何变量,就开始使用指针
数组与指针
函数参数表中的数组实际上是指针
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的指针,所以不能被赋值,
inta[] <==> int * const a=...
指针运算
(+,+=,-,-=)可以给指针做运算
递增,递减,(++/--)使其移动到下一个位置
两个指针相减:结果表示 两个地址间可以放几个这样相同的类型
给一个指针加1表示要让指针指向下一个变量
int a[l0];
int*p=a;
*(p+1)-> a[I]
如果指针不是指向一片连续分配的空间,如数组,则这种运算没有意义
*p++
取出p所指的那个数据来,顺便把p到下一个位置去
*的优先级虽然没有++高
常用于数组类的连续空间操作
在某些CPU上,这可以直接被翻译成一条.汇编指令
0地址
内存中有0地址,但是0地址通常是个不能随便碰的地址
所以指针不应该具有0值
因此可以用0地址来表示特殊的事情:
返回的指针是无效的
指针没有被真正初始化(先初始化为0)
NULL是一个预定定义的符号,表示0地址
有的编译器不可以用0来表示0地址
指针的类型
无论指向什么类型,所有的指针的大小都是一样的,因为都是地址
但是指向不同类型的指针是不能直接互相赋值的
指针的类型转换
void*表示不知道指向什么东西的指针
计算时与char*相同(但不相通)
指针也可以转换类型
int *p = &i; void*q = (void*)p;
这并没有改变p所指的变量的类型,而是让其他人用不同的眼光通过p看它所指的变量
指针用处
需要传入较大的数据时用作参数
传入数组后对数组做操作
函数返回不止一个结果
需要用函数来修改不止一个变量
动态申请的内.....
动态内存分布
数据的输入,当需要多个数据输入,并记录时
int *a = (int' )malloc(n* sizeof(int));
此时需要
#include<stdlib.h>
malloc
#include <stdlib.h>
void* malloc(size_ _t size);
向malloc申请的空间的大小是以字节为单位的
返回的结果是void*, 需要类型转换为自己需要的类型
(int*)malloc(n*sizeof(int))
如果没有空间,则返回0或NOLL
free( )
把申请来的空间还给系统,只能还申请来的空间的原地址
如果没有free,长时间则会使运行内存逐渐下降
任何指针在定义时就应该初始化为0