C++:指针

2023-11-15

目录

1.指针

1.1指针三要素:

1.2修饰结构体struct 

1.3 Pointers of Pointers

1.4constant修饰 pointer

2.指针和数组

2.1.数组的地址是连续的

2.2pointer arithmetic:指针的代数运算 

2.3指针和数组的不同

3.内存分配:


1.指针

1.1指针三要素:

  • 运算符&:可以取对象或基本类型变量的地址。
  • 运算符*:可以获取指针指向的内容
int main(){
    //指针三要素
    int num = 10;
    int *p1 = NULL , *p2 = NULL;  //1.声明指针变量,必须初始化(NULL=整数0)
    p1 = # //2.取num地址,赋值给指针
    p2 = #
    cout << "p1的值:"<<p1 <<endl;
    cout<<"num = "<<num<<endl;

    *p1 = 20;  //3.利用指针修改num的值
    cout<<"num = "<<num<<endl;

    *p2 = 50;  //利用指针修改num的值
    cout<<"num = "<<num<<endl;

    cout << "p1的值:"<<p1 <<endl;
    cout << "p2的值:"<<*p2 <<endl;
    
    return 0;
}

1.2修饰结构体struct 

指针指向结构体:

  • p->member
  • (*p).member

 

    Student zhaoyan = { "yan",2000,true}; //实例化结构体
    Student *pStu = &zhaoyan;    //取这个结构体的地址

    strncpy(pStu->name,"Li",4);  //将pStu->name修改为Li
    pStu->born = 2021;
    (*pStu).born = 2002;
    pStu->male = false;

    cout << zhaoyan.name << " was born in " << zhaoyan.born 
         << ". Gender: " << (zhaoyan.male ? "male" : "female") << endl;
    
    //打印指针地址
    printf("address of zhaoyan: %p\n",pStu);           //C style p:输出指针地址
    cout<< "addres of zhaoyan: "<< pStu <<endl;       //C++ style
    cout<< "addres of zhaoyan: "<< &zhaoyan <<endl;       //C++ style
    cout<< "addres of zhaoyan.born: "<< &(zhaoyan.born) <<endl;       //C++ style

    cout<<"sizeof(pStu):" << sizeof(pStu) <<endl;

    return 0;

1.3 Pointers of Pointers

指针也是变量,也有地址:任何指针变量都占4个字节

    int num = 10;
    int *p = &num;
    int **pp = &p;  //指针的指针

    *(*pp) =20;
    cout<< "num=:"<<num<<endl;

    return 0;

1.4constant修饰 pointer

int main()
{
    int num = 1;
    int another = 2;
    
    //You cannot change the value that p1 points to through p1
    const int * p1 = &num; 指向的地址不变,即num不变
    *p1 = 3; //error 不能利用指针修改指针指向的值
    num = 3; //okay

    //You cannot change value of p2 (address)
    int * const p2 = &num; 内存里地址的值不变 ,即(*a)不变
    *p2 = 3; //okay  只能通过指针修改指针指向的值
    p2 = &another; //error

    //You can change neither
    const int* const p3 = &num;
    *p3 = 3; //error
    p3 = &another; // error

    return 0;
}

 例子:

为了函数求和等,传入只读的数

int foo(const char * p)
{
    // the value that p points to cannot be changed
    // play a trick?
    char * p2 = p; //syntax error 
    //...
    return 0;
}

2指针和数组

2.1.数组的地址是连续的

    Student stu[128];
    Student *p0 = &stu[0]; //主要中括号的优先级比&高
    Student *p1 = &stu[1];
    Student *p2 = &stu[2];
    Student *p3 = &stu[3];

    printf("p0=%p\n",p0);
    printf("p1=%p\n",p1);
    printf("p2=%p\n",p2);
    printf("p3=%p\n",p3);

    //相同的操作
    stu[1].born = 2000;
    p1->born =2000;

将数组名可以看作一个指针:
 

Student students[128];

printf("&students = %p\n", &students);
printf("students = %p\n", students);
printf("&students[0] = %p\n", &students[0]);

Student * p = students;
p[0].born = 2000; 
p[1].born = 2001;
p[2].born = 2002;

printf("students[0].born = %d\n", students[0].born);
printf("students[1].born = %d\n", students[1].born);
printf("students[2].born = %d\n", students[2].born);

2.2pointer arithmetic:指针的代数运算 

  • p+num  or  num+p points :指向数组p的第num个元素
  • p - num :指向第-num个数组

 给参数加()是为了优先级:更安全

//用宏来打印数组:宏是不能换行的
#define PRINT_ARRAY(array,n)\
for(int i=0;i<(n);i++)\                         //最好加一个()防止优先级
    cout<<"array["<<i<<"] = " <<(array)[idx] <<endl;

 

int main(){
    int numbers[4] = {0,1,2,3};
    PRINT_ARRAY(numbers,4);

    int *p = numbers+1;  //指向值为1的元素
    p++;    //指向值为2的元素

    cout << "numbers = " << numbers << endl;
    cout << "p = " << p << endl;

    *p =20;  //change 2 to 20
    *(p-1) = 20; //change 1to 10
    p[1] = 30;  //change 3 to 30
 
    PRINT_ARRAY(numbers,4);

    return 0;
}

