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