zoukankan      html  css  js  c++  java
  • C语言学习7 :二级指针定义,强制转换,多级指针初步,6级指针构造,错误应用*p=&a,错误应用 二级p2,void型指针的兼容性,malloc函数基本用法,malloc分配空间和堆栈空间的区别,验证malloc函数内存的分配,验证malloc函数的越界,内存泄漏,指针不能返回局部变量地址,内存分配

    1,二级指针定义

    
    #include <stdio.h>
    {
         //int**   p;
        //p2是二级指针,是一个变量,
       //p2本身是int **类型
      //p2 指向 int *   类型      
    
    
    
         int **p2=NULL;
         int *p1=NUL;
         int a=8;
         
         p1=&a;
         p2=&p1;
    //   p2 --------》*p2 ----------》 **p2
    //   int**         int *                 int
    
          printf(“a=%d, **p2=%d
    ”,a,**p2);
        return 0;
    }

    结果:

    a = 8, **p2 = 8

    2,强制转换

    #include <stdio.h>
    
    int main(void)
    {
         unsigned long  p2=0;
         int *p1=NULL;
         int a=8;
    
         P1=&a;
         p2=(unsigned long)&p1;   //强制转换,因为p2是无符长整型,此时p2只是存储p1地址的无符号长整型,不是指针
    **(int **)p2=16; //int **是定义 p2是二级指针型整型,强制赋值, printf(“a=%d,**p2=%d ”,a,**(int **)p2); }

    结果:

    a = 16, **p2 = 16

    3,多级指针,本质上是二级指针。

     #include <stdio.h>
    
    int main(void)
    {
       int ******p6=NULL;
       int   *****p5=NULL;
    
       int a=8;
    
       p5=(int *****)&a;   //五级指针变量获得a的地址,并且把地址变成五级指针整型
       p6=&p5;               //指针变量p6获得指针变量p5的地址,指向p5。
       
       printf(“a=%d,**p6=%d
    ”,a,**p6);
    
       return 0;
    }

    结果:

    a = 8, **p6 = 8

    4,6级指针构造

    #include <stdio.h> 
       
       int main(void) 
      { 
             int ******p6=NULL; 
             int *****p5=NULL; 
             int ****p4=NULL; 
             int ***p3=NULL; 
             int **p2=NULL; 
             int *p1=NULL;//构建六级指针定义 
    
             int a=8; 
    
             p1=&a,p2=&p1,p3=&p2, 
             p4=&p3,p5=&p4,p6=&p5;//六级指针赋值 
    
             printf("a=%d,******p6=%d
    ",a,******p6); 
    
             p6=&p5,p5=&p4,p4=&p3, 
             p3=&p2,p2=&p1,p1=&a;//反方向也是一样的效果 
      
             printf("a=%d,******p6=%d
    ",a,******p6);
             
             return 0;
    }

    结果:

    a = 8, ******p6 = 8
    a = 8, ******p6 = 8

    5,错误应用*p=&a,

    #include <stdio.h> 
    
    int main(void) 
    { 
            int **p2; 
    
            int a=8; 
    
            //p2中是一个随机值
            //*p2 访问一个随机地址, 
            *p2=&a; //这个表示将a的地址传给指针p2指向的变量,p2的指向完全未知
                            //不过这样单独写是不对的除非是指向指针的指针,但是关系未名。
                            //要这样才行int *p=&a;等于 int *p;p=&a
    
            printf("a=%d,**p2=%d
    ",a,**p2); 
    
            return 0; 
    } 

    结果:

    Segmentation fault (core dumped)

    6,错误应用 二级指针p2

    #include <stdio.h> 
    
    int main(void) 
    { 
            int **p2=NULL; 
            int *p1=NULL; 
            int  a=8; 
    
            p2=(int **)&a; 
            //*p2已经是a,a==8 
            //**p2 *(*p2)在访问地址 8   
            printf("a=%d,**p2=%d
    ",a,**p2); 
    
            return 0; 
    } 

    结果:

    Segmentation fault (core dumped)

    7,void型指针的兼容性

    #include <stdio.h> 
    
    int main(void) 
    {    
            //p2本身是int **类型 
            //p2 指向int *类型 
            int *  *p2=NULL; 
            int    *p1=NULL; 
            //pv2自己是void **类型 
            //pv2指向void *类型 
            void * *pv2=NULL; 
            //pv1是void *类型,void *类型和所有指针类型兼容 
            //pv1 指向void 类型(void 类型和所有类型兼容)。 
            void   *pv1=NULL; 
    
            int a =16;
            p1=&a; 
            p2=&p1; 
             //类型不兼容,强制转换后兼容。原本pv2是 void **类型
            pv2=(void *)p2; 
             //类型兼容 ,因为强制转换的原因。pv2变成void *型,所以就可以赋值。
            pv1=pv2; 
    
            printf("a=%d,**pv2=%d
    ",a,**(int **)pv2); 
    
            printf("--------------------
    "); 
    
            printf("a=%d,**pv1=%d
    ",a,**(int **)pv1); 
            printf("a=%d,**pv1=%d
    ",a,*(int *)(*(unsigned long *)pv1)); 
    
            return 0; 
    } 

    结果:

    a=16,**pv2=16 
    -------------------- 
    a=16,**pv1=16 
    a=16,**pv1=16 

    8,malloc函数基本用法

    #include <stdio.h> 
    #include <stdlib.h> 
    //分配内存空间,指针变量p作为函数malloc()的返回值 
    //括号内的32代表开辟的字节长度,为32字节。 
    //p其实存的是开辟空间的首地址,你可以把它当作一维数组
    //别忘了还要释放空间free(); 
    int main(void) 
    { 
            int *p=NULL; 
    
            p=malloc(32); 
            if(NULL==p) 
                    goto err1; 
    
            int i; 
            for(i=0;i<8;i++)//产生随机值赋值 
            {   
                    *(p+i)=rand()%100; 
            }   
            printf("___________________________________
    "); 
    
            for(i=0;i<8;i++)//打印输出 
            {   
                    printf("%d  ",*(p+i)); 
            } 
            putchar('
    '); 
            free(p); 
    
            return 0; 
    err1: 
            return 1; 
    
    } 

    结果:

    ___________________________________ 
    83  86  77  15  93  35  86  92 

    9,malloc分配空间和堆栈空间的区别

    #include <stdio.h> 
    #include <stdlib.h> 
    //全局变量存储在静态数据库中,extern用在main函数里声明全局变量 
    //局部变量放在栈区,函数退出时将其释放 
    //malloc()函数分配的空间在堆区。返回一个指向该空间的void指针。 
    int a=36; 
    
    int main(void) 
    { 
            int *ptr_heap = NULL; 
            int *ptr_dseg = NULL; 
            int *ptr_stack= NULL; 
    
            int b=18; 
    
            ptr_dseg= &a;//获取外部变量地址 
            ptr_stack=&b;//获取局部变量地址 
            ptr_heap = malloc(4);//获取分配空间的地址 
    
            printf("pointer point to data segment,ptr_dseg=%p
    ",ptr_dseg); 
            printf("pointer pointer to stack, ptr_stack=%p
    ",ptr_stack); 
            printf("pointer point to heap,ptr_heap=%p
    ",ptr_heap); 
    
           free(ptr_heap); 
    
            return  0; 
    }

    结果:

    pointer point to data segment,ptr_dseg=0x11030 
    pointer pointer to stack, ptr_stack=0xbefc0190 
    pointer point to heap,ptr_heap=0x1aba008 

    10,验证malloc函数内存的分配

    #include <stdio.h> 
    #include <stdlib.h> 
    //验证内存的分配,其实是两次在同一个地址区间内进行 
    int main(void) 
    { 
            int *p=NULL; 
            int *p1=NULL; 
    
            p=malloc(20); 
            printf("p=%p
    ",p); 
            int i; 
            for(i=0;i<5;i++) //赋值
            {   
                    *(p+i)=rand()%100; 
            }   
    
            for(i=0;i<5;i++) //打印
            {   
                    printf("%d ",*(p+i)); 
            }   
            putchar('
    '); 
            free(p); 
    
            printf("================================
    "); //下同
    
            p1=malloc(20); 
            printf("p1=%p
    ",p1); 
    
            for(i=0;i<5;i++) 
                    *(p+i)=rand()%100; 
            for(i=0;i<5;i++) 
                    printf("%d ",*(p+i)); 
             putchar('
    '); 
             free(p1); 
    
            return 0; 
    } 

    结果:

    p=0x27a008 
    83 86 77 15 93 
    ================================ 
    p1=0x27a008 
    35 86 92 49 21     

    11,验证malloc 函数的越界效果以及free掉之后又开始填充的效果

    #include <stdio.h> 
    #include <stdlib.h> 
    // 此式子验证越界的效果 
    int main(void) 
    { 
            int *p=NULL; 
    
            p=malloc(20); 
    
            int i; 
            //越界内存访问,这个是觉对的错误的代码 
            //但在多数情况下会运行成功 
            for(i=0;i<6;i++)//只有20个字节空间,可是全赋值了24个字节空间数 
                    *(p+i)=rand()%100; 
            for(i=0;i<6;i++) 
                    printf("%d ",*(p+i)); 
            putchar('
    '); 
    
            free(p); 
            //内存已经free,绝对错误的代码 
            //但多数情况下会运行成功 
            for(i=0;i<6;i++) 
                    *(p+i)=rand()%100; 
            for(i=0;i<6;i++) 
                    printf("%d ",*(p+i)); 
            putchar('
    '); 
    
            return 0; 
    } 
     

    结果:结果是看运气的

    83 86 77 15 93 35 
    86 92 49 21 62 27 

    12,内存泄漏

    #include <stdio.h> 
    #include <stdlib.h> 
    //关于内存泄漏 
    
    void get_mem(int *p,int len) 
    {    
            //局部变量p拿到了内存 
           //但出了函数,p被释放掉,但内存继续占用,这个就是内存泄漏 
           p=malloc(sizeof(int)*len);//这个让我想起,*p=&a的方式。
                                                            //int *p=&a,其实就是(int *) p=&a. *P并不存在,是类型为     
                                                            //int *的指针变量得到a的地址而已
           
    } 
    
    void *get_mem1(int len) 
    { 
            //这个是返回一个一级指针变量,所以要首先定义一个指针变量,然后赋值。
            int *p=NULL; 
            p=malloc(sizeof(int)*len); 
            return p; 
    } 
    
    void get_mem2(int **pcallee,int len)  //&p是二级指针变量,p是一级指针变量。*p是值
    { 
            *pcallee=malloc(sizeof(int)*len); //这个*pcallee也就是传递p的值而已
    } 
    int main(void) 
    { 
            int *p=NULL; 
    
            get_mem(p,10); 
            printf("p=%p
    ",p); //p含有分配空间首地址的指针变量
    
            printf("====================
    "); 
    
            p=get_mem1(10); 
            printf("p=%p
    ",p); 
    
            printf("====================
    "); 
    
            get_mem2(&p,10); 
            printf("p=%p
    ",p); 
    
            free(p); 
    
    
    
            return 0; 
    }       

    结果:get_mem是内存泄漏,出现了局部int *p变量拿到内存,当时他出门就释放了,就会出现p=(nil),但是系统没看到free,就认为没有释放。

    所以malloc函数只能使用二级指针和返回指针

    p=(nil) 
    ==================== 
    p=0x1a35038 
    ==================== 
    p=0x1a35068 

    13,指针不能返回局部变量地址

    #include <stdio.h> 
    //指针编程原则:不要返回函数栈内的局部变量的地址
    //换句话说,不要返回指向栈内局部变量的指针
    //因为出了函数,局部变量被销毁,这个地址也就没有意义了。
    int *add(int l,int r) 
    { 
            int ret; 
            ret=l+r; 
            return &ret; 
            //不能返回地址,可以加个指针变量,存储地址返回,比如int  *p=&ret;return p;就不会有
            //警告了,如果不改结果依然是8,但是清零失败。
    } 
    
    void just_wipe_stack(void) 
    { 
            char s[1000]={0}; 
    } 
    
    int main(void) 
    { 
            int a=3,b=5; 
            int *p=NULL; 
    
            p=add(a,b); 
    
    printf("ret=*p=%d
    ",*p); 
    
            just_wipe_stack(); 
    
            printf("ret=*p=%d
    ",*p); 
            return  0; 
    
    } 

    结果:

    未更改:
    13ptrlocalvar.c: In function ‘add’:
    13ptrlocalvar.c:12:2: warning: function returns address of local variable [enabled by default]
    will@will-Inspiron-N4010:~/c/6th$ ./a.out
    ret = *p = 8
    ret = *p = 0
    更改:
    ret = *p = 8
    ret = *p = -1216790540

    14.内存分配 m多少行,n多少个

    #include <stdio.h>
    #include <stdlib.h>
    //这个程序按结果看是形成一个二维数组
    //重点是做怎么进行二维内存分配,重点在于alloc_mem()函数的操作int **alloc_mem(int row,int col)
    {
        int **p=NULL;//返回二级指针变量就要在此赋值,
    
        p=malloc(sizeof(int *)*row);//得到行空间,因为行要指向列的地址
                                    //所以是int *指针型整型
        if(NULL==p)
            goto err0;//内存分配出错处理
        int i,j;
        for(i=0;i<row;i++)//循环走完行
        {
            *(p+i)=malloc(sizeof(int)*col);//每行指向一列的空间
                if(NULL==p[i])
                    goto err1;
        }
        return p;
    err1:
        for(j=0;j<i;j++)//清空行就行了
            free(p[j]);
        free(p);//释放完后往下走,返回退出
    err0:
        return NULL;
    }
    
    void rand_mem(int **p,int row,int col)//就是二维数组的做法
    {
        int i,j;
        for(i=0;i<row;i++)
            for(j=0;j<col;j++)
                *(*(p+i)+j)=rand()%100;      
    }
    
    void print_mem(int **p,int row,int col)//这个也同上
    {
        int i,j;
        for(i=0;i<row;i++)
        {    for(j=0;j<col;j++)
                printf("%d ",p[i][j]);
            printf("
    ");
        }    
               
    }
    
    void free_mem(int **p,int row)
    {
        int i;
        for(i=0;i<row;i++)
            free(*(p+i));
        free(p);
    }
    
    int main(void)
    {
        int m,n;
        int **p=NULL;
    
        printf("int put m & n:");
        scanf("%d%d",&m,&n);
    
        p=alloc_mem(m,n);
    
        rand_mem(p,m,n);
        print_mem(p,m,n);
    
        free_mem(p,m);
    
        return 0;
    }        

    结果:

    will@will-Inspiron-N4010:~/c/6th$ ./a.out
    pls input m & n: 5 4
    83 86 77 15 
    93 35 86 92 
    49 21 62 27 
    90 59 63 26 
    40 26 72 36 
  • 相关阅读:
    Python 使用正则表达式匹配URL网址
    第3章 网络爬虫基础
    《精通Python网络爬虫》
    /etc/hosts
    Linux alias 命令
    file()
    Win10 取消桌面快捷键图标
    Win10 我的电脑 -- 右键点击管理打不开
    MongoDB 备份恢复
    ORACLE 日期比较
  • 原文地址:https://www.cnblogs.com/will-boot/p/3303241.html
Copyright © 2011-2022 走看看