注意:指针不能去了不该去的地方!这种错误最难找

小心越界:有时候会报错,有时不报错

int num = 0;
int * p = &num;
p[-1] = 2; //out of bound
p[0] = 3; //okay
*(p+1) = 4; //out of bound

 2.3指针和数组的不同

  • 数组是const指针
  • sizeof运算符指向指针将返回地址的大小(4或8)
  • 数组中所有元素的总大小可以通过sizeof运算符获得
int numbers[4] = {0, 1, 2, 3};
int * p = numbers;
cout << sizeof(numbers) << endl; //4*sizeof(int)
cout << sizeof(p) << endl; // 4 or 8
cout << sizeof(double *) << endl; // 4 or 8

3.内存分配:

在head上可以申请很大的内存使用, 

  •  分配未初始化存储的大小字节 malloc函数:。
void* malloc(size_t size)
  • 分配4个字节并将指针显式转换为(int*)
int *p1 = (int*)malloc(4)
  • Question:
int *p1 = (int*)malloc(3) 
//申请3个字节,但是int*需要4个字节
//但是不会报错,因为内存至少分配16个字节

内存的释放:

  • 必须显式释放动态分配的内存!:free函数
void free(void* ptr);
  • Question:
p = (int *) malloc(4 * sizeof(int));
// ...
p = (int *) malloc(8 * sizeof(int));
// ...
free (p);

内存泄漏:

案例:

void foo()
{
    int* p = (int*) malloc(sizeof(int));
    return;
}

上述的函数没有释放就return,在内存就找不到申请指针p的地址;必须在函数内释放

内存泄漏: 没有变量保留第一个地址。内存管理系统不会自动解除分配。浪费内存!

int main()
{
    int * p = NULL;
    
    p = (int *) malloc(4 * sizeof(int));
    // some statements
    p = (int *) malloc(8 * sizeof(int));
    // some statements
    free (p);
    // the first memory will not be freed

    for(int i = 0; i < 1024; i++)
    {
        p = (int *) malloc(1024 * 1024 * 1024);
    }
    printf("End\n");
    return 0;
}

C++中申请释放内存:

new:

   //allocate an int, default initializer (do nothing)
    int * p1 = new int; 
    //allocate an int, initialized to 0
    int * p2 =  new int();
    //allocate an int, initialized to 5
    int * p3 =  new int(5); 
    //allocate an int, initialized to 0
    int * p4 =  new int{};//C++11    
    //allocate an int, initialized to 5
    int * p5 =  new int {5};//C++11

    //allocate a Student object, default initializer
    Student * ps1 = new Student;
    //allocate a Student object, initialize the members
    Student * ps2 = new Student {"Yu", 2020, 1}; //C++11

    //allocate 16 int, default initializer (do nothing) 
    int * pa1 = new int[16];
    //allocate 16 int, zero initialized 
    int * pa2 = new int[16]();
    //allocate 16 int, zero initialized 
    int * pa3 = new int[16]{}; //C++11
    //allocate 16 int, the first 3 element are initialized to 1,2,3, the rest 0
    int * pa4 = new int[16]{1,2,3}; //C++11

    //allocate memory for 16 Student objects, default initializer
    Student * psa1 = new Student[16];
    //allocate memory for 16 Student objects, the first two are explicitly initialized
    Student * psa2 = new Student[16]{{"Li", 2000,1}, {"Yu", 2001,1}}; //C++11
    cout << psa2[1].name << endl;
    cout << psa2[1].born << endl;

delete:

    //deallocate memory
    delete p1;
    //deallocate memory
    delete ps1;

    //deallocate the memory of the array
    delete pa1;
    //deallocate the memory of the array
    delete []pa2;

    //deallocate the memory of the array, and call the destructor of the first element
    delete psa1;

    //deallocate the memory of the array, and call the destructors of all the elements
    //调所有的析构函数
    delete []psa2;  //最好用这种方法,删除数组结构体里所有内容

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++:指针 的相关文章

