要接受的观点

1.操作系统管理内存分配(有人来了,要分房间给它住)、内存回收(人走了,房间要收回来)的方式就是给内存编号。这个编号是二进制的编号,而且与操作系统位数相关。
    2.  所有变量运行时都要保存在内存中,程序有两种方式来访问变量:
       - 直接访问方式:根据变量对变量赋值或读取变量。
       - 间接访问方式:每个变量都需要保存在内存中,因此它所在的首内存就有一个内存编号,此时也可通过该内存编号来访问变量。
    3.内存编号 = 内存地址 = 指针(pointer)
    指针变量及其基本用法:
           定义指针变量:
                   类型 * 变量名;
    定义了一个变量,该变量用于装内存编号(地址、指针),而且该变量只能装指定类型的变量所在内存的内存地址。
    两个运算符:
       &变量:取地址运算符,获取给定变量所在内存的首地址。
       *指针变量:取变量运算符。获取指定的内存编号(地址、指针)中所装的变量。

 

指针作为函数的参数

当使用指针作为函数参数,程序传入函数的不再是普通的变量、而是地址的副本。
    使用指针作为函数参数时,有两点注意:
       1. 程序传入函数的,依然是指针(地址)的副本。
       2. 函数可以改变指针所指变量的值。但函数对传入参数(指针变量本身)依然不会有任何影响。

指针与数组

数组变量,本身就是指针。数组变量指向数组的首地址。
    数组变量,里面装的是第一个元素所在内存的编号(首地址)。
    数组变量与普通指针变量的区别为:普通指针变量可以被赋值(改变),但数组变量不允许被赋值。
    指针变量的赋值方式:
       int * p = 0x14344 ;                                  ×
       int * p = &int型变量;                             √
       int * p = q;   其中q是另一个int*型的变量           √
       int * p = arr;   其中arr是int数组                   √
       int * p = arr[i];   其中arr是int数组                  ×
       int * p = &arr[i];   其中arr是int数组                 √
    指针的运算:
           指针的加法、减法并非以字节为单位,而是size(类型)为单位。
           指针 + n: 将内存编号 + n*sizeof(类型)
           通常而言,只有对指向数组元素的指针进行加N才有意义,相当得到该元素后面第N个元素的地址
           指针 - n: 将内存编号 - n*sizeof(类型)
           通常而言,只有对指向数组元素的指针进行减N才有意义,相当得到该元素钱面第N个元素的地址
          指针 - 指针 => 编号差/sizeof(类型)
          通常而言,只有两个指向数组元素的指针相减才有意义,得到结果就是两个元素之间相差几个元素。
          指针与指针可以比较大小。通常而言,只有对指向同一个数组元素的两个指针比较大小,指针越大,位于数组的越后面。
    数组本身作为函数的参数
          当程序把数组本身作为函数的参数时,实际上就是把指针作为函数的参数。
          1.  程序只是将数组变量的副本传入函数。
          2.  函数不能改变数组变量本身(肯定不能改变),但是可以改变数组元素的值
         记住:如果函数需要改变数组元素的值,那么应该向函数传入数组元素的地址,或者数组变量本身(第一个数组元素的地址)。
         arr[i]在底层的访问方式,本身就是2步:①、先计算arr+i的地址;②、根据地址去取得对应元素。
         如果你写成&arr[i]——这就会导致系统先计算地址,再根据地址得到数组元素,最后又根据元素获取地址。
 
    指向多维数组的指针:
    对于intarr[3][4]这样一个数组。
     arr+n与 arr[n]、*(arr+n)都是指针,它们装的编号是相同的,都是指向整个数组的首地址。
     *(arr+n)与*arr+n是否相同?不同,其实计算公式如下:
           arr+n   =>  arr编号 + n* 第二维长度  * sizeof(类型)
          *arr+n =>  arr编号 + n*sizeof(类型)
          arr[m] + n  、*(arr+m)+n  、&arr[m][n]是一样的。
          *(arr[m] + n) 、*(*(arr+m)+n)、 arr[m][n]是一样的。

字符串与字符指针

C本身并没有字符串,C采用了字符数组来保存字符串。
       程序可以直接用字符串对字符数组进行赋值,程序会自动在所有字符之后添加结束符(\0)。
        【虽然程序可以用字符数组来装多个字符,从而代码字符串,但由于数组不能被重复赋值,因此用起来不方便】。
       由于数组的本质,就是指针,因此实际上往往会使用字符指针来代表字符串。
       使用字符指针声明字符串之后,有如下2个特征:
       -- 由于指针是可以被多次赋值的,因此char*可以被多次存入不同的字符串。
          每次传入字符串时,实际上是先将字符串转换为字符数组,再将数组的首地址赋值给字符指针变量。
       -- 使用char*声明的字符串,是不可变的字符串,它的字符序列是不允许改变的。

函数和指针

C语言允许定义函数指针来指向函数, 函数指针可以在不同时间指向不同的函数。
    函数指针
           定义函数指针的语法:
           函数返回值类型 (* 函数指针变量)();
         【注意】:对函数指针类型的变量赋值时,要用函数本身进行赋值,而不是调用函数!!       
           int (* fnPt)();
          fnPt = jiechen; //jiecheng为自定义的一个函数
          (*fnPt)(5);   //利用函数指针类型调用函数的方法
    返回指针的函数
            对于返回指针的函数,该指针指向的东西,不能是函数中的局部变量。函数返回的指针,通常有如下做法:
           1.  如果指针指向的该函数中的局部变量,应该将局部变量用static修饰。
           2.  让函数返回的指针指向全局变量
           3.  让函数返回的指针指向main函数中的变量——这是因为main结束时,你的程序大致上也就结束了。