指针

1,问题的引入
    int a;
    a = 100;//把数值100存放到变量a对应的存储单元中去
    b = a;//把a的数值存放到变量b对应的存储单元中去
    ==> 在C语言中,任何一个变量名,都有两层含义
    (1)代表该变量的存储单元,左值 lvalue
    (2)代表该变量的值        右值 rvalue
    
    而且,我们对变量的访问有两种情况
    (1)写操作,把一个值写入变量对应的存储单元中
    (2)读操作,读出变量对应存储单元中存放的值
    
    我们知道系统已经把变量名与变量的地址相关联,系统实质上通过地址
    来访问变量对应的存储空间。那么是不是我们也可以直接通过地址来访问
    变量呢?
    ==> 指针
    
2,指针的概念
    地址:系统把内存以一个字节为单位划分成许多份进行编号,这个编号就是内存单元的地址。
    
    在C语言中,指针的概念与地址差不多,你可以指针就是有类型的地址。
    一个变量的首地址,称为该变量的"指针"。它标志着该变量的内容从哪里开始。
    
3,指针变量
    ★指针变量也是一个变量,它是用来保存一个对象的地址的。
    
    指针变量的定义:
        类型  *指针变量名;
        "类型":指针变量指向的类型
        "指向":如果我保存了你的地址,那么就说我指向你。
        
    eg:  int *p;
         int a;
         p = &a;
         p是一个指针变量名,它指向的类型是int
         p的类型是: int*
         
    注意:在32位的处理器里,地址都是32位的,即指针变量分配的空间都是4个字节。
        所以把指针变量的类型强制转化为其它指针类型也不会失真。
        因此 void* 也叫通用指针。
        
   ★指针变量的类型只决定指针变量的变化(与整形加减)与实际地址变化间的倍率
    eg:   int a;
          char b;
          int *p1=&a;
          char *p2=&b;
          printf("%p\n",p1);//%p是打印地址的格式控制符
          printf("%p\n",++p1);
          printf("%p\n",p2);
          printf("%p\n",++p2);
        
4,如何获取地址
    (1)通过取地址符  &
        &对象名: 表示取该对象的地址
        对象: 变量,数组元素。。。
    (2)有些对象的名字本身就表示地址
        如:数组名,函数名....
    注:这两种方式获取到的地址都有类型的。
    
5,如何访问指针指向的空间。  *(指向运算符)
    *(地址) <==> 地址对应的那个变量
    即*(地址) 可作左值也可作右值,还可以取地址。
     *(&a) <==> a;
     *& 可直接约掉
    注意: 与定义时的*区分
    
6,数组与指针
    数组元素与普通变量,也有自己的地址。
    并且数组元素间地址是连续的。(数组名为首元素的地址,是个常量)
    eg:
        int a[10];
        int *p;
        p = &a[0];

        那么把100赋值给a[0],有几种方法:
            a[0] = 100;
            *p = 100;
            *a = 100;//数组名为首元素的地址,是个常量
            p[0] = 100;
            
        那么 *(a+1) ==> a[1]
        ★得到公式
          *(p+i) <=> p[i],when i>=0
          
7,字符串与指针
    在C语言中,并没有内置字符串的类型,C语言的字符串是通过char*指针
    来实现的。
    char *str = "ABCDEF";
    str:保存字符串的首地址,即'A'的地址
    str+1:指向字符'B'的地址
    *(str+1) = '2';//error(段错误),因为这里没有定义字符数组,没有分配空间
                   //常量保存在rodata段内,不能被改变
    eg:               
        char *str1 = "ABCDEF";//字符串保存在rodata段内
        char str2[]= "ABCDEF";//字符串保存在数组里
        
        *(str1+1) = '2';//error(段错误),指向的是只读空间,不能进行写操作
        *(str2+1) = '2';//right,指向的是数组空间,可以进行写操作
        str1++;//right,str1是指针变量,其值可以改变
        str2++;//error(段错误),str2是数组名,其值不能改变
    
    注意: (1)NULL在C语言中表示不指向任何空间,若指向了NULL并进行了读或写操作,
            就会出现段错误,NULL的值是0
          (2)出现段错误的两种情况
             a.指向了NULL,并进行了读或写操作
             b.对只读空间进行了写操作
             
