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 
原文地址:https://www.cnblogs.com/will-boot/p/3303241.html