C++使用指针,动态数组,指针做参数需要注意的问题等总结

简介: C++使用指针,动态数组,指针做参数需要注意的问题等总结

在这里插入图片描述


@[TOC]


一. 前言

指针是什么,有些萌新一听到指针就开始畏惧了,这种畏惧并不是来自指针给你的,而是他人给你的。我相信基本所有人都会在刚学习的时候百度:C语言最难的是什么?包括我。大多数答案告诉你指针最难,实话实说,指针确实难,但是是相对于其他知识点来说。通过网络上得到的一些信息,在没有学习指针之前,你便已经开始对指针存满了畏惧,在这里我想说,只有自己经历了才有资格去评价它其实单讲指针其实也没什么,前面学习的基本变量,整形,浮点型,字符型,等等,现在多了一个指针形,你只需要知道指针类型是用来存储地址的。地址也是一种数值,所以这没有什么难的,千万不要道听途说,要自己去证明。


二. 进入正题

1. 声明指针

//这就是指针的声明方式,对应的可以有如下几种形式,但不是全部:

 int * p_1; 
 long * P_2;
 char * P_3;
 cout << sizeof(p_1) << " " << sizeof(P_2) << " " << sizeof(P_3);

大家认为上述三种指针类型各占多少字节?
答案是不论是什么类型的指针,都是占4个字节,因为地址用4个字节来存储是足够的,不要问为什么,我不知道。有时候,你只管像一个傻子一样去做事就好了。记住这句话。那有人又开始问了,既然都是4个字节,还分什么类型,只用一种类型就可以了啊。
一个最基本的答案是:地址虽然足以用4字节存储,但是数值不是,之所以有不同类型的指针,是为了让编译器知道从地址开始位置读取几个字节。
如果是char 则只读取1个字节,如果是int,就读去4个字节。现在明白了吗。
大家一定见过这样的例子:

 int num = 123;
 int * p;
 p = &num;
 //*p 等于 num,这时候萌新又有问题了 到底 int * p中,*是跟哪边一起的,是int* p,还是int *p,
 //不知道你们是否有此问题,反正当初我是有的

我现在告诉你,是前者,但是两种写法都是合法的,我只是帮你理解指针,如果代码写成这样,会不会更容易理解点?

 int num = 123;
 int * p = &num;
 p = &num;

这里有一个坑,需要注意:

 int * P_1, P_2;//P_2是不是指针呢?答案是不是的,P_2只是普通的int类型
 int *P_3, *P_4;//这里的P_4是指针类型,如果按照这种写法,又会觉得*p是一起的。

所以总结起来就是定义一个指针,int p, int p, int*p三种写法都是合理的。
但是如果连续定义多个指针,应将*和变量名挨在一起。


2. int * pa 和 int pa[ ]的区别

接着来说 int * pa 和 int pa[]的区别,这也是众多初学者的疑问,不管是数组或者指针,大多数情况下不可能存在于全局变量,讲之前再补充一点知识:

我们写的代码代码存储在包括栈区,堆区,数据区,代码区的地方,而全局变量存储在数据区,我们不做讨论
不使用指针声明的数组被称为静态数组,局部静态数组被存储在栈区
而使用指针声明的数组被称为动态数组,局部动态数组被存储在堆区
栈区(stack)由编译器自动分配释放,存放函数的参数值、局部变量的值等。
堆区(heap)用于动态内存分配。一般由程序员分配和释放,若程序员不释放,结束程序时有可能由OS回收。
int pa_1[10] = { 1,2,3,4,5,6,7,8,9,10 }; 
//静态数组 编译之前要确定数组的大小,所以有时候会浪费内存,有时候会栈溢出。
 int * pa_2; //这仅仅是一个int类型的指针,并不是动态数组,想要成为动态数组,我们需要申请内存
 pa_2 = new int;//申请一个int类型的变量,未初始化
 int * pa_3;
 pa_3 = new int(1);//申请一个int类型变量并初始化为1
 int * pa_4;
 pa_4 = new int[10];//未初始化动态数组
 int * pa_5;
 pa_5 = new int[10]();//初始化动态数组为0
 //测试:
 cout << *pa_2 << endl;
 cout << *pa_3 << endl;
 cout << *pa_4 << endl;
 cout << *pa_5 << endl;

运行结果:
在这里插入图片描述


3. 访问数组和指针

访问静态数组和动态数组的不同,说之前再补一点知识,嘿嘿:

在Windows下,栈是高向低地址扩展的数据结构,是一块连续的内存的区域。
堆是向高地址扩展的数据结构,是不连续的内存区域,你们可以自行测试一下!
 //访问静态数组:
 cout << pa_1[0] << endl;
 cout << pa_1[1] << endl;
 cout << pa_1[2] << endl;
 //下面的操作访问静态数组正确吗?
 cout << pa_1[0]++ << endl;//正确,将访问pa_1[0]后并自增为2,并不是访问pa_1[1],要注意。
 cout << pa_1[0] << endl;
 //cout << pa_1 << endl; pa_1是数组名也是地址,不正确
 //cout << pa_1++ << endl; pa_1++无法运行 
 //pa_1是数组名,是一个常量,而pa_1[0]可以认为是一个变量名
 //自增运算符的操作对象要求是可修改的左值,但是数组名是常量,不是可修改的左值,所以不可进行自增或自减。
 //然后是动态数组:
 cout << *(pa_5++) << endl;//向右移动一个单位(一个单位指指针类型大小,int为4)
 cout << (*pa_5)++ << endl;//访问pa_5[0]并加自增
 cout << *pa_5 << endl;//显示自增结果

