C++ 指针详细分析(转)

原以为自己对指针掌握了,却还是对这个问题不太明白。请教!  
程序1:

void  myMalloc(char  *s)  //我想在函数中分配内存,再返回
{
  s=(char  *)  malloc(100);
}
void  main()
{
  char  *p=NULL;
    myMalloc(p);    //这里的p实际还是NULL,p的值没有改变,为什么?
    if(p)  free(p);
}

程序2:

void  myMalloc(char  **s)
{
  *s=(char  *)  malloc(100);
}
void  main()
{
  char  *p=NULL;
  myMalloc(&p);    //这里的p可以得到正确的值了
  if(p)  free(p);
}  

程序3:

#include
void  fun(int  *p)
{
  int  b=100;
  p=&b;
}
main()
{
  int  a=10;
  int  *q;
  q=&a;
  printf("%d\n",*q);
  fun(q);
  printf("%d\n",*q);
  return  0;
}  

结果为
10
10
程序4:

#include
void fun(int *p)
{
  *p=100;
}
main()
{
  int a=10;
  int *q;
  q=&a;
  printf("%d\n",*q);
  fun(q);
  printf("%d\n",*q);
  return 0;
}

结果为  
10  
100  
为什么?  
---------------------------------------------------------------   
1.被分配内存的是行参s,p没有分配内存   
2.被分配内存的是行参s指向的指针p,所以分配了内存  
---------------------------------------------------------------  
不是指针没明白,是函数调用的问题!看看这段:   
7.4指针参数是如何传递内存的?   
 如果函数的参数是一个指针,不要指望用该指针去申请动态内存。示例7-4-1中,Test函数的语句GetMemory(str,  200)并没有使str获得期望的内存,str依旧是NULL,为什么?

void  GetMemory(char  *p,  int  num)
{
  p  =  (char  *)malloc(sizeof(char)  *  num);
}
void  Test(void)
{
  char  *str  =  NULL;
  GetMemory(str,  100);            //  str  仍然为  NULL
  strcpy(str,  "hello");            //  运行错误
}  

示例7-4-1  试图用指针参数申请动态内存  
毛病出在函数GetMemory中。编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是  _p,编译器使  _p  =  p。如果函数体 内的程序修改了_p的内容,就导致参数p的内容作相应的修改。这就是指针可以用作输出参数的原因。在本例中,_p申请了新的内存,只是把 _p所指的内存地址改变了,但是p丝毫未变。所以函数GetMemory并不能输出任何东西。事实上,每执行一次GetMemory就会泄露一块内存,因 为没有用free释放内存。   
如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”,见示例7-4-2。

void  GetMemory2(char  **p,  int  num)
{
  *p  =  (char  *)malloc(sizeof(char)  *  num);
}
void  Test2(void)
{
  char  *str  =  NULL;
  GetMemory2(&str,  100);            //  注意参数是  &str,而不是str
  strcpy(str,  "hello");
}
void  fun(int  *p)
{
  int  b=100;
  p=&b;
}
main()
{
  int  a=10;
  int  *q;
  q=&a;
  printf("%d\n",*q);
  fun(q);////道理同第一个程序.
  printf("%d\n",*q);
  return  0;
}  

结果为  
10  
10  
程序4:

#include
void  fun(int  *p)
{
  *p=100;//参数P和实参P所指的内存单元是相同的.所以改变了参数P的内存单元内容,就改变了实参
                     //的内存单元内容
}
main()
{
  int  a=10;
  int  *q;
  q=&a;
  printf("%d\n",*q);
  fun(q);
  printf("%d\n",*q);
  return  0;
}  

结果为  
10  
100  
为什么?  
---------------------------------------------------------------

void  main()
{
  char  *p=NULL;
  myMalloc(p);    //这里的p实际还是NULL,p的值没有改变,为什么?
  if(p)  free(p);
}
void  myMalloc(char  *s)  //我想在函数中分配内存,再返回
{
  s=(char  *)  malloc(100);
} 

myMalloc(p)的执行过程:   
分配一个临时变量char  *s,s的值等于p,也就是NULL,但是s占用的是与p不同的内存空间。此后函数的执行与p一点关系都没有了!只是用p的值来初始化s。  
然后s=(char  *)  malloc(100),把s的值赋成malloc的地址,对p的值没有任何影响。p的值还是NULL。  
注意指针变量只是一个特殊的变量,实际上它存的是整数值,但是它是内存中的某个地址。通过它可以访问这个地址。  
程序2:

void  myMalloc(char  **s)
{
  *s=(char  *)  malloc(100);
}
void  main()
{
  char  *p=NULL;
  myMalloc(&p);    //这里的p可以得到正确的值了
  if(p)  free(p);
}  

