首页 > 编程知识 正文

一级指针和二级指针,二级指针指向一级指针

时间:2023-05-03 14:24:52 阅读:231314 作者:2767

一、一级指针

如下图所示,整型指针xptr指向变量x的地址。

int *xptr;int x=10;xptr = &x;


源码:

#include <stdio.h>int main(){ int *xptr = NULL; int x = 10; xptr = &x; printf("x = %d, *xptr = %dn", x, *xptr); printf("&x = %p, xptr = %pn", &x, xptr); return 0;}

二、二级指针

实现方法一
如下图所示,先为二级整型指针ptr分配空间,然后赋值。

int **ptr=NULL;int num=4, size=4, i,j;ptr = (int **)malloc(num*sizeof(int*));for(i=0; i<num; ++i){*(ptr+i) = (int *)malloc(size*sizeof(int));*(*(ptr+i) +j)=(i+1)*j;}


源码:

#include <stdio.h>#include <stdlib.h> int main(){ int **ptr = NULL; int num=4, size=4, i, j; ptr = (int **)malloc(num * sizeof(int *)); for(i=0; i<num; ++i) { *(ptr+i) = (int *)malloc(size * sizeof(int)); for(j=0; j<size; ++j) *(*(ptr+i)+j) = (i+1)*j; } for(i=0; i<num; ++i) { for(j=0; j<size; ++j) { printf("(%d, %d) -> %dt", i, j, *(*(ptr+i)+j)); } printf("n"); } return 0;}

运行结果:

实现方法二
如下图所示,先为二级整型指针ptr分配空间,然后赋值。
与实现方法一的不同之处,在于使用数组形式就行相关操作。

int **ptr=NULL;int num=4, size=4, i;ptr = (int **)malloc(num*sizeof(int*));for(i=0; i<num; ++i){ptr[i]= (int *)malloc(size*sizeof(int));ptr[i][j]=(i+1)*j;}


源码:

#include <stdio.h>#include <stdlib.h>int main(){ int **ptr = NULL; int num=4, size=4, i, j; ptr = (int **)malloc(num * sizeof(int *)); for(i=0; i<num; ++i) { ptr[i] = (int *)malloc(size * sizeof(int)); for(j=0; j<size; ++j) { ptr[i][j] = (i+1)*j; } } for(i=0; i<num; ++i) { for(j=0; j<size; ++j) { printf("[%d, %d] -> %dt", i, j, ptr[i][j]); } printf("n"); } return 0;}

运行结果:

先看两个例子:

*p和**p的区别
int *p :一级指针,表示p所指向的地址里面存放的是一个int类型的值
int **p :二级指针,表示p所指向的地址里面存放的是一个指向int类型的指针(即p指向的地址里面存放的是一个指向int的一级指针)
例如:
int i=10; //定义了一个整型变量
int *p=&i; //定义了一个指针指向这个变量
int **p1=&p; //定义了一个二级指针指向p指针
那么取出10的值方式为:
printf(“i=[%d]n”,*p);
printf(“i=[%d]n”,**p1);

void test(char *p){ printf("[test1][p]:%p.n",p); printf("[test2][p]:%s.n",p); p=(char *)malloc(10); strcpy(p,"ABCDE"); printf("[test3]malloc之后.....n"); printf("[test4][p]:%p.n",p); printf("[test5][p]:%s.n",p); free(p);} int main(){ char b[6] = "abcde"; char *a = b; printf("[main1][a]:%p.n",a); printf("[main2][a]:%s.n",a); test(a); printf("[main3][a]:%p.n",a); printf("[main4][a]:%s.n",a); return 0;}

输出结果: 注意:(test函数的pde值已改变,main函数的a的值未改变)

main1][a]:0xbfeaaef6.
[main2][a]:abcde.
[test1][p]:0xbfeaaef6.
[test2][p]:abcde.
[test3]malloc之后…
[test4][p]:0x8a52008.
[test5][p]:ABCDE.
[main3][a]:0xbfeaaef6.
[main4][a]:abcde.

