加深理解指针的四个实验

来源:互联网 发布:大数据的统计学基础 编辑:程序博客网 时间:2024/06/06 15:04

最近在做有关进程通信的管道的实验的过程中,遇到了一个C语言中指针的问题。这个问题其实以前也遇到过,不过长时间不用,大概忘了,这次特地做一个总结,以加强记忆。

关于指针的基本内容在此就不介绍了。直接根据代码解释:

1)void test0(int p){    printf("p is %d(in sub function).\n",p);    p = 10;    printf("p is %d(in sub function).\n",p);}int main(){    int i = 5,*p = &i;    test0(i);    printf("i is %d.\n",i);  return 0;}

代码分析:以上的测试是一个最经典的指针使用错误。想要通过test0()函数改变传入变量的值。但实际上在主函数中并没有改变i的值(只在test0()函数中临时改变了i的值)。程序原理很简单,在此不再多说,只从内存分配的角度展示其执行的过程,其流程中内存结构图如下:

这里写图片描述

2)void test1(int *p){     printf("p is:%#X(in sub function)\n",p);     printf("*p is %d.\n(in sub function)",*p);     *p = 10;   printf("p is:%#X(in sub function)\n",p);     printf("*p is %d.(in sub function)\n",*p);}int main(){int i = 5,*p = &i;    printf("p is:%#X(in main function)\n",p);    printf("*p is %d.(in main function)\n",*p);    test1(p);    printf("p is:%#X(in main function)\n",p);    printf("*p is %d.(in main function)\n",*p);  return 0;}

代码分析:以上的函数test1()利用指针在函数内部改变了传入变量的值。内存流程图如下:

这里写图片描述

在这里要注意每个内存空间都有一个地址。p的内容(内存空间,即图中大的矩形)是变量i的地址。&p是变量p的地址。

(3)void test2(int* p){    printf("before memory allocation(in sub function): p is %#X.\n",p);    printf("before memory allocation(in sub function): *p is %d.\n",*p);    p = (int *)malloc(sizeof(int));    *p = 10;    printf("after memory allocation(in sub function): p is %d.\n",p);    printf("after memory allocation(in sub function): *p is %#X.\n",*p);}int main(){    int i = 5,*p = &i;     printf("before memory allocation(in main): p is %#X.\n",p);     printf("before memory allocation(in main): *p is %d.\n",*p);     test2(p);     printf("after memory allocation(in main): p is %#X.\n",p);     printf("after memory allocation(in main): *p is %0d.\n",*p);  return 0;}

代码分析:以上的程序,是想在主函数中传入一个指针变量p。然后在test2函数中用p指向一段(在这里为了描述方便只申请了一个单元)新动态申请的内存空间,返回给主函数。这个程序是实现不了这个功能的。虽然传入的是指针,但犯得错误从某种角度上说,和(1)中的类似。程序的内存分配流程图如下:

这里写图片描述

和上面(2)一样在①中,p的内容是i变量的地址,*p就是i变量所定义的内存空间,其值是5。
然后在②中,重新申请了一个内存趋于,p的内容不再是i变量的地址,而是新申请的那块内存的地址。*p自然是新申请的那块内存区域的内容。
在③中,对*p进行赋值10。当然不会影响原来的i变量了。
运行程序,看出其地址的变化。
在此说和第(1)种情况类似,是因为第一种情况的p变量是系统自动分配的局部变量。这里是我们动态分配的变量。最后都没有改变i变量的值,是因为在赋值之前,p或者*p已经不是原来的i变量的地址空间了。

4)void test3(int **p0){   printf("before memory allocation(in sub function): *p0 is %#X.\n",*p0);   printf("before memory allocation(in sub function): **p 0 is %d.\n",**p0);    *p0 = (int *)malloc(sizeof(int));    *(*p0) = 10;   printf("after memory allocation(in sub function): *p0 is %#X.\n",*p0);   printf("after memory allocation(in sub function): **p0  is %0d.\n",**p0);}int main(){     int i = 5,*p = &i;     printf("before memory allocation(in main): p is %#X.\n",p);     printf("before memory allocation(in main): *p is %d.\n",*p);     test3(&p);     printf("after memory allocation(in main): p is %#X.\n",p);     printf("after memory allocation(in main): *p is %0d.\n",*p);  return 0;}

代码分析:这个程序用到了二重指针实现了(3)中没实现的功能。内存分配图如下:

这里写图片描述

在①中和(2)中的一样。
在②中,传入的是指针变量p的地址&p,即p0 = &p。此时*p0为p的内容,即&i(变量i的地址)。**p0为变量i的内容(内存空间),其值为5。
在③中进行了动态的内存分配,使得*p0(即p的内容)指向了新的分配的内存地址。**p0即是新分配的内存空间。
在④中,对**p0(即*p)进行赋值10。
最后程序返回的时候*p的内容即是10。
在这里需要注意的是,在子函数中*p0(即p的内容)已经不是指向了原来的i的地址,而是重新动态分配的内存地址。所以确切的说,在test3()内部并不是改变了原来i的内容,而是使p重新指向了一块新的内存空间。

总结:如果有这样一个需求,即在主函数中传入一个指针给子函数,然后在子函数中进行动态的内存分配,把使得这个传入的指针可以带回来一段动态分配的内存空间,应该使用二重指针(或者是C++中指针的引用)。还有一种方法,就是在主函数中把动态的内存空间分配好,然后仅仅在子函数中修改内存中的内容,这样直接使用普通的一维指针就行(像(2)中一样)。

原创粉丝点击