8,二维数组与指针
    int a[3][4];
    二维数组a可以看成元素为int[4]的一维数组。
    所以,*(a+i)<=>a[i]指向的是该一维数组的第i个元素,该元素为int[4]类型,
    因此,这里需要再指向一下才能指向二维数组的元素。
    即*((*(a+i))+j) <=> a[i][j],这时元素的类型为int型。
    
    表达式(i>=0,j>=0)          类型                                 含义                                      值
    a+i                           int[4]*/int[3][4]   指向第i行的首地址/整个二维数组             &a[i]
                     做指针运算/sizeof(a),typeof(a)
    *(a+i)+j<=>a[i]+j           int*/int[4]     第i行第j列的元素的地址/i行的一维数组    &a[i][j]
                    做指针运算/sizeof(a[i]),typeof(a[i])    
    *(*(a+i)+j)<=>a[i][j]           int                          第i行第j列的元素                          a[i][j]

9,数组指针与指针数组 
    int a[10];
    如果我们需要定义一个指针变量p,来保存a的地址,该如何定义?
    typeof(a) *p;
    => int[10] *p;
    => int(*p)[10];
    p就是一个指针变量,指向一个数组(int[10]),那么我们把p叫做数组指针。
    因为*的结合性较低,所以这里要把*p括起来,表示定义的是指针变量。
    
    int *p[10];
    这里的p是一个数组,里面有10个元素,每个元素都是int*类型,
    那么我们把p叫做指针数组。
    eg:
        int(*p1)[10];
        int *p2[10];
        printf("%d %d\n",sizeof(p1),sizeof(p2));
    ★二维数组名的类型就是数组指针
    
10,main的参数
    在unix/liunx下面,main函数的原型,应该是如下的
    int main(int argc,char *argv[])
    {
    
    }
    在操作系统调用你的可执行程序时(调用你的main函数),允许带参数,
    只不过参数都是字符串类型(char *)
    argc:argument count,表示允许你的程序时,参数的个数(程序名是第一个参数)
    argv:argument vector 参数字符串指针的数组
    eg:  ./sum   1   2
    
    命令的本质就是程序,只不过它存放在命令搜索路径里

11,二级指针与多级指针
    其实main函数原型也可写为如下模式
    int main(int argc,char **argv)
    {}
    
    可见指针数组就是二级指针,二级指针就是能指向两次的指针。
    一般有以下两种理解方式
    (1)指针变量的地址
        eg:   int a;
              int *p = &a;
              int **p2 = &p;
            printf("%d %d %d\n",a,*p,**p2);
    (2)指针数组
        如果一个数组的元素是指针,则该数组名就是二级指针
        同理,如果一个数组的元素是二级指针,则该数组名就是三级指针
        ...
        eg:  
            int a=1,b=2,c=3;
            int *p[3]={&a,&b,&c};
            *(p+1)  ==>   p[1]  ==> &b
            **(p+1) ==> b
            
        在C语言中,char *可以表示字符串,其实指针也可以表示一个已定义好的数组。
        它们区别是:字符串有终止符'\0'来确定长度,而数组必须要我们自己给定长度。
        
        int array_max(int *a,int n)
        {
            
        }
        
12,函数指针
    函数指针变量就是用来保存函数地址的变量
    
    函数指针变量的定义格式:
        指向的函数返回值类型 (*函数指针变量名)(指向的函数形参列表)
        
    通过函数指针调用指向的函数:
        (*函数指针名)(实参列表);
        或
        (函数指针名)(实参列表);

    ☆函数指针数组
        void (*a[3])(int,int);//定义了一个函数指针数组a,该数组有3个元素,每个元素都是
                              //函数指针类型,指向的函数返回类型是void,参数类型是int,int。
                              
13,指针作为函数参数
    由于形参不能改变实参,被调函数想传数据给主调函数一般用return返回。
    除此之外还有两种方法
    (1)访问全局变量
    (2)带指针作为函数参数
    
14,动态内存分配(malloc.c)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值