指针和自由存储空间

  指针是一个变量,其存储的是值的地址,而不是值本身。

  对变量应用地址运算符(&),就可以获得它的位置。

  使用常规变量时,值是指定的量,而地址为派生量。下面来看看指针策略,它是C++内存管理编程理念的核心。



  指针与C++基本原理

  面向对象编程与传统的过程性编程的区别在于,OPP强调的是在运行阶段(而不是编译阶段)进行决策。运行阶段指的是程序正在运行时,编译阶段指的是编译器将程序组合起来时。

  运行阶段决策提供了灵活性,可以根据当时的情况进行调整。在运行阶段做决策并非OPP独有的,但使用C++编写这样的代码比使用C语言简单。



  处理存储数据的新策略刚好相反,将地址视为指定的量,而将值视为派生量。一种特殊类型的变量——指针用于存储值得地址。因此,指针名表示的是地址。*运算符被称为间接值或解除引用运算符,将其应用于指针,可以得到该地址处存储的值(这和乘法使用的符号相同;C++根据上下文来确定所指的是乘法还是解除引用)。例如,假设manly是一个指针,则manly表示的是一个地址,而*manly表示存储在该地址处的值。*manly与常规int变量等效。

声明和初始化指针

  指针声明必须指定指针指向的数据的类型。

int*P_updates

  这表示,*p_updates的类型为int。由于*运算符被用于指针,因此p_updates变量本身必须是指针。我们说p_updates指向int类型,我们还说p_updates的类型是指向int的指针,或int*。可以这样说,p_updates是指针(地址),而*p_updates是int,而不是指针。

int *ptr;//传统上,C程序员使用这种格式。这强调*ptr是一个int类型的值。
int* ptr;//很多C++程序员使用这种格式。这强调的是:int*是一种类型——指向int的指针。
/*下面的声明创建一个指针(p1)和一个int变量(p2)*/
int* p1,p2;
/*对每个指针变量名,都需要使用一个*在C++中,int*是一种复合类型,是指向int的指针。*/

  可以在声明语句中初始化指针。在这种情况下,被初始化的是指针,而不是它指向的值。也就是说,下面的语句将pt(而不是*pt)的值设置为&higgens:

int higgens=5;
int* pt=&higgens;

指针的危险

  极其重要的一点是:在C++创建指针时,计算机将反派用来存储地址的内存,但不会分配用来存储指针所指向的数据的内存。为数据提供空间是一个独立的步骤,忽略这一步无疑是自找麻烦,如下所示:

long* fellow;
*fellow=223323;

  fellow确实是一个指针,但它指向哪里呢?上述代码没有将地址赋给fellow。由于fellow没有被初始化,它可能有任何值。不管值是什么,程序都将它解释为存储223323的地址。如果fellow的值碰巧是1200,计算机将把数据放在地址,计算机将把数据放在地址1200上,即使这恰巧是程序代码的地址。fellow指向的地方很可能并不是所要存储223323的地方。这种错误可能会导致一些最隐匿、最难以跟踪的bug。

  一定要在对指针应用解除引用运算符(*)之前,将指针初始化为一个确定的、适当的地址。这是关于使用指针的金科玉律。

指针和数字

  不能简单地将整数赋给指针:

int* pt;
pt=0xB8000000;

  在这里,左边是指向int的指针,因此可以把它赋给地址,但右边是一个整数。您可能知道,0xB8000000是老式计算机系统中视频内存的组合段偏移地址,但这条语句并没有告诉程序,这个数字就是一个地址。在C99标准发布之前,C语言允许这样赋值。但C++在类型一致方面的要求更严格,编译器将显示一条错误信息,通告类型不匹配。要将数字值作为地址来使用,应通过强制类型转换将数字转换为适当的地址类型:

int* pt;
pt=(int*)0xB8000000;

  使用new来分配内存

/*use_new.cpp*/
#include<iostream>
int main()
{
    using namespace std;
    int nights = 1001;
    /*使用new为int类型的数据对象分配内存。这是在程序运行时进行的。
    有了指针,就可以像使用变量那样使用*pt。将值赋给*pt,从而将这些值赋给新的数据对象。
    new分配的内存块通常与常规变量声明分配的内存块不同。变量nights和pd的值都储存在被称为栈(stack)的内存区域中,而new从被称为堆(heap)或自由存储区(free store)的内存区域分配内存*/
    int* pt = new int;
    *pt = 1001;

    cout << "nights 的值=";
    cout << nights << ":地址" << &nights << endl;
    cout << "整型";
    cout << "值=" << *pt << ":地址=" << pt << endl;
    double*pd = new double;
    *pd = 10000001.1;

    cout << "浮点型";
    cout << "值=" << *pd << ":地址=" << pd << endl;
    cout << "指针pd的地址:" << &pd << endl;
    cout << "pt的大小=" << sizeof(pt);
    cout << "*pt的大小=" << sizeof(*pt) << endl;
    cout << "pd的大小=" << sizeof pd;
    cout << ":*pd的大小=" << sizeof(*pd) << endl;
    cin.get();
    cin.get();
    return 0;
}

使用new来创建动态数组

/*arranew.cpp*/
#include<iostream>
int main()
{
    using namespace std;
    /*为数组分配内存的通用格式:type_name* pointer_name=new name[num_elements];*/
    double* p3 = new double[3];
    p3[0] = 0.2;
    p3[1] = 0.5;
    p3[2] = 0.8;
    cout << "p3[1] is" << p3[1] << ".\n";
    /*不能修改数组名的值。但指针是变量,因此可以修改它的值。
    p3加1导致它指向第2个元素而不是第1个*/
    p3 = p3 + 1;
    cout << "Now p3[0] is" << p3[0] << "and";
    cout << "p3[1] is" << p3[1] << ".\n";
    /*p3减1后,指针将指向原来的值,这样程序便可以给delete[]提供正确的地址。*/
    p3 = p3 - 1;
    /*方括号告诉程序,应释放整个数组,而不仅仅是指针指向的元素*/
    delete[]p3;

    cin.get();
    cin.get();
    return 0;
}

