zoukankan      html  css  js  c++  java
  • day5 -指针

    指针和指针变量

    1. 指针就是地址,地址就是指针
    2. 地址就是存放单元的编号
    3. 指针变量是存放地址的变量
    4. 指针和指针变量是两个不同的概念,但是要注意,通常我们叙述时会把指针变量简称为指针,实际他们含义并不一样

    指针热身-1

     1 #include <stdio.h>
     2 
     3 int main(void)
     4 {
     5     int * p; //p是变量的名字,int * 表示p变量存放的是int变量的地址
     6             // int *p不表示一个名字叫做p的变量
     7             //int*p应该理解为p是变量名,p变量的数据类型是int *类型
     8             //   所谓 int *类型实际就是存放int变量地址的类型
     9     int i=3;
    10     int j;
    11     p=&i;
    12     /*
    13         1.p保存了i的地址,因此p指向i;
    14         2.p不是i,i也不是p,更准确的说,修改p的值不影响i的值,修改i的值也不影响p的值
    15         3.如果一个指针变量指向了某个普通变量则
    16             *的指针变量 就完全等同于  普通变量
    17             例子:
    18             如果p是个指针变量,并且p存放了普通变量i的地址
    19             则p指向了普通变量i
    20             *p 完全等同于  i
    21             或者说 在所有出现*p的地方都可以替换成i
    22             *p 就是以p的内容为地址的变量
    23     */
    24 //    p=i; //error,因为类型不一致,p只能存放int类型变量的地址,不能存放int类型变量的值
    25     j = *p;  //等价于j= i
    26     printf("i=%d,j= %d",i,j);
    27     return 0;
    28 }

    指针的重要性:

    1. 表示一些复杂的数据结构 
    2. 快速的传递数据
    3. 使函数返回一个以上的值
    4. 能直接访问硬件
    5. 能够方便出来字符串
    6. 是理解面向对象语言中引用的基础

     总结:指针是c语言的灵魂

    指针的定义

    地址:内存单元的编号

           从零开始的非负整数

      范围:4G【0-4G】

    指针:指针就是地址,地址就是指针

       指针变量就是存放内存单元编号的变量,或者说指针变量就是存放地址的变量

    指针的本质就是一个操作受限的非负整数

    指针的分类

    • 基本类型指针
    • 指针和数组
    • 指针和函数
    • 指针和结构体
    • 多级指针

     经典指针程序—互换两个数字

     1 //    互换两个数字的值
     2 #include <stdio.h>
     3 void huhuan_2(int * p,int * q) //*p=a *q=b
     4 {
     5     int t;  //如果要互换*p和*q的值,则t必须定义成int,不能定义成int *,否则语法出错
     6     t=* p ;  //p是int *,*p是int
     7     * p= * q;
     8     * q= t;
     9     return ;  
    10 }
    11 /*void huhuan_1(int a,int b) //不能完成互换功能
    12 {
    13     int t;
    14     t=a;
    15     a=b;
    16     b=t;
    17     return ;  
    18 }*/
    19 int main(void)
    20 {
    21     int a=3;
    22     int b=5;
    23     huhuan_2(&a,&b);   
    24 printf("%d %d
    ",a,b);
    25     return 0;
    26 }

    附注:

    *的含义

    1.乘法

    2.定义指针变量

      int  * p   //定义了一个名字叫p的变量,int *表示p只能够存放int变量的地址

    3.指针运算符

      该运算符放在已经定义好的指针变量的前面

      如果p是一个已经定义好的指针变量,则*p表示以p的内容为地址的变量

    如何通过被掉函数修改主调函数普通变量的值?

    1.实参必须为该普通变量的地址

    2.形参必须为指针变量

    3.在被掉函数中通过

      *形参名

      的方式就可以修改朱掉函数相关变量的值

    2.指针和数组

    指针和一维数组

      一维数组名是个指针常量,它存放的是一维数组和第一个元素的地址 

    1 // 一维数组名是个指针常量,它存放的是一维数组和第一个元素的地址
    2 #include <stdio.h>
    3 int main(void)
    4 {
    5 int a[5];
    6 printf("%#x
    ",&a[0] );
    7 printf("%#x
    ",a);
    8 return 0;
    9 }
    10 /* 在vc6.0中的结果为:
    11 0x18ff34
    12 0x18ff34

      下标和指针的关系

    如果p是个指针变量,则 p[i]永远等价于*(p+i)

    确定一个一维数组需要几个参数

      需要两个参数

        1.数组第一个元素的地址

        2.数组的长度

     1 #include <stdio.h>
     2 //f函数可以输出任何一个一堆数组的内容
     3 void f(int * p,int q)
     4 {
     5     int i;
     6 //    for (i=0;i<q;++i)
     7     for (i =0;i<q;++i)
     8         printf("%d
    ",*(p+i));   //*(p+i)等价于 p[i] 也等价于 a[i]也等价于*(b+i)
     9 }
    10 /*
    11     p[i]的意思就是从地址p开始向后偏移i个单位后的地址空间内的值
    12 *(p+i) 也是上面的意思 
    13 []实际上就是个地址偏移操作符 ,c语言编译器就是把p[i]转换成*(p+i)处理的,p[i]和*(p+i)无条件等价 
    14 比如有数组int p[4]={1,2,3,4}; 
    15 p就是这个数组的首地址 
    16 p[2]就是从p开始偏移2个int单位后的地址内的值 就是3
    17 *(p+2) 这个更好理解,p+2就是在p的基础上+2个int单位的地址,那么*(p+2)就是这个地址内的值:3
    18 */
    19 int main(void)
    20 {
    21     int a[5]={1,2,3,4,5};
    22 
    23     f(a ,5);   //a是int *
    24     return 0;
    25 }
     1 #include <stdio.h>
     2 void f(int * p, int q)
     3 {
     4     p[3]=88;
     5 }
     6 int main(void)
     7 {
     8     int a[6] ={1,2,3,4,5,6};
     9     printf("%d
    ",a[3]);
    10     f(a ,6);
    11     printf("%d
    ",a[3]);
    12     return 0;
    13 }
    14 /*在vc6.0中的结果为
    15 4
    16 88

     

     指针变量的运算

        指针变量不能想加 不能想乘 不能相除

        如果两个指针变量指向的是同一块连续空间中的不同存储单元  则这两个指针变量才可以相减

     1 #include <stdio.h>
     2 int main(void )
     3 {
     4     int a[5];
     5     int * p;
     6     int * q;
     7     p=&a[1];
     8     q=&a[4];
     9     printf("p和q所指向的单元相隔%d个单元
    ",q-p);
    10     return 0;
    11 }
    12 //在vc6.0中的结果为:p和q所指向的单元相隔3个单元

      一个指针变量到底占几个字节

        假设p指向char类型变量(1个字节)

        假如q指向int类型变量(4个字节)

        假如r指向double类型变量(8个字节)

        p,q,r本身所占的字节数是一样的

    指针和二维数组

    动态内存分配

    传统数组的缺点:

      1.数组长度必须事先指定,且只能是常整数,不能是变量     例子:  int a[5] // ok    int len;int a [len] //error

      2.传统形式定义的数组,该数组的内存程序员无法手动释放 

       在一个函数运行期间,系统为该函数中所非配的内存会一直存在,直到该函数运行完毕时,该数组才会被系统释放

      3.数组的长度一旦定义,其长度就不能再更改

         数组的长度不能再函数运行的过程中动态的扩充或缩小

      4.A函数定义的数组,在A函数运行期间可以被其他函数使用,但A函数运行完毕之后,A函数中的数组将无法再被其他函数使用

        传统方式定义的数组不能跨函数使用

    为什么需要动态分配内存

      动态数组很好的解决了传统数组的这4个缺点

      传统数组也叫静态数组

    动态分配内存举例—动态数组的构造

    molloc函数
     1 #include <stdio.h>
     2 #include <malloc.h>
     3 int main(void )
     4 {
     5     int i = 5; //分配了4个字节,静态分配
     6     int * p=(int *)malloc(4); //12行
     7     /*
     8         1.要使用molloc函数,必须要加malloc.h这个头文件
     9         2.malloc函数只有一个形参,并且形参是整型
    10         3.4表示请求系统为本程序分配4个字节
    11         4.malloc函数只能返回第一个字节的地址
    12         5.12行分配了8个字节,p变量占4个字节,p所指向的内存也占4个字节
    13         6.p本身所占的内存是静态分配的,p所指向的内存是动态分配的
    14     */
    15     * p =5; //*p代表就是一个int变量,只不过*p这个整型变量内存分配和11行的i变量分配方式不同
    16     freee (p);//表示把p所指向的内存给释放掉
    17     printf("同志们好!");
    18     return 0;
    19 }

    静态内存和动态内存的比较

    跨函数使用内存的问题

  • 相关阅读:
    C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本
    C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本
    C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本
    C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本
    《程序员,你伤不起》 回答热心爸爸读者的疑问
    入驻微信公众号平台【今日热点在线】、【大数据躺过的坑】和【九哥九嫂小日子】,欢迎关注
    入驻百家号【九哥聊IT】和【九哥九嫂小日子】,欢迎关注
    全网最详细的最新稳定OSSEC搭建部署(ossec-server(CentOS7.X)和ossec-agent(CentOS7.X))(图文详解)
    CentOS 7的安装详解
    全网最全的Windows下Anaconda2 / Anaconda3里正确下载安装爬虫框架Scrapy(离线方式和在线方式)(图文详解)
  • 原文地址:https://www.cnblogs.com/8013-cmf/p/4632288.html
Copyright © 2011-2022 走看看