指针全面复习

news/2024/10/19 5:30:21/

一.指针简介:

小端存储与大端存储

int a = 0x12345678

小端存储:

大端存储和小端存储位置相反

数组的存储是正向的,和其他类型不同,

如char A[3] = {2,3,4}

int *p;
int data = 10;
int arr[2] = {1,2};p = &arr[0];//数组的首地址就是首个元素的地址
p = a;//数组名就是数组的首地址#include <iostream>using namespace std;int main()
{int arr[] = {1, 6, 9};int *p;int *q;int num = 2222;p = &num;q = arr;cout << *p << endl;cout << *(q + 1) << endl;return 0;
}

二.指针的增量和数组的关系

#include <iostream>using namespace std;int main()
{int arr[] = {1, 2, 3};char arr1[] = {1, 2, 3};int *p;char *q;q = arr1;p = arr;cout << "p : " << *p << endl;cout << "address of p: " << p;cout << "q : " << *q << endl;cout << "address of q : " << q;// 指针的偏移量// 偏移量根基指针的类型// 偏移之后,还是他还是一个地址cout << *(p + 1) << endl;cout << "address of p+1: " << p << endl;cout << *(q + 1) << endl;cout << "address of q + 1: " << q + 1 << endl;return 0;
}

访问数组元素:

①指针法

        1.偏移

        2.取内容

*p++的优先级:

p先与++结合,后与*结合

②数组下标法

注意遍历数组之后,指针重新回到数组的首元素

但是这种写法是不被允许的

int arr[3] = {2,3,4};
int *p;
//p = arr;//由于p是int *类型,而i是int型,所以会报错
for(int i = 0,p = arr;i < 3; i++){cout << *p++ << endl;
}

三.对于两种方法的效率对比:

对于指针和数组下标的选择:

系统在使用数组下标对数组成员进行访问时,开销比较大,指针的访问效率远远大于数组名的访问效率

但是只有在指针访问正确时,才比数组下标访问更有效率(指针容易出错)

下标法更容易理解,在可读性方面也更有优势 

见怪不怪的指针:

指针可以当作数组名进行下标法访问

数组名也可以当作指针进行偏移方式进行访问

但是数组名++ 是不可行的,因为指针p是一个指针变量,指针所指向的地址是可以改变的,但是arr是一个常量指针,指针常量不允许++

 关于sizeof的区别

    int arr[] = {1, 2, 3};int *p = arr;cout << "arr is " << sizeof(arr) << endl;cout << "p is " << sizeof(p) << endl;cout << "int is " << sizeof(int) << endl;cout << "int* is " << sizeof(int*) << endl;cout << "char is " << sizeof(char) << endl;cout << "char* is " << sizeof(char*) << endl;cout << "double is " << sizeof(double) << endl;cout << "float is " << sizeof(float) << endl;

sizeof(arr)指的是arr数组当中有三个元素 3*4=12

sizeof(p) 指的是计算机操作系统用4个字节表示一个地址 

下列例子表示,此计算机的os指针都是用4个字节表示

四.关于指针常量和常量指针

        

        常量指针和指针常量是指针的两种不同类型

        它们有以下区别:

        1.常量指针(const pointer):指针本身是常量,指针指向的值可以改变。声明时在*前加const关键字。

int x = 5;
int y = 10;
const int *ptr = &x;
ptr = &y; // 合法,可以改变指针指向的地址
*ptr = 15; // 非法,无法改变指针指向的值

        2.指针常量(pointer to const):指针指向的值是常量,指针本身可以改变指向其他地址。声明时在*后加const关键字。

int x = 5;
int y = 10;
int *const ptr = &x;
*ptr = 15; // 合法,可以改变指针指向的值
ptr = &y; // 非法,无法改变指针指向的地址

一些关于这两个词的问题的答案帮助理解:

当涉及到指针常量和常量指针的概念时,可以设计一些问题来帮助加深理解。以下是一些关于指针常量和常量指针的问题:

