《C++程序设计》阅读笔记【4-指针(1)】

在这里插入图片描述

在这里插入图片描述

🌈个人主页:godspeed_lucip
🔥 系列专栏:《C++程序设计》阅读笔记

本文对应的PDF源文件请关注微信公众号程序员刘同学,回复C++程序设计获取下载链接。



1 指针

1.1 概述

指针常量:指针指向的地址是不可以变的

指针变量:指针指向的地址是可以变的(一般而言的指针就是指针变量)

常量指针:常量也有地址,常量指针中就保存这地址

用&操作符可以获取变量的地址,指针用于存放地址

&variable 是一个指针类型,其实际上是变量的地址,而地址可以用整数表示。但是这两者的数据类型是不一样的

用0给指针赋值,表诉一个空指针

1.2 指针的运算

指针只有加减法

#include <stdio.h>

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int *ptr = arr; // 指向数组的第一个元素

    printf("Before: %d\n", *ptr); // 输出数组第一个元素的值

    ptr++; // 将指针自增,指向数组的下一个元素

    printf("After: %d\n", *ptr); // 输出数组第二个元素的值

    return 0;
}

int *并没有重载++运算符,指针自增进而指向下一个元素是C++的语言特性,是自动完成的。32位机器中,int通常是4字节,因此int *的++实际上每次都会加4个字节(假设按照字节编址)

数组名实际上就是指针,因此用整型数组iArray给指针iPtr赋值时,可以使用iPtr=iArray,也可以使用iPtr = &iArray[0]

1.3 指针和数组

对于 int a[100]; int *iPtr=a;来说,

a[i];
*(a + i);
iPtr[i];
*(iPtr + i);

都是等价的。

理解:对于*(a + i),数组名会被隐式转换为指针,因此a+i相当于指针的加法。

对于iPtr[i],要理解的是:下标操作是针对地址的,而不仅仅是针对数组名的。也就是说对于编译器来说,iPtr[i]就是表示从iPtr这个地址出发,向后偏移i个元素单位的数据。

要理解:数组名是一个指针常量。也因此,让数组名赋值或运算是错误的

数组名是可以进行运算的,但是不可以重新赋值。(例如上面的*(a+i))。

数组和指针的关系

1.4 堆内存分配

堆允许程序在运行时(而不是在编译时)申请某个大小的内存空间。对于在栈(局部)或全局区(全局)的数组,其大小都应该是已知的,但是往往不知道数组该多大,因此这个时候就适合把数组分配在堆区。

注意:一个拥有内存的指针可以视为一个数组

1.4.1 获取堆空间

理解malloc函数:

它的原型为void * malloc(size_t size)。它会占用堆区中大小为size的空间,并将它的首地址返回,该内存中的数据是未知的。由于其返回值是void *(malloc不知道用这些内存来干什么),因此常常要做强制类型转换。

1.4.2 释放堆空间

free函数。

1.4.3 new和delete

例如:

int *array = new int[aSize]; //分配一块aSize大小的内存,此时array就可以视为一个数组
delete[] array; //释放内存。如果是释放数组的内存,那么要加一个[]

1.4.4 数组在堆上的分配和释放

一维数组:

int* arr = new int[n];//创建一维数组
delete[] arr;//销毁

二维数组:

int** arr = new int*[row];//这样相当于创建了数组有多少行
for(int i=0;i<row;i++){
	arr[i] = new int[col];//到这里才算创建好了
}
//释放
for(int i=0;i<row;i++){
	delete[] arr[i];
}
delete[] arr;

1.5 const指针

1.5.1 指向常量的指针(常量指针)

在指针定义语句的类型前加const,表示指向的对象是常量。例如const int *ptr= &a;。可以修改指针的指向,但不能修改指针指向的值(否则就是修改常量)。

1.5.2 指针常量

在指针定义语句的指针名前加 const,表示指针本身是常量。例如:

char * const ptr = "abcd";

不可以修改其指针值,但是可以修改其指向地址的值。

在定义指针常量时必须初始化。

1.5.3 指向常量的指针常量(常量指针常量)

既不能改变指针的指向,也不能改变指针指向地址的值

例如:

const int * const ptr = &b;

1.6 指针和函数