随机推荐

  • Android插件化的探索

    简介 对于App而言 所谓的插件化 个人的理解就是把一个完整的App拆分成宿主和插件两大部分 我们在宿主app运行时可以动态的载入或者替换插件的部分 插件不仅是对宿主功能的扩展而且还能减小宿主的负担 所谓的宿主就是运行的app 插件即宿主运
  • 几种本地存储方式

    浏览器本地存储的容器 1 cookie 2 sessionStorage 3 localStorage cookie cookie 浏览器早期存储数据容器 主要用于 存放用户名和密码 特点 容量小 4kb 操作繁琐 name zs pass
  • android studio安装automotive模拟器

    添加源 打开android studio的SDK Manager 选择SDK Update Sites选项卡 点击Add 弹出地址设置界面 添加polestar2 sys img Name填写 Polestar 2 System Image
  • RabbitMQ如何保证消息的顺序性【重点】

    1 1 保证顺序性的意义 消息队列中的若干消息如果是对同一个数据进行操作 这些操作具有前后的关系 必须要按前后的顺序执行 否则就会造成数据异常 举例 比如通过mysql binlog进行两个数据库的数据同步 由于对数据库的数据操作是具有顺序
  • SQLi LABS Less-12 联合注入+报错注入

    第十二关是双引号 括号的字符型注入 推荐使用联合注入 报错注入 方式一 联合注入 参考文章 联合注入使用详解 原理 步骤 实战教程 第一步 判断注入类型 用户名输入 a or 1 a 密码随便输入 1 页面正常显示 用户名输入 a or 0
  • 【C++】crypto++加密库简单使用

    crypto 加密库简单使用 目录 crypto 密码学库简单使用 一 简介 二 配置 三 使用示例 1 CRC32校验 2 Base64编码 3 Blake2b 4 AES 5 RSA 一 简介 crypto 是一个免费开源 公共领域 的
  • 功能测试之单元测试

    功能测试之单元测试 单元测试 理论 实例 单元测试 理论 简介 1 单元测试的基本概念 2 单元测试的策略 3 单元测试的步骤 4 Junit测试简单Java程序 1 单元测试概念 什么是单元测试 单元测试是一种验证行为 是指对软件中的最小
  • 第1章 多线程概述

    学习多线程之前 我们先要了解几个关于多线程有关的概念 A 进程 进程指正在运行的程序 确切的来说 当一个程序进入内存运行 即变成一个进程 进程是处于运行过程中的程序 并且具有一定独立功能 B 线程 线程是进程中的一个执行单元 负责当前进程中
  • Java经典面试题详解:springframework框架

    一面 1 自我介绍和项目 2 Java的内存分区 3 Java对象的回收方式 回收算法 4 CMS和G1了解么 CMS解决什么问题 说一下回收的过程 5 CMS回收停顿了几次 为什么要停顿两次 6 Java栈什么时候会发生内存溢出 Java
  • unity3d人物碰撞提示文字

    设置碰撞体 例如cube 将脚本挂载在物体上 碰撞显示text using System Collections using System Collections Generic using UnityEngine using Unity
  • 深度学习环境配置:2080Ti+Ubuntu16.04+CUDA10+cuDNN7.3+TensorFlow-gpu1.12

    目录 第一步 系统安装 Ubuntu16 04 第二步 连接校园网 第三步 cuda10 0 cudnn7 3安装
  • ES6 语法之 Iterator

    一 概念 Iterator 遍历器 为不同的数据类型提供统一的访问机制 只要部署了 Iterator 接口 原型上有 Symbol iterator 方法 就可以完成遍历操作 遍历操作主要通过 for of 完成 let arr 1 2 3
  • 【SQL基础】SQL查询语句实例

    参考自 https www w3school com cn sql index asp 下面举实例 员工表 部门表 薪资等级表 附上sql语句 薪资等级表SALGRADE 部门表DEPT 员工表EMP CREATE TABLE DEPT D
  • Python 安装Python-Jenkins 报错No matching distribution found for python-jenkins

    1 报错情况 报错原因 找不到与python jenkins匹配的分布 pip 安装使用的是外国源镜像 导致获取超时 安装失败 获取不到新版本 解决办法 切换至 pip 源到国内镜像 2 切换pip源的方法 可以直接通过Pycharm 设置
  • Windows Server 2016搭建文件服务器

    1 进入系统在服务器管理器仪表盘中添加角色和功能 2 下一步 3 继续下一步 4 下一步 5 勾选Web服务器 IIS 6 添加功能 7 下一步 8 下一步 9 下一步 10 角色服务没有特殊要求 保持默认 下一步 我这里多选了IP和域限制
  • 2020年4月蓝桥杯第二次模拟赛解题报告(本科组)Java语言描述__2021/3/21

    3 单词重排 问题描述 将LANQIAO中的字母重新排列 可以得到不同的单词 如LANQIAO AAILNOQ等 注意这7个字母都要被用上 单词不一定有具体的英文意义 请问 总共能排列如多少个不同的单词 答案提交 这是一道结果填空的题 你只
  • 代理模式--动态代理--jdk代理

    动态代理 jdk代理 基于接口代理 cglib 基于类代理 javassist 基于字节码 一个jdk动态代理类代理的是一个接口 一般归属于一个业务 在不改动源代码的同时可以很方便的低成本的进行加工附属改造 jdk代理主要是通过java l
  • php邮件发送类源码,一个邮件发送类..

    一个邮件发送类 class emailui static function runlog mode SMTP b c d static function sendmail toemail subject message from cfg a
  • R语言确定聚类的最佳簇数:3种聚类优化方法

    原文链接 http tecdat cn p 7275 确定数据集中最佳的簇数是分区聚类 例如k均值聚类 中的一个基本问题 它要求用户指定要生成的簇数k 一个简单且流行的解决方案包括检查使用分层聚类生成的树状图 以查看其是否暗示特定数量的聚类
  • C++:指针

    目录 1 指针 1 1指针三要素 1 2修饰结构体struct 1 3 Pointers of Pointers 1 4constant修饰 pointer 2 指针和数组 2 1 数组的地址是连续的 2 2pointer arithmet