1. 声明一个指针常量和一个常量指针,并解释它们之间的区别。
2. 给定一个指向整数的指针常量,如何修改指针指向的整数值?是否可以修改指针指向的地址?
3. 如果有一个常量指针指向一个整数,如何确保不能修改指针指向的值?
4. 在函数参数中如何声明一个指针常量和一个常量指针?这会对函数内部的操作有何影响?
5. 编写一个函数,接受一个常量指针作为参数,并尝试修改指针指向的值。观察会发生什么情况。

这些问题可以帮助理解指针常量和常量指针的概念,以及它们在实际编程中的应用和限制。

以下是关于指针常量和常量指针问题的答案:

1. **指针常量和常量指针的区别**:
   - 指针常量(pointer to const):指针本身是常量,指针指向的值不能被修改,但可以指向其他地址。
   - 常量指针(const pointer):指针指向的值是常量,不能被修改,但指针本身可以指向其他地址。

2. **修改指针常量指向的值**:
   - 可以通过指针常量间接修改指向的值,如 `*ptr = newValue;`。
   - 不能修改指针常量指向的地址,因为指针常量的地址是固定的。

3. **确保常量指针指向的值不可修改**:
   - 将指向的值声明为常量,如 `const int *ptr`。
   - 尝试修改 `*ptr` 的值会导致编译错误。

4. **在函数参数中声明指针常量和常量指针**:
   - 声明指针常量:`void func(const int *ptr)`,防止在函数内修改指向的值。
   - 声明常量指针:`void func(int *const ptr)`,防止在函数内修改指针指向的地址。

5. **尝试修改常量指针指向的值**:
   - 如果尝试在函数中修改常量指针指向的值,会导致编译错误,因为常量指针指向的值是只读的。

注意:

关于程序运行过程中出现的段错误,程序卡在半中间,不继续执行了

可以在编译时,加一个 -g选项

如gcc demo1.c -g  之后 gdb a.exe回车

加-g选项,会让编译出来的程序变成可调试

gdb就是用来调试程序的(使用gdb来找段错误)

输入指令之后,程序是待运行状态,输入 r 回车

程序进入调试

这样一步一步执行,如果遇到错误,程序就会终止,而且会提示出哪里出了问题

要退出输入q

y(yes)确定退出,n(no)取消退出

注:

关于vscode中出现中文输出乱码的问题:

vscode中文乱码问题及几种常见的解决方案-CSDN博客

关于scanf函数和cin的一点注意事项:

关于下列函数中

void initNum(int *parr, int size)
{for (int i = 0; i < size; i++){cout << "请输入第 " << i + 1 << "个数为:" << endl;scanf("%d", parr);parr++;}
}

scanf函数可以,而cin函数不行的原因是

在输入数组元素时使用了不同的输入方式,一个使用 `scanf` 函数,另一个使用 `cin` 对象。问题出在第二个函数中的 `cin >> parr;` 这行代码中。

原因是 `cin >> parr;` 中 `cin` 是输入流对象,而 `parr` 是一个指针这里的操作会尝试将输入值存储到指针 `parr` 指向的地址,而不是数组元素本身。这种方式是错误的,因为应该将输入值存储到 `parr` 指向的地址,而不是修改指针本身。

正确的方式是使用 `*parr` 来访问指针指向的地址,并将输入值存储在该地址上,如 `cin >> *parr;`。这样可以确保输入的值被正确存储在数组中的每个元素位置上。

而在第一个函数中,`scanf` 是可以正常工作的,因为 `scanf` 函数是通过指针来接收输入值并将其存储在指针指向的地址上。这种方式与 `cin` 不同,`scanf` 需要传递指向变量地址的指针作为参数来接收输入值

因此,对于 `scanf` 函数,可以通过 `scanf("%d", parr);` 来接收输入的整数值并将其存储在 `parr` 指向的地址上,这样可以正确地初始化数组中的各个元素。

   利用指针代替数组,进行存储和遍历的完整的函数实现:

