指针
取地址运算
1 . 运算符 &
- scanf(“%d”, &i);?的&
- 获得变量的地址,它的操作数必须是变量,int i; printf(“%x”,&i);
- 地址的??是否与int相同取决于编译器,int i; printf(“%p”,&i);
2. &不能取的地址
&不能对没有地址的东?取地址
&(a+b)?
&(a++)?
&(++a)?
3. 试试这些&
变量的地址
相邻的变量的地址
&的结果的sizeof
数组的地址
数组单元的地址
相邻的数组单元的地址
指针
1. scanf
如果能够将取得的变量的地址传递给?个函数, 能否通过这个地址在那个函数内访问这个变量?
- scanf(“%d”, &i);
scanf()的原型应该是怎样的?我们需要?个参数 能保存别的变量的地址,如何表达能够保存地址 的变量?
2. 指针
就是保存地址的变量
int i;
int* p = &i;
int* p,q;
int *p,q;
3. 指针变量
- 变量的值是内存的地址
- 普通变量的值是实际的值
- 指针变量的值是具有实际值的变量的地址
4. 作为参数的指针
- void f(int *p);
- 在被调?的时候得到了某个变量的地址:int i=0; f(&i);
- 在函数??可以通过这个指针访问外?的这个i
5. 访问那个地址上的变量*
- *是?个单?运算符,?来访问指针的值所表?的地 址上的变量
- 可以做右值也可以做左值int k = *p;*p = k+1;
6. *左值之所以叫左值
- 是因为出现在赋值号左边的不是变量,?是值,是表 达式计算的结果:a[0] = 2; *p = 3;
- 是特殊的值,所以叫做左值
7. 指针的运算符&*
互相反作?
*&yptr -> * (&yptr) -> * (yptr的地 址)-> 得到那个地址上的变量 -> yptr
&*yptr -> &(*yptr) -> &(y) -> 得到y的地 址,也就是yptr -> yptr
8. 传?地址
- 为什么 ? int i; scanf(“%d”, i);
- 编译没有报错?
9. 指针应?场景?
交换两个变量的值
void swap(int *pa, int *pb){ int t = *pa; *pa = *pb; *pb = t; }
10. 指针应?场景?
- 函数返回多个值,某些值就只能通过指针返回
- 传?的参数实际上是需要保存带回的结果的变量
11. 指针应?场景?b
- 函数返回运算的状态,结果通过指针返回
- 常?的套路是让函数返回特殊的不属于有效范围内的 值来表?出错:-1或0(在?件操作会看到?量的例?)
- 但是当任何数值都是有效的可能结果时,就得分开返 回了,后续的语?(C++,Java)采?了异常机制来解决这 个问题
12. 指针最常?的错误
- 定义了指针变量,还没有指向任何变量,就开始使? 指针
13. 9.1-3 指针与数组
传?函数的数组成了什么?
- 函数参数表中的数组实际上是指针
- sizeof(a) == sizeof(int*)
- 但是可以?数组的运算符[]进?运算
14. 数组参数
以下四种函数原型是等价的:
int sum(int *ar, int n);
int sum(int *, int);
int sum(int ar[], int n);
int sum(int [], int);
15.数组变量是特殊的指针
- 数组变量本?表达地址,所以
- int a[10]; int*p=a; // ?需?&取地址
- 但是数组的单元表达的是变量,需要?&取地址
- a == &a[0]
- []运算符可以对数组做,也可以对指针做:
- p[0] <==> a[0]
- *运算符可以对指针做,也可以对数组做:
- *a = 25;
- 数组变量是const的指针,所以不能被赋值
- int a[] <==> int * const a=….
*9.1-4 指针与const
1.指针与const
2. 指针是const
- 表??旦得到了某个变量的地址,不能再指向 其他变量
- int * const q = &i; // q 是 const
- *q = 26; // OK
- q++; // ERROR
3. 所指是const
- 表?不能通过这个指针去修改那个变量(并不 能使得那个变量成为const)
- const int *p = &i;
- *p = 26; // ERROR! (*p) 是 const
- i = 26; //OK
- p = &j; //OK
4. 这些是啥意思?
int i;
const int* p1 = &i;
int const* p2 = &i;
int *const p3 = &i;
判断哪个被const了的标志是const在*的前?还是后?
5. 转换
- 总是可以把?个?const的值转换成const的
void f(const int* x);
int a = 15; f(&a);// ok
const int b = a;
f(&b); // ok
b = a + 1; // Error!
- 当要传递的参数的类型?地址?的时候,这是常?的? 段:既能??较少的字节数传递值给参数,?能避免函 数对外?的变量的修改
6. const数组
const int a[] = {1,2,3,4,5,6,};
数组变量已经是const的指针了,这?的const 表明数组的每个单元都是const int
所以必须通过初始化进?赋值
7. 保护数组值
因为把数组传?函数时传递的是地址,所以那个函数 内部可以修改数组的值
为了保护数组不被函数破坏,可以设置参数为const
- int sum(const int a[], int length);
指针是可计算的
1. 1+1=2?
- 给?个指针加1表?要让指针指向下?个 变量
- int a[10];
- int *p = a;
- *(p+1) —> a[1]
- 如果指针不是指向??连续分配的空间, 如数组,则这种运算没有意义
2. 指针计算
- 这些算术运算可以对指针做:
- 给指针加、减?个整数(+, +=, -, -=)
- 递增递减(++/—)
- 两个指针相减
3. *p++
- 取出p所指的那个数据来,完事之后顺便 把p移到下?个位置去
- *的优先级虽然?,但是没有++?
- 常?于数组类的连续空间操作
- 在某些CPU上,这可以直接被翻译成?条 汇编指令
4. 指针?较
- <, <=, ==, >, >=, != 都可以对指针做
- ?较它们在内存中的地址
- 数组中的单元的地址肯定是线性递增的
5. 0地址
- 当然你的内存中有0地址,但是0地址通常是 个不能随便碰的地址
- 所以你的指针不应该具有0值
- 因此可以?0地址来表?特殊的事情:
- 返回的指针是?效的
- 指针没有被真正初始化(先初始化为0)
- NULL是?个预定定义的符号,表?0地址
- 有的编译器不愿意你?0来表?0地址
6. 指针的类型
- ?论指向什么类型,所有的指针的??都 是?样的,因为都是地址
- 但是指向不同类型的指针是不能直接互相 赋值的
- 这是为了避免?错指针
7. 指针的类型转换
- void* 表?不知道指向什么东?的指针
- 计算时与char*相同(但不相通)
- 指针也可以转换类型
- int *p = &i; void*q = (void*)p;
- 这并没有改变p所指的变量的类型,?是让 后??不同的眼光通过p看它所指的变量
- 我不再当你是int啦,我认为你就是个void!
8. ?指针来做什么
- 需要传?较?的数据时?作参数
- 传?数组后对数组做操作
- 函数返回不??个结果
- 需要?函数来修改不??个变量
- 动态申请的内存...
动态内存分配
1.输?数据
- 如果输?数据时,先告诉你个数,然后再输?,要记 录每个数据
- C99可以?变量做数组定义的??,C99之前呢?
- int *a = (int*)malloc(n*sizeof(int));
2. malloc
- #include void* malloc(size_t size);
- 向malloc申请的空间的??是以字节为单位 的
- 返回的结果是void*,需要类型转换为?? 需要的类型
- (int*)malloc(n*sizeof(int))
3.没空间了?
如果申请失败则返回0,或者叫做NULL
你的系统能给你多?的空间?
4. free()
- 把申请得来的空间还给“系统”
- 申请过的空间,最终都应该要还
- 混出来的,迟早都是要还的
- 只能还申请来的空间的?地址 ? free(0)?
5. 常?问题
- 申请了没free—>?时间运?内存逐渐下降
- 新?:忘了
- ??:找不到合适的free的时机
- free过了再free
- 地址变过了,直接去free
函数间传递指针
1. 好的模式
如果程序中要?到动态分配的内存,并且 会在函数之间传递,不要让函数申请内存 后返回给调?者
因为?有?九调?者会忘了free,或找不 到合适的时机来free
好的模式是让调?者??申请,传地址进 函数,函数再返回这个地址出来
2. 函数返回指针?
- 返回指针没问题,关键是谁的地址?
- 本地变量(包括参数)?函数离开后这些变量就不 存在了,指针所指的是不能?的内存
- 传?的指针? 没问题
- 动态申请的内存? 没问题
- 全局变量—>以后再解释
函数返回数组?
- 如果?个函数的返回类型是数组,那么它实际返回 的也是数组的地址
- 如果这个数组是这个函数的本地变量,那么回到调 ?函数那?,这个数组就不存在了
- 所以只能返回
- 传?的参数:实际就是在调?者那?
- 全局变量或动态分配的内存