第1周:指针与字符串——1.1 指针的使用
1.指针的应用场景
交换两个变量的值(只能由指针完成);
函数返回多个值,某些值就只能通过指针返回(传入的参数实际上是需要保存带回的结果的变量)函数结果不止一个,通过指针把要接收的结果变量的地址传进去,函数把结果变量填好传回值;
函数返回运算的状态,结果通过指针返回。常用的套路是让函数返回特殊的不属于有效范围的值来表示出错(-1或0,在文件操作会看到大量的例子)。但是当任何数值都是有效的可能结果时,就得分开返回了。状态用 return ,值用指针。后续的语言(C++ ,Java)采用了异常机制来解决这个问题。
2.指针最常见的错误
定义了指针变量,还没有指向任何变量,就开始使用指针。
所有本地变量都不会有默认的初始值,若未赋值,本地变量里什么都没有。
任何一个地址变量,没有被赋值之前,没有得到任何变量的地址之前,不能通过*访问任何的变量和数据。
3.传入函数的数组成了什么?
普通变量传入函数,接收到的是值;指针传入函数,接收到的是指针的值,代表外面的变量。
为什么函数参数表里面的数组在函数里头必须留一个空的方括号?为什么方括号里写数字也没用?为什么函数里没有办法用 sizeof 得到正确的元素个数?
函数参数表中的数组实际上是指针,样子看上去像一个数组,函数头可以把它写成指针类型,编译通过,运行正确。对于函数参数中的数组的 sizeof ,返回的是 int* 的 sizeof 而不是数组的。函数参数里的数组,与 main 中的数组地址相同,是同样的地址代表同一个数组。
sizeof(a)==sizeof(int*)。但是可以用数组的运算符 [ ] 进行运算。
以下4种函数原型是等价的:
int sum( int *ar,int n ); int sum( int *,int );
int sum( int ar[ ],int n ); int sum( int [ ],int );
4.数组变量是特殊的指针
数组变量本身表达地址。所以 int a[10]; int *p=a; 无需用&取地址。
但是数组的单元表达的是变量,需要用&取地址。a==&a[0];
[ ] 运算符可以对数组做,也可以对指针做。p[0] 相当于 a[0]。把 p (指针变量)所指的地方当作是个数组,可认为是长度为1的数组。
* 运算符可以对指针做,也可以对数组做。
数组变量是 const 指针,所以不能被赋值。数组变量间不能做互相赋值。
int b[] ;相当于 int* const b; b是常数,不能被改变,不能代表别的数组,是一个常量指针。
5.指针与 const
指针可以是 const ,指针指向的值可以是 const 。
指针是 const 表示一旦得到了某个变量的地址,不能再指向其他变量(关系永久)。
int *const q = &i; // q 是 const, q 的值不能被改变。
*q = 26;// OK q++;// ERROR
所指是 const 表示不能通过这个指针去修改那个变量(并不能使得那个变量成为 const)。
const int *p = &i; *p = 26;// ERROR! ( *p )是 const ,不能通过 p 做赋值。
i = 26; // OK i 可修改 p = &j ; // OK p 可修改
判断哪个被 const 的标志是 const 在 * 的前面还是后面。
const 在 * 的前面表示所指是 const ,不能通过指针修改变量。
const 在 * 的后面表示指针是 const ,指针不能被修改。
6.转换
总是可以把一个非 const 的值转换成 const 的。
即使a不是const也能传入函数中void f ( const int* x) ,将 x 用指针的方式传进去,传 const 指针。表示在函数内部不改变指针所指的值,不能通过指针修改变量。
当要传递的参数的类型比地址大的时候,这是常用的手段:既能用比较少的字节数传递值给参数,又能避免函数对外面的变量的修改。
7. const 数组
const int a[ ] = { 1,2,3,4,5,6 };
数组变量已经是 const 的指针了,这里的 const 表明数组的每个单元都是 const int 。
所以必须通过初始化进行赋值。
8.保护数组值
因为把数组传入函数时,传入的是地址,所以那个函数内部可以修改数组的值。
为了保护数组不被破坏,可以设置参数为 const 。
int sum( const int a[ ] , int length );