#include <iostream>using namespace std;void initNum(int *parr, int size)
{for (int i = 0; i < size; i++){cout << "请输入第 " << i + 1 << "个数为:" << endl;cin >> *parr++;}
}void printNum(int *parr, int size)
{cout << "您要输出的值是:" << endl;for (int i = 0; i < size; i++){cout << *parr++ << ' ';}
}int main()
{int arr[5];int *p = arr;int size = sizeof(arr) / sizeof(arr[0]);cout << size << endl;initNum(arr, size);printNum(&arr[0], size);return 0;
}

  输入一个数组,将数组倒叙输出(利用指针)

void initArr(int *parr, int size)
{for (int i = 0; i < size; i++){cout << "请输入第" << i << "个数" << endl;cin >> *parr++;}
}
void reverseArr(int *parr, int size)
{for (int i = 0, j = size - 1 - i; i < size / 2; i++, j--){int temp = *(parr + i);*(parr + i) = *(parr + j);*(parr + j)= temp;}
}
void OutPut(int *parr, int size)
{for (int i = 0; i < size; i++){cout << *parr++ << ' ';}
}main函数:int arr[5];int *p = arr;int size = sizeof(arr) / sizeof(arr[0]);initArr(p, size);reverseArr(p, size);OutPut(p, size);return 0;

五.二维数组的地址认知、

int arr[3][3] = {{1, 2, 3}, {11, 22, 33}, {111, 222, 333}};

       首先要明白,数组名是数组的首地址,arr是数组arr[0]的首地址,arr[0]

    a[0] a[1] a[2]既然是数组名,而C语言中又规定了数组名是数组的首地址,

    因此a[0]代表一位数组当中第0列元素的地址 a[0]是一个数组名,数组当中的

    第零个元素(a[0][0])取一个地址 → &a[0][0]他是首地址,数组中数组名就是首地址

    所以&a[0][0] 等价于 a[0]   首个元素的地址是数组的首地址

        &a[0][0] == a[0]     &a[0] = arr

也就是说a[1]的值是&a[1][0],a[2]的值是&a[2][0] 

        数组中首个元素取个地址,就是数组的首地址,也是数组名代表的地址

*a和a[0]是等价的

arr是一个二维数组,定义一个指针,取出来的首地址是一个数组,但是在C语言中没有对数组操作的概念,所以*a和a[0]是一个意思,也就是一层级之后,继续向里深入,a[0]代表的是二维数组的首地址

能够表示数组的首地址,两种方式

法一:数组名

法二:首个元素的地址

在数组当中 数组名就是数组的首地址  数组的首个元素取个地址,就是数组的首地址,也是数组名代表的数组的首地址

首个元素的地址是数组的首地址,数组名也是数组的首地址

六.关于malloc函数

    int *p = (int *)malloc(sizeof(int));*p = 10;

这段代码的含义是:

1. `int *p = (int *)malloc(sizeof(int));`:这行代码首先声明了一个指针 `p`,类型为 `int *`,然后使用 `malloc` 函数动态分配了存储一个 `int` 类型数据大小的内存空间,并将这块内存的地址赋给指针 `p`。这意味着在堆内存中分配了足够存储一个整数的空间,并且指针 `p` 指向这块内存。

2. `*p = 10;`:这行代码将值 `10` 赋给指针 `p` 指向的内存地址,也就是将整数值 `10` 存储到了动态分配的内存空间中,相当于给这块内存赋值为 `10`。

总的来说,这段代码的作用是动态分配了一个整数大小的内存空间,并将整数值 `10` 存储在这块内存中,通过指针 `p` 来访问和操作这个动态分配的内存空间。在使用完这块内存后,应当使用 `free(p);` 来释放这块内存,以避免内存泄漏。

free(q)代表的是:把q指向的内存地址释放 

malloc函数的用法及指针举例

#include <stdio.h>
#include <malloc.h>
#include <iostream>using namespace std;void f(int* p){*p = 200;
}int main()
{int* p = (int *)malloc(sizeof(int));*p = 10;cout << *p <<endl;f(p);cout << *p;return 0;}

结果:

动态内存分配与传统数组:

动态内存和静态内存的比较:

七.多级指针

了解多函数指针,是为了跨函数内存

