zoukankan      html  css  js  c++  java
  • C语言(十五)指针

    一、指针

    1. 指针的重要性

      表示一些复杂的数据结构

      快速的传递数据,减少了内存的耗用

      使函数返回一个以上的值

      能直接访问硬件

      能够方便的处理字符串

      是理解面向对象语言中引用的基础

      

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

    2. 指针的定义

      地址

        内存单元的编号

        从0开始的非负整数

        范围:4G [0--4G-1]

      指针

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

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

        

        

    3. 指针的分类

       1. 基本类型指针

       2. 指针和数组

          指针和一维数组

            一维数组名

              一维数组是个指针常量

              他存放的是一维数组第一个元素的地址

          下标和指针的关系

              如果p是个指针变量,则

                p[i] 永远等价于 *(p+i)

          确定一个一维数组需要几个参数(如果一个函数要处理一个一维数组,则需要接收该数组的哪些信息)

            需要两个参数:

                数组第一个元素的地址

                数组的长度

            

          指针变量的运算

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

              如果两个指针变量只想的是同一块连续的空间中的不同的存储单元

              则两个指针变量才可以相减

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

              预备知识:

                  sizeof(数据类型)

                  功能:返回值就是该数据类型所占的字节数

                  例子: sizeof(int) = 4 sizeof(char) = 1

                      sizeof(double) = 8

                  sizeof(变量名)

                   功能:返回值是该变了所占的字节数

              

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

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

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

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

                答案: p q r 本身所占的字节都是一样的

               总结:一个指针变量,无论它指向的变量占几个字节

                  该指针变量本身只占四个字节

                  一个变量的地址,是用该变量的地址使用该变量首字节的地址来表示。

        指针和二维数组

       3. 指针和函数

       4. 指针和结构体

       5. 多级指针

    专题:

        动态内存分配(重点难点)

            传统数组的缺点:

              1.  数组的长度必须事先制定,且只能是常整数,不能是变量

                 例子:

                    int a[5]; //Ok

                    int len = 5; int a[len]; //error

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

               在一个函数运行期间,系统为该函数中数组所分配的空间

               会一直存在,直到该函数运行完毕时,数组的空间才会被

               系统释放  

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

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

              4.     A函数定义的数组,在A函数运行期间可以被其他函数使用,

                但A函数运行完毕之后,A函数中的数组将无法在被其他函数使用。

                

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

            为什么需要动态内存

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

              传动数组也叫静态数组

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

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

              静态内存是由系统自动分配,由系统自动释放

              静态内存是在在栈分配的

              动态内存是由程序员手动分配,手动释放

              动态内存是在堆分配的

            跨函数使用内存的问题

    4. *的含义

      1. 乘法

      2. 定义指针变量

        int * p;(int * p 和 *p = 5    此时*号的含义不一样)

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

      3. 指针运算符

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

        如果p是一个已经定义好的指针变量

        则 *p表示以p的内容为地址的变量

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

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

      2. 形参必须为指针变量

      3. 在被调函数中通过

          *形参名 = .....

      的方式就可以修改主调函数相关变量的值

    二、指针简单介绍

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 int main()
     4 {
     5     int *p;  //p是变量的名字,int * 表示p变量存放的是int类型的地址
     6     int i = 3;
     7     
     8     p = &i;     //OK
     9     //p = i;    //error,因为类型不一致,p只能存放int类型变量的地址,不能存放int类型变量的值
    10     //p = 55; //error,原因同上。
    11     system("pause");
    12     return 0;
    13 }
    指针用法_1  
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 int main()
     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         
    12     p = &i;     
    13     /*
    14         1. p保存的i的地址,因此p指向i
    15         2. p不是i,i也不是p,更准确的说:修改p的值不影响i的值,修改i的值也不影响p的值
    16         3. 如果一个指针变量指向某个普通变量,则*指针变量 就完全等同于 普通变量
    17         例子:
    18             如果p是个指针变量,并且存放了普通变量i的地址
    19             则p指向了普通变量i
    20             *p 就完全等同于 i
    21             或者说:在所有出现*p的地方都可以替换成i
    22                     在所有出现i的地方都可以替换成*p
    23                     
    24                     
    25             *p就是以p的内容为地址的变量
    26         
    27     */
    28     j = *p; //等价于 j = i;
    29     printf("i = %d, j = %d
    ",i,j);
    30     system("pause");
    31     return 0;
    32 }
    33 
    34 /*
    35     指针就是地址,地址就是指针
    36     地址就是内存单元的编号
    37     指针变量是存放地址的变量
    38     指针和指针变量是两个不同的概念
    39     但是要注意通常我们叙述时会把指针变量简称为指针,实际它们含义并不一样
    40 
    41 */
    指针用法_2 
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 int main()
     4 {
     5     int *p;
     6     int i = 5;
     7     
     8     p = &i;  //没有这一步 这个程序就是错误的
     9     *p = i;
    10     printf("%d
    ",*p);
    11     system("pause");
    12     return 0;
    13 }
    指针的常见错误_1 
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 int main()
     4 {
     5     int * p;
     6     int * q;
     7     int i = 5;
     8     
     9     p = &i;
    10     //*q = p  //error 语法编译会出错
    11     //*q = *p //error
    12     p = q; //q是垃圾值,q赋给p,p也变成垃圾值
    13     printf("%d
    ",*q);
    14      /*
    15         q的空间是属于本程序的,所以本程序可以读写q的内容,
    16         但是如果q内部是垃圾值,则本程序不能读写*p的内容
    17         因为*q所代表的内存单元的控制权限并没有分配给本程序
    18         所以本程序运行到13行就会立即出错
    19      */
    20     system("pause");
    21     return 0;
    22 }
    指针的常见错误_2
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 void huhuan(int a, int b )
     5 {
     6     int t;
     7     
     8     t = a;
     9     a = b;
    10     b = t;
    11     
    12     return;
    13 }
    14 
    15 
    16 int main()
    17 {
    18     int a = 3;
    19     int b = 5;
    20     
    21     huhuan(a,b);
    22     
    23     printf("%d %d",a,b);
    24     
    25     system("pause");
    26     return 0;
    27 }
    28 /*
    29 
    30     这个程序是错误的
    31 */
    互换两个数字_1
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 //不能完成互换功能
     4 void huhuan(int * p , int * q )
     5 {
     6     int * t; //如果要互换p和q的值,则t必须是int *,不能是int,否则会出错
     7     
     8     t = p;
     9     p = q;
    10     q = t;
    11     
    12     
    13     return;
    14 }
    15 
    16 
    17 int main()
    18 {
    19     int a = 3;
    20     int b = 5;
    21     
    22     huhuan(&a,&b); //huhuan_2(*p,*q);是错误的,huhuan(a,b);也是错误的
    23     
    24     printf("%d %d",a,b);
    25     
    26     system("pause");
    27     return 0;
    28 }
    29 /*
    30 
    31     这个程序是错误的
    32 */
    互换两个数字_2
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 void huhuan(int * p , int * q )
     4 {
     5     int t;  //如果要互换*p和*q的值,则t必须的定义成int,不能定义成 int*,否则语法会出错
     6     
     7     t = *p;   //p是int *, *p是int
     8     *p = *q;
     9     *q = t;
    10     
    11     
    12     return;
    13 }
    14 
    15 
    16 int main()
    17 {
    18     int a = 3;
    19     int b = 5;
    20     
    21     huhuan(&a,&b); //huhuan_2(*p,*q);是错误的,huhuan(a,b);也是错误的
    22     
    23     printf("%d %d",a,b);
    24     
    25     system("pause");
    26     return 0;
    27 }
    28 /*
    29     这个程序是正确的
    30 */
    互换两个数字_3 
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 int main(void)
     4 {
     5     int * p; //等价于int *p; 也等价于 int* p;
     6     int i = 5;
     7     char ch = 'A';
     8     
     9     p = &i;  // *p 以p的内容为地址的变量
    10     *p = 99;
    11     printf("%d
    ",i);
    12     //p = &ch; //error 不能是字符变量地址
    13     //p = ch; //error
    14     // p = 5; //error
    15     
    16     system("pause");
    17     return 0;
    18 }
    基本类型指针 
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 //f函数可以输出任何一个一维数组的内容
     5 void f(int * pArr, int len)
     6 {
     7     int i ;
     8     
     9     for(i=0; i<len; ++i)
    10         printf("%d ",*(pArr+i)); //*pArr *(pArr+1) *(pArr+2)
    11     printf("
    ");
    12 }
    13 int main(void)
    14 {
    15     int a[5] = {1,2,3,4,5,6};
    16     int b[6] = {-1,-2,-3,-4,5,-5};
    17     int c[100] = {1,99,22,33};
    18     
    19     f(a,5);
    20     f(b,6);
    21     f(c,100);
    22      
    23     system("pause");
    24     return 0;
    25 }
    一维数组指针_1 
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 void f(int * pArr, int len)
     5 {
     6     int i;
     7     for(i=0; i<len; ++i)
     8         printf("%d ",pArr[i]); //*(pArr+i0等价于 pArr[i] 也等价于b[i] 也等价于 *(b+i)
     9 }
    10 int main(void)
    11 {
    12     int b[6] = {1,2,3,4,5,6};
    13     f(b,6);
    14     b[i]
    15     system("pause");
    16     return 0;
    17 }
    一维数组指针_1 
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 int main(void)
     5 {
     6     int i = 5;
     7     int j = 10;
     8     int * p = &i;
     9     int * q = &j;
    10     int a[5];
    11     p = &a[1];
    12     q = &a[4];
    13     printf("p和q所指向的单元相隔%d个单元
    ",q-p);
    14     system("pause");
    15     return 0;
    16 }
    指针变量运算
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 int main()
     4 {
     5 
     6     char ch = 'A';
     7     double x = 66.6;
     8     int i = 99;
     9     char *p = &ch;
    10     int *q = &i;
    11     double *r = &x;
    12     printf("%d  %d  %d",sizeof(p),sizeof(q),sizeof(r));
    13    
    14      system("pause");
    15     return 0;
    16 }
    指针占用多少个字节
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 void g(int * pArr, int len)
     4 {
     5     pArr[2] = 88;    //pArr[2] == a[2]
     6 }
     7 
     8 void f(void)
     9 {
    10     int a[5] = {1,2,3,4,5}; //20个字节的存储空间程序员无法手动编程释放它
    11                             //它只能在本函数运行完毕时由系统自动释放                    
    12     g(a,5);
    13     printf("%d
    ",a[2]);
    14 }
    15 
    16 int main(void)
    17 {
    18 
    19     f();
    20      system("pause");
    21     return 0;
    22 }
    静态数组
     1 /*
     2     malloc 是 memory(内存) allocate(分配)的缩写
     3 */
     4 
     5 #include <stdio.h>
     6 #include <stdlib.h>
     7 #include <malloc.h>  //不能省
     8 
     9 int main(void)
    10 {
    11     int i = 5; //分配的4个字节 静态分配
    12     int * p = (int *)malloc(4);
    13         /*
    14             1. 要使用malloc函数,必须添加malloc.h,这个头文件
    15             2. malloc函数只有1个形参,并且形参是整数类型
    16             3. 4表示请求系统为本程序分配4个字节
    17             4. malloc函数只能返回第一个字节的地址
    18             5. 12行分配了8个字节,p变量占4个字节,p指向的内存也占4个字节
    19             6. p本身所占的内存是静态的分配的,p所指向的内存是动态分配的
    20         */
    21     *p = 5; //*p 代表的就是一个int变量,只不过*p这个整型变量的内存分配方式和11行的i变量分配方式不同
    22     free(p); //free(p)表示把p所指向的内存释放掉,p本身的内存是静态对,不能有程序员手动释放,p本身的内存只能在p变量所在的函数运行终止时由系统自动释放
    23     printf("同志们好!
    ");
    24      system("pause");
    25     return 0;
    26 }
    malloc函数的用法_1 
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <malloc.h> 
     4 
     5 void f(int * q)
     6 {
     7     //*p = 200; //error
     8     //q = 200; //error
     9     *q = 200;
    10     //free(q); //把q所指向的内存释放掉 , 本语句必须得注释掉,否则会导致第20行的代码出错       
    11 }
    12 int main(void)
    13 {
    14     int *p = (int *)malloc(sizeof(int)); //sizeof(int)返回值是int所占的字节数
    15     *p = 10;
    16     
    17     printf("%d
    ",*p);
    18     f(p);  //p是int *类型
    19     printf("%d
    ",*p);
    20     
    21     system("pause");
    22     return 0;
    23 }
    malloc函数的用法_2
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <malloc.h> 
     4 
     5 int main(void)
     6 {
     7     int a[5]; //如果int占4个字节的话,则本数组总共包含20个字节,每四个字节被当作一个int变量来使用
     8     int len;
     9     int * pArr;
    10     int i;
    11     
    12     //动态的构造一维数组
    13     printf("请输入你要存放的元素的个数:");
    14     scanf("%d",&len);
    15     pArr = (int *)malloc(4*len); //本行动态的构造了一个一维数组,该一维数组的长度是len ,该数组的数组名是pArr,该数组的每个元素是int类型,类似于 int pArr[len];
    16    
    17    //对一维数组进行操作
    18    //对动态一维数组进行赋值  如:对动态一维数组进行赋值
    19     for(i=0; i<len; ++i)
    20         scanf("%d",&pArr[i]);
    21         
    22     //对一维数组进行输出
    23     printf("一维数组的内容是:
    ");
    24     for(i=0; i<len; ++i)
    25         printf("%d
    ",pArr[i]);
    26     
    27     free(pArr); //释放掉动态分配的数组
    28     system("pause");
    29     return 0;
    30 }
    动态内存分配举例
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <malloc.h> 
     4 
     5 int main(void)
     6 {
     7     int i = 10;
     8     int * p = &i;
     9     int ** q = &p;
    10     int *** r = &q;
    11     
    12     //r = &p; //因为r是int ***类型,r只能存放int **类型变量的地址
    13     printf("i = %d
    ",***r);
    14     
    15     system("pause");
    16     return 0;
    17 }
    多级指针 
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <malloc.h>
     4 
     5 void f(int *** r)
     6 {
     7     int i = 15;
     8     **r = &i;
     9 
    10 }
    11 int main(void)
    12 {
    13     int i = 10;
    14     int * p = &i;
    15     int ** q = &p;
    16     
    17     printf("%d
    ",**q);
    18     
    19     f(&q);
    20     printf("%d
    ",**q);
    21     system("pause");
    22     return 0;
    23 }
    使用多级指针_1
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <malloc.h>
     4 
     5 void f(int ** q)
     6 {
     7     
     8     **q = 1000;
     9 }
    10 
    11 void g()
    12 {
    13     int i = 10;
    14     int * p = &i;
    15     f(&p);
    16     printf("%d
    ",*p);
    17 }
    18 int main(void)
    19 {
    20     g();
    21     system("pause");
    22     return 0;
    23 }
    使用多级指针_2
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <malloc.h>
     4 
     5 void f(int ** q) //q是个指针变量,无论q是什么类型的指针变量,都只占4个字节
     6 {
     7     int i = 5;
     8     //*q等价于p q和**q都不等价于p
     9     //*q = i; //error 因为*q = i; 等价于 p = i;这样写是错误的
    10     *q = &i; //p = &i;
    11 }
    12 int main(void)
    13 {
    14     int *p;
    15     f(&p);
    16     // 15行已经把f()给释放了
    17     printf("%d
    ",*p);  //本语句语法没有问题,但逻辑上有问题。
    18     
    19     system("pause");
    20     return 0;
    21 }
    静态内存不可以跨函数使用
     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <malloc.h>
     4 
     5 void f(int ** q) 
     6 {
     7     *q = (int *)malloc(sizeof(int)); //sizeof(数据类型)返回值是该数据类型所占的字节
     8                 //等价于 p = (int *)malloc(sizeof(int));
     9     //q = 5;
    10     //*q = 5; //error p = 5;
    11     **q = 5;//*p = 5;
    12 }
    13 int main(void)
    14 {
    15     int *p;
    16     f(&p);
    17 
    18     printf("%d
    ",*p); 
    19     
    20     system("pause");
    21     return 0;
    22 }
    动态内存可以跨行数使用
  • 相关阅读:
    算法分析(3)——冒泡排序真的慢吗?
    算法分析(2)——大O和大Θ
    算法分析(1)——数据的影响和函数的增长
    递归的逻辑(5)——米诺斯的迷宫
    递归的逻辑(4)——递归与分形
    李洪强和你一起学习前端之(9)规避脱标,CSS可见性,滑动门案例
    iOS应用管理(优化)
    iOS开发-应用管理
    iOS开发-Tom猫
    iOS 10.3.3 更新背后的故事
  • 原文地址:https://www.cnblogs.com/Maxwell599/p/3175527.html
Copyright © 2011-2022 走看看