程序2是正确的,为什么呢?看一个执行过程就知道了:  
myMalloc(&p);将p的地址传入函数,假设存储p变量的地址是0x5555,则0x5555这个地址存的是指针变量p的值,也就是Ox5555指向p。  
调用的时候同样分配一个临时变量char  **s,此时s  的值是&p的值也就是0x5555,但是s所占的空间是另外的空间,只不过它所指向的值是一个地址:Ox5555。  
*s=(char  *)  malloc(100);这一句话的意思是将s所指向的值,也就是0x5555这个位置上的变量的值赋为 (char  *)  malloc(100),而0x5555这个位置上存的是恰好是指针变量p,这样p的值就变成了 (char  *)  malloc(100)的值。即p的值是新分配的这块内存的起始地址。  
这个问题理解起来有点绕,关键是理解变量作函数形参调用的时候都是要分配一个副本,不管是传值还是传址。传入后就和形参没有关系了,它不会改变形参的值。 myMalloc(p)不会改变p的值,p的值当然是 NULL,它只能改变p所指向的内存地址的值。但是myMalloc(&p)为什么就可以了,它不会改变(&p)的值也不可能改变,但是 它可以改变(&p)所指向内存地址的值,即p的值。   
---------------------------------------------------------------   
你要弄清楚的是指针变量和指针所指的变量(可能是一片内存)。   
指针变量和普通变量一样存储的。

时间: 2024-10-14 06:35:35

C++ 指针详细分析(转)的相关文章

关于Delphi中的字符串的详细分析

关于Delphi中的字符串的详细分析 只是浅浅的解析下,让大家可以快速的理解字符串. 其中的所有代码均在Delphi7下测试通过. Delphi 4,5,6,7中有字符串类型包括了: 短字符串(Short String) 长字符串(Long String) 宽字符串(Wide String) 零结尾字符串(Null-Terminated String).PChar和字符数组 1.短字符串(Short String) 固 定长度,最大字符数个数为255,短字符串也成为长度字节(Length-byt

ZIP压缩算法详细分析及解压实例解释

最近自己实现了一个ZIP压缩数据的解压程序,觉得有必要把ZIP压缩格式进行一下详细总结,数据压缩是一门通信原理和计算机科学都会涉及到的学科,在通信原理中,一般称为信源编码,在计算机科学里,一般称为数据压缩,两者本质上没啥区别,在数学家看来,都是映射.一方面在进行通信的时候,有必要将待传输的数据进行压缩,以减少带宽需求:另一方面,计算机存储数据的时候,为了减少磁盘容量需求,也会将文件进行压缩,尽管现在的网络带宽越来越高,压缩已经不像90年代初那个时候那么迫切,但在很多场合下仍然需要,其中一个原因是

uboot的relocation原理详细分析

最近在一直在做uboot的移植工作,uboot中有很多值得学习的东西,之前总结过uboot的启动流程,但uboot一个非常核心的功能没有仔细研究,就是uboot的relocation功能. 这几天研究下uboot的relocation功能,记录在此,跟大家共享. 所谓的relocation,就是重定位,uboot运行后会将自身代码拷贝到sdram的另一个位置继续运行,这个在uboot启动流程分析中说过. 但基于以前的理解,一个完整可运行的bin文件,link时指定的链接地址,load时的加载地址

LeetCode::Sort List 详细分析

Sort a linked list in O(n log n) time using constant space complexity. 这道题目非常简短的一句话,给链表排序,看到nlogn,我们可以来简单复习一下排序.首先说一下这个nlogn的时间复杂度(根据决策树我们可以得出这个界限),是基于比较排序的最小上限,也就是说,对于没有一定范围情况的数据来说,最快的排序思路就是归并和快速排序了(当然具体的参数系数还是由更具体的设置决定的).对于数组的话,如果使用归并排序,不是in place的

LinkedList详细分析

一.源码解析1. LinkedList类定义2.LinkedList数据结构原理3.私有属性4.构造方法5.元素添加add()及原理6.删除数据remove()7.数据获取get()8.数据复制clone()与toArray()9.遍历数据:Iterator()二.ListItr 一.源码解析 1. LinkedList类定义. public class LinkedList<E> extends AbstractSequentialList<E> implements List&

Remove Duplicates from Sorted List II [详细分析]

Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list. For example, Given 1->2->3->3->4->4->5, return 1->2->5. Given 1->1->1->2->3, return 2->3

uboot第一阶段详细分析

原文:uboot第一阶段详细分析 作者:程老师,华清远见嵌入式学院讲师. uboot的第一阶段设计的非常巧妙,几乎都是用汇编语言实现的,下面我们一起来看看它的精妙之处吧! 首先我们来看一下它的链接脚本,通过它我们可以知道它整个程序的各个段是怎么存放的. OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")        OUTPUT_ARCH(arm)    

基于Java 生产者消费者模式(详细分析)

本文目录:1.等待.唤醒机制的原理2.Lock和Condition3.单生产者单消费者模式4.使用Lock和Condition实现单生产单消费模式5.多生产多消费模式(单面包)6.多生产多消费模式 生产者消费者模式是多线程中最为常见的模式:生产者线程(一个或多个)生成面包放进篮子里(集合或数组),同时,消费者线程(一个或多个)从篮子里(集合或数组)取出面包消耗.虽然它们任务不同,但处理的资源是相同的,这体现的是一种线程间通信方式. 本文将先说明单生产者单消费者的情况,之后再说明多生产者多消费者模

熊猫烧香_汇编级_超详细分析

1.样本概况 1.1 应用程序信息 文件: C:\Windows\System32\drivers\spo0lsv.exe 大小: 30001 bytes 修改时间: 2007年1月17日, 12:18:40 MD5: 512301C535C88255C9A252FDF70B7A03 SHA1: CA3A1070CFF311C0BA40AB60A8FE3266CFEFE870 CRC32: E334747C 简单功能介绍: \1. 自启动 \2. 删除gho文件 \3. 全盘感染指定类型文件 \