int main()
{int i = 2;int *p = &i;int **q = &p;cout << i << endl;cout << p << endl;cout << *p << endl;cout << q << endl;cout << *q << endl;cout << **q << endl;return 0;
}

结果:

八.静态变量不能跨函数使用详解

上述这个程序中,虽然最终结果没有报错,但是第16行的语句有逻辑上的问题

在main函数中,调用了f函数,f函数之星完毕之后,就会释放掉在f函数中包括 i *q 的内存

所以*p 虽然等于&i ,但是此时 i 的内存已经被释放,p已经没有权限去读取i的值,而且i的值也不存在。

p中可以存 i 的地址,但是不能通过*p来读取 i 的值(不能访问 i 的空间,因为 i 的空间已经释放)

p是属于 main函数中的,可以对p进行各种形式的读写

九.指针的重要性及指针的优点大总结

十.关于结构体的一些注意事项


http://www.ppmy.cn/news/1452616.html

相关文章

npm ERR! Invalid dependency type requested: alias解决

错误说明&#xff1a; 在使用vue通过npm进行依赖下载的时候出现&#xff1a; npm ERR! Invalid dependency type requested: alias 原因是使用的是nodejs版本比较低&#xff0c;其中附带的npm版本也比较低&#xff0c;较低npm 版本不支持使用别名&#xff08;alias&#xff0…

Elasticsearch 数据聚合

Bucket聚合&#xff08;桶聚合&#xff09; 对文档做分组&#xff0c;aggs 按照文档字段值或日期进行分组&#xff0c;能参与分词的字段不能做聚合&#xff0c;如text类型的字段 例如&#xff1a;根据城市名称做聚合&#xff0c;也就是城市名称对数据进行分组统计。可以加qu…

QT, 系统托盘 及 菜单

通过 QSystemTrayIcon 和 QMenu 可以实现pc应用的系统托盘及菜单&#xff1a; QSystemTrayIcon::setContextMenu(QMenu*); 关键代码&#xff08;截取项目中的代码&#xff09;如下&#xff1a; //!系统托盘及菜单;m_sysTray new QSystemTrayIcon(this);m_sysTray->setIco…

服务器硬件:裸金属安装 VMware ESXi

写在前面 工作中遇到&#xff0c;简单整理博文内容涉及 裸金属安装VMware ESXi 基本步骤理解不足小伙伴帮忙指正 不必太纠结于当下&#xff0c;也不必太忧虑未来&#xff0c;当你经历过一些事情的时候&#xff0c;眼前的风景已经和从前不一样了。——村上春树 一、准备工作 确…

(12)配置Notch滤波器(一)

文章目录 前言 1 陷波滤波器设置概述 2 启用陷波滤波器 3 陷波滤波器控制类型 4 确定陷波滤波器的中心频率 5 滤除的谐波数量 6 检查陷波滤波器的有效性 7 双层/三层陷波 前言 ArduPilot 支持两个陷波滤波器&#xff0c;对于电机来说&#xff0c;其滤波频率可以与电机…

英语前缀汇总

目录 A a- &#xff08;1&#xff09;无、不、非 &#xff08;2&#xff09;在...&#xff0c;向... &#xff08;3&#xff09;加强意义 ab- 离去&#xff0c;相反&#xff0c;不 ac- 含有at,to&#xff08;朝&#xff0c;向&#xff09;之意&#xff0c;或表示加强意义…

PHP 反序列化

一、PHP 序列化 1、对象的序列化 <?php class people{public $nameGaming;private $NationLiyue;protected $Birthday12/22;public function say(){echo "老板你好呀&#xff0c;我是和记厅的镖师&#xff0c;叫我嘉明就行&#xff0c;要运货吗你&#xff1f;"…

MIKE + MATLAB - 使用DHI工具包时读取数据

这里写目录标题 1. 读取投影 1. 读取投影 dfsu2.Projection.WKTString dfsu2.Projectionans DfsProjection - 属性:Type: ProjectionWKTString: [11 System.String]Longitude: 123.0000Latitude: 0Orientation: 0dfsu2.Projection.WKTStringans PROJCS["CGCS2000_3_Degr…