输出

p3[1] is 0.5.
Now p3[0] is 0.5 and p3[1] is 0.8.
时间: 2024-11-05 19:33:50

指针和自由存储空间的相关文章

C++ Primer Plus学习:第四章

C++入门第四章:复合类型 1 数组 数组(array)是一种数据格式,能够存储多个同类型的值. 使用数组前,首先要声明.声明包括三个方面: 存储每个元素中值的类型 数组名 数组中的元素个数 声明的通用风格如下: typename arrayname[arrysize]; 注;arrysize指定元素数目,必须是整型常量,不能是变量. 数组的很多用途均基于这样一个事实:可以单独访问数组元素.方法是使用下表或索引对元素进行编号.C++数组从0开始编号,并使用带索引的方括号表示法来指定数组元素. 注

C++ Primer Plus 复合类型

复合类型是指基于基本整型和浮点类类型而创建的数据格式. 1. 数组 1.1 声明数组时,必须指定元素数目,且元素数目必须是编译时已知的,所以变量(运行时设置的)不可以用来指定数目: 1.2 如果只对数组的一部分进行初始化,则编译器将其他元素设置为0; 所以初始化整个数组为0可以--int array[10] = {0}; 注: C++ 11支持去掉代码中的等号以及0,且不支持缩窄转换; 2. 字符串(C-风格字符串) 2.1 C++处理字符串有两种方式--C-风格字符串 & string类库;

C++ primer puls 学习笔记 (二)

一.知识点回顾 1.数组(array) (1)数组的基本信息 数组是一种数据格式,能够存储多个类型的值,要声明数组,可使用声明语句,但应该包含以下三点: ● 数组名 ● 存储在每个元素中的值的类型 ● 数组中的元素数 数组声明的通用格式如下: TypeName arrayName [arraysize] arraysize必须是整形常数或const值,也可以是常量表达式(具体地说不能是变量). (2)数组编号 数组的很多用途都是用于访问单独的数组元素,C++数组从0开始编号,然后利用索引来标识访

C++ Primer Plus

第1章 预备知识 第2章 开始学习C++ 第3章 处理数据 第4章 复合类型 第5章 循环和关系表达式 第6章 分支语句和逻辑运算符 第7章 函数-C++的编程模块 第8章 函数探幽 第9章 内存模型和名称空间 第10章 对象和类 第11章 使用类 第12章 类和动态内存分配 第13章 类继承 第14章 C++中的代码重用 第15章 友元,异常和其他 第16章 string类和标准模板库 第17章 输入,输出和文件 第18章 探讨C++新标准 附录A 计数系统 附录B C++保留字 附录C AS

(3)C++复合类型

一.数组 //初始化赋值1 short a[3]; a[0] = 1; a[1] = 16; a[2] = 90; //始化赋值2 short b[3] = { 2,6,13 }; //始化赋值3,自己计算个数 short c[] = { 2,6,13 }; //如果没赋值,会初始化为默认字符 short d[6] = { 5 }; 二.字符串 string类 三.结构 四.共用体 五.枚举 六.指针和自由存储空间 七.指针.数组和指针算术 八.类型组合 九.数组的替代品 原文地址:https:

黑马程序员---C基础9【字符串的输入输出】【字符串相关函数】【指针】【指针变量初始】【二级指针】

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- [字符串的输入输出] 1.字符串输出: %s-------从给定的地址开始输出字符直到遇到\0停止: printf("%s\n",&a[3]);  printf("%s\n",a); char a[]="hellowo\0rd!"; 2.字符串输入: 从键盘上接收一个字符串,保存在以a为首地址的字符数组中 scanf("%s&

iOS开发之c语言基础Lesson-08 指针 上课笔记 与 试题练习

1 ////////////////Lesson 08 指针 课堂笔记 与练习///////////// 2 3 //指针:本质是一个指针变量,只不过该变量用来存储地址. 4 //地址:内存单元的编号,也是一个数,只不过是以0x开头的十六进制数. 5 6 // int a = 10; 7 // int *p = &a; //定义一个指针变量,将a的地址给指针变量p:p指向a 8 // a = 20; //直接访问 9 // printf("%d ", *p); 10 // *p

[编程开发] 由指针传參引发的一点分析

昨天有同学(初学指针)在练习单链表和二叉树的时候,程序老是崩溃,或者得不到正确结果,于是向我求助.问题就出在指针的參数传递上,没传好指针导致内存混乱,其它代码基本全对.这个错误十分可惜.故在此我想做个记录,可能显得十分基础. 假设函数的參数是普通的一级指针,那么就意味着你仅仅能使用指针.改变指针指向或者改变指向的目标变量.不能试图通过这个指针来申请内存. void getMemory(int *p) { p = (int *)malloc(sizeof(int) * 10); } void fu

C 入门 第八节 指针

void changeValue(int num1,int num2){    int temp = num1;    num1 = num2;    num2 = temp;}//指针作为函数的参数进行传递,可以实现形参的改变作用到实参 void changeValue2(int *p1,int *p2){    int temp = *p1;    *p1 = *p2;    *p2 = temp;} //字符指针作为形参void func2(int *a,int count){    fo