1.6.1 传递数组的指针性质

sum(int array[],int n);
sum(int *array,int n);

这两个是一样的。因为数组在作为参数传递到函数中时,会退化为指针。此时sizeof(arr)和指针的大小是一样的。此时,该数组可以进行和指针一样的运算。

请看下面的例子:

#include<iostream>
using namespace std;

int sum(int array[],int n){
	cout<<sizeof(array)<<endl;
}

int sum2(int *array,int n){
	cout<<sizeof(array)<<endl;
}

int main(){
	int arr[] = {1,2,3,4,5};
	cout<<sizeof(arr)<<endl;
	sum(arr,5);
	sum2(arr,5);
	int *ptr = new int[5];
	cout<<sizeof(ptr)<<endl;
	return 0;
} 

运行结果为:

image-20240228203556766

1.6.2 指针函数

返回指针的函数称为指针函数。

指针函数不能把在它内部说明的具有局部作用域的数据地址作为返回值。

解释:

在C++中,函数内部声明的局部变量具有函数作用域,这意味着它们只在声明它们的函数中可见。当函数执行完成后,这些局部变量会被销毁,它们的内存空间将被释放。

如果一个指针函数试图返回一个在其内部声明的局部变量的地址,这样的做法是不安全的。这是因为当函数执行完成时,局部变量将被销毁,而返回的指针将指向一个不再存在的内存地址,这可能导致未定义行为。

可以返回堆地址,以返回全局或静态变量的地址,但不要返回局部变量的地址

请看下面的例子:
image-20240228204451506

其运行结果为:
image-20240228204515172

解释:getInt函数返回之后,编译器自动将其中的局部变量保存。因此第一次输出时是正确的,但是接下来编译器就会将局部变量销毁,所以第二次输出的时候就是一个无意义的数字。尽管理论上,函数返回后,其局部变量会立即被销毁,但是编译器会做出这样的优化行为。

钱能书上的解释:在主函数中,指针 pr 得到一个局部变量的地址,输出该地址中的内容 20。随后,调用了另一个函数 somefn(),该函数将前一个被调函数的栈空间位置作为自己的栈工作空间,所以函数返回后,栈中内容发生了变化。而主函数下一个语句输出的是该变化了的内存空间内容。

1.6.3 void指针

void指针不指向任何类型,就是一个单纯的地址。既不可以进行运算(加减),也不能解引用。(这些操作都需要指针的类型信息)

由于其他指针都包含地址信息,所以将其他指针的值赋给空类型指针是合法的;反之将空类型指针赋给其他指针则不被允许,除非进行显式转换。

2 总结

C++,犹如编程的交响乐, 在代码的海洋中奏响和谐的旋律。

它是创造者的笔,雕刻着无尽可能,

是思想的翅膀,让梦想飞翔的天空。

无拘无束,灵活多变。

C++,是程序员心中的宝藏,永不凋零的花朵。

渴望挑战C++的学习路径和掌握进阶技术?不妨点击下方链接,一同探讨更多C++的奇迹吧。我们推出了引领趋势的💻C++专栏:《C++程序设计》阅读笔记,旨在深度探索C++的实际应用和创新。🌐🔍

在这里插入图片描述

在这里插入图片描述

相关推荐

  1. C++程序设计学习笔记(一)

    2024-04-05 22:30:03       41 阅读
  2. C++程序设计学习笔记(二)

    2024-04-05 22:30:03       52 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-05 22:30:03       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-05 22:30:03       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-05 22:30:03       87 阅读
  4. Python语言-面向对象

    2024-04-05 22:30:03       96 阅读

热门阅读

  1. 拿到运营商给的IP池

    2024-04-05 22:30:03       34 阅读
  2. WebKit结构简介

    2024-04-05 22:30:03       33 阅读
  3. css:阴影效果box-shadow

    2024-04-05 22:30:03       43 阅读
  4. 鸿蒙组件学习_Tabs组件

    2024-04-05 22:30:03       40 阅读
  5. 【pytest】`setup`和`teardown`

    2024-04-05 22:30:03       39 阅读
  6. 网络层面测评项

    2024-04-05 22:30:03       37 阅读
  7. docker容器gitlab数据迁移

    2024-04-05 22:30:03       44 阅读