void test(char **p){ printf("[test1][p]:%p.n",p); printf("[test2][*p]:%p.n",*p); *p=(char *)malloc(10); strcpy(*p,"ABCDE"); printf("[test3]malloc之后.....n"); printf("[test4][p]:%p.n",p); printf("[test5][*p]:%p.n",*p); printf("[test6][*p]:%s.n",*p); free(*p);} int main(){ char b[6] = "abcde"; char *a = b; printf("[main1][a]:%p.n",a); printf("[main2][a]:%s.n",a); test(&a); printf("[main3][a]:%p.n",a); printf("[main4][a]:%s.n",a); return 0;}

输出结果: 注意:(test函数的pde值已改变,main函数的a的值也已经改变)

[main1][a]:0xbfaca776.
[main2][a]:abcde.
[test1][p]:0xbfaca770.
[test2][*p]:0xbfaca776.
[test3]malloc之后…
[test4][p]:0xbfaca770.
[test5][*p]:0x9132008.
[test6][*p]:ABCDE.
[main3][a]:0x9132008.
[main4][a]:ABCDE.

三、形参和实参的概念?

实参:实实在在的参数,我们自己定义的,比如以上程序中指针a和数组b都是实参,都是自己定义的,基本程序中花括号内定义的所有参数都是实参

形参:我们定义一个函数时,括号内的参数,比如以上程序中的char *p和char **p中的p就是形参,主要是为了让实参的数据可以传递到函数内,供函数操作

四、参数传递的实质?

参数的传递分为两种,一种是值传递,另一种是引用;我们这里说的只主要是值传递,暂时不说引用传递;值传递又分为两种:一种是实际的值传递,int类型的参数传递属于实际值传递;另一种就是地址值传递,实参比实际地址传递给形参,比如指针就是地址值传递。

这里是参数传递的重点,当实参把实际值或者地址值传递给形参时,实际上不是直接使用实参,而是在栈去开辟内存空间copy一个副本,int a的副本是_a(_a=a),,char *p的副本是_p(_p=p), 所以函数内的操作都是对副本进行操作,改变形参的值不会影响实参的值,函数执行完就释放副本开辟的空间。

五、为什么要用指向指针的指针?

指针的概念,指针也是一个参数,和int及char类似,int 参数存放整数,char参数存放字符,指针存放的是一个地址而已;指针就是保存一片内存的起始地址,知道这个指针就可以对这个指针指向的内存进行操作;指向指针的指针即二级指针保存的是一级指针的地址,比如:

p是一级指针,保存的是a的地址;q是指向指针的指针(二级指针),保存的是一级指针(p)的地址;q的内容就是0xbfaca770,q的值即q指向的内容0xbfaca776,即q仍然是一个地址,也就是指针p的内容,即q=p,(好好理清楚),对q操作就是对p指向的内存操作;为什么要使用二级指针呢?下面会有讲述:

六、为什么第一个程序不能改变a的值,而第二个程序却可以? 第一个程序:

我们先看看调用test函数前后,以及malloc之前和malloc之后的指针p的和指针a的地址以及指向情况:

之前的指向情况:(方块上面是当前变量的地址,方块内是当前变量的值)

之后的指向情况: (方块上面是当前变量的地址,方块内是当前变量的值)

从之前的情况可以看出,函数进行参数传递时,实参把地址传给了形参p(p即是a的副本(_a),p=_a是为了表达更直观,并不会产生变量名_a),两个指针同时指向一片内存;使用malloc之后,空出一遍新内存并把地址赋给p,即p的指向改变,指向了新地址;所以test内对p的内容进行改变不会改变a的值。

第二个程序:

同样先看看调用test函数前后,以及malloc之前和malloc之后的指针p的和指针a的地址以及指向情况:

之前的指向情况:

之后的情况:

好了,我们来看一下,test函数的形参使用的是二级指针,我们把a的地址传给了p,即p指向了a;指针a指向的是数组b,即保存的是b的首地址,见第二个程序第一张图;二级指针p指向一级指针a,所以p的值就是a的首地址,所以改变p的内容就是改变a的内容,即改变a的指向;当malloc一段内存并把首地址保存在p的内容中,就是把malloc内存的首地址直接替换指针a原来的内容,所以a指针的指向发生了改变,见第二个程序第二张图;所以改变p就是改变a的值(要理解*p和a就是同一个变量);

所以要对实参传进来的指针进行直接操作的话,就可以使用二级指针,把实参的地址传给二级指针,通过二级指针去改变一级指针的值。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。