运行结果:

在这里插入图片描述


4. 释放内存

//还有一个要注意的地方,动态数组是我们自己申请的内存,在程序运行完毕应进行内存释放
 delete pa_5;//将只调用pa_5[0]的析构函数
 delete[]pa_5;//整个数组全部调用析构函数
 //析构函数我们现在不讲,只需要知道,对于基本指针类型,上面两种释放无异,但要是类对象,应该使用第二种。
 //补充一点,数组是可以赋值给指针的
 pa_5 = pa_1;

5. 指针或者数组做函数参数

//文章最后再来说一说指针或者数组做函数参数:
int fun_1(int a[])
{
}
int fun_2(int * a)
{
}
int fun_3(int a[10])
{
}
//在声明上,除了作为函数参数的数组名总是编译器转化成指针,上面三种写法作用相同下角标没有任何意义
//其他情况下,数组名就是数组名,指针就是指针,

6. 指针做参数需要注意的问题

//指针作形参,需要注意的问题。
int * end = NULL;
void func_1(int * end)
{
 int * p = new int;
 *p = 66;
 end = p; //如果试图通过传入一级指针在函数内修改一级指针,原指针不会任何变化
}
//解决办法有两种:一是指针作为函数值返回
int * func_2(int * end)
{
 int * p = new int;
 *p = 66;
 return p;
}
//二是通过二级指针来修改一级指针
 int ** end_2 = &end;
void func_2(int ** end_2)
{
 int * p = new int;
 *p = 66;
 end_2 = &p;
}

不知道读者有没有想到一个常见的例子,用一个函数交换两个变量的值,变量作参数,这是值传递,我们知道函数内对传递过来的值作任何操作,对原值没有任何影响,于是我们引入指针,引入变量地址来解决交换,现在也一样,我们想改变一级指针,自然就需要二级指针来解决问题,所以,你明白了吗。

关于指针的应用还有函数指针,和指针函数,这两部分内容等写到函数的时候再详谈,再见咯。


相关文章
|
8天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
27 4
|
23天前
|
存储 C语言 C++
如何通过指针作为函数参数来实现函数的返回多个值
在C语言中,可以通过将指针作为函数参数来实现函数返回多个值。调用函数时,传递变量的地址,函数内部通过修改指针所指向的内存来改变原变量的值,从而实现多值返回。
|
23天前
|
存储 安全 编译器
在 C++中,引用和指针的区别
在C++中,引用和指针都是用于间接访问对象的工具,但它们有显著区别。引用是对象的别名,必须在定义时初始化且不可重新绑定;指针是一个变量,可以指向不同对象,也可为空。引用更安全,指针更灵活。
|
23天前
|
存储 搜索推荐 C语言
如何理解指针作为函数参数的输入和输出特性
指针作为函数参数时,可以实现输入和输出的双重功能。通过指针传递变量的地址,函数可以修改外部变量的值,实现输出;同时,指针本身也可以作为输入,传递初始值或状态。这种方式提高了函数的灵活性和效率。
|
1月前
|
存储 C++
c++的指针完整教程
本文提供了一个全面的C++指针教程,包括指针的声明与初始化、访问指针指向的值、指针运算、指针与函数的关系、动态内存分配,以及不同类型指针(如一级指针、二级指针、整型指针、字符指针、数组指针、函数指针、成员指针、void指针)的介绍,还提到了不同位数机器上指针大小的差异。
38 1
|
1月前
|
存储 编译器 C语言
C++入门2——类与对象1(类的定义和this指针)
C++入门2——类与对象1(类的定义和this指针)
29 2
|
1月前
|
算法 编译器 C++
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
77 2
|
1月前
|
存储 安全 编译器
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(一)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
1月前
|
存储 C++ 索引
C++函数指针详解
【10月更文挑战第3天】本文介绍了C++中的函数指针概念、定义与应用。函数指针是一种指向函数的特殊指针,其类型取决于函数的返回值与参数类型。定义函数指针需指定返回类型和参数列表,如 `int (*funcPtr)(int, int);`。通过赋值函数名给指针,即可调用该函数,支持两种调用格式:`(*funcPtr)(参数)` 和 `funcPtr(参数)`。函数指针还可作为参数传递给其他函数,增强程序灵活性。此外,也可创建函数指针数组,存储多个函数指针。
|
2月前
|
编译器 C++
【C++核心】指针和引用案例详解
这篇文章详细讲解了C++中指针和引用的概念、使用场景和操作技巧,包括指针的定义、指针与数组、指针与函数的关系,以及引用的基本使用、注意事项和作为函数参数和返回值的用法。
37 3