指针(Pointer)
1 指针和常量的区别:
指针常量和常量指针的区别:https://www.cnblogs.com/lizhenghn/p/3630405.html
1.空指针
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。
NULL 指针是一个定义在标准库中的值为零的常量。请看下面的程序:
实例
#include <iostream>
using namespace std;
int main ()
{
int *ptr = NULL;
cout << "ptr 的值是 " << ptr ;
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
ptr 的值是 0
在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而,内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。
如需检查一个空指针,您可以使用 if 语句,如下所示:
if(ptr) /* 如果 ptr 非空,则完成 /
if(!ptr) / 如果 ptr 为空,则完成 */
因此,如果所有未使用的指针都被赋予空值,同时避免使用空指针,就可以防止误用一个未初始化的指针。很多时候,未初始化的变量存有一些垃圾值,导致程序难以调试。
2.指针数组
把 ptr 声明为一个数组,由 MAX 个整数指针组成。因此,ptr 中的每个元素,都是一个指向 int 值的指针。下面的实例用到了三个整数,它们将存储在一个指针数组中,如下所示:
实例
#include <iostream>
using namespace std;
const int MAX = 3;
int main ()
{
int var[MAX] = {10, 100, 200};
int *ptr[MAX];
for (int i = 0; i < MAX; i++)
{
ptr[i] = &var[i]; // 赋值为整数的地址
}
for (int i = 0; i < MAX; i++)
{
cout << "Value of var[" << i << "] = ";
cout << *ptr[i] << endl;
}
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
3.指向指针的指针
指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。
指针的指针就是将指针的地址存放在另一个指针里面。
通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。
#include <iostream>
using namespace std;
int main ()
{
int var;
int *ptr;
int **pptr;
var = 3000;
// 获取 var 的地址
ptr = &var;
// 使用运算符 & 获取 ptr 的地址
pptr = &ptr;
// 使用 pptr 获取值
cout << "var 值为 :" << var << endl;
cout << "*ptr 值为:" << *ptr << endl;
cout << "**pptr 值为:" << **pptr << endl;
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
var 值为 :3000
*ptr 值为:3000
**pptr 值为:3000
4 传递指针给函数
C++ 允许您传递指针给函数,只需要简单地声明函数参数为指针类型即可。
#include <iostream>
using namespace std;
// 函数声明
double getAverage(int *arr, int size);
int main ()
{
// 带有 5 个元素的整型数组
int balance[5] = {1000, 2, 3, 17, 50};
double avg;
// 传递一个指向数组的指针作为参数
avg = getAverage( balance, 5 ) ;
// 输出返回值
cout << "Average value is: " << avg << endl;
return 0;
}
double getAverage(int *arr, int size)
{
int i, sum = 0;
double avg;
for (i = 0; i < size; ++i)
{
sum += arr[i];
}
avg = double(sum) / size;
return avg;
}
5.函数返回指针
必须声明一个返回指针的函数,如下所示:
int * myFunction()
{
.
.
.
}
另外,C++ 不支持在函数外返回局部变量的地址,除非定义局部变量为 static变量。
//生成 10 个随机数,并使用表示指针的数组名(即第一个数组元素的地址)来返回它们
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
// 要生成和返回随机数的函数
int * getRandom( )
{
static int r[10];
// 设置种子
srand( (unsigned)time( NULL ) );
for (int i = 0; i < 10; ++i)
{
r[i] = rand();
cout << r[i] << endl;
}
return r;
}
// 要调用上面定义函数的主函数
int main ()
{
// 一个指向整数的指针
int *p;
p = getRandom();
for ( int i = 0; i < 10; i++ )
{
cout << "*(p + " << i << ") : ";
cout << *(p + i) << endl;
}
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
624723190
1468735695
807113585
976495677
613357504
1377296355
1530315259
1778906708
1820354158
667126415
*(p + 0) : 624723190
*(p + 1) : 1468735695
*(p + 2) : 807113585
*(p + 3) : 976495677
*(p + 4) : 613357504
*(p + 5) : 1377296355
*(p + 6) : 1530315259
*(p + 7) : 1778906708
*(p + 8) : 1820354158
*(p + 9) : 667126415
2.&和*区别
指针是指向变量的地址
&:获取变量的地址
一元运算符: 返回位于操作数所指定地址的变量的值*
简单的例子分析:
int main()
{
int a = 3;
int *b = &a;
cout << "a:" << a << endl;
cout << "b:" << b << endl;
*b = 10;
cout << "&a:" << &a << endl;
cout << "b:" << b << endl;
cout << "a=" << &a << endl;
system("pause");
}
结果:
a:3
b:00EFFE28
&a:00EFFE28
b:00EFFE28
a=10
**b是a的指针,指向a的地址。(也就是a与b相连,只要修改*b的值,a的值也跟着改动)**
3.类和指针
类
https://blog.csdn.net/keneyr/article/details/89364275
https://www.jianshu.com/p/a75b267325c2
void指针
void指针是没有类型.任何指针都可以赋值给void指针 ,不用转换,只需要地址而不需要长度,不能判断指向对象长短的指针 , void *vp; int *p; vp=p;
但是void指针赋值给其他类型的指针时都要进行类型转换 ,类型转换的目的是获得指向变量/对象大小 type p=(type)vp;
void指针不能解引用 的 *vp//错误 因为void指针只知道,指向变量/对象的起始地址 ,而不知道指向变量/对象的大小(占几个字节)所以无法正确引用。
void指针不能参与指针运算,除非进行转换 (type*)vp++; //vp==vp+sizeof(type)
void * 和 void 在函数返回值中的区别在:
函数的返回值中, void 是没有任何返回值, 而 void * 是返回任意类型的值的指针.
4 通过函数返回指针和数组
函数通过函数返回指针
#include <iostream>
using namespace std;
void splitfloat(int *x,int *y)//形参x,y为指针
{
int x1 = 1;
int y1 = 100;
*x = y1 + x1;
*y = y1 - x1;
}
int main()
{
int n=0, f=0;
splitfloat(&n, &f); //变量地址作为实参
cout << "n:" << n << endl;
cout << "f:" << f << endl;
函数通过函数返回指针和数组
test.h文件
#ifndef TEST_H_
#define TEST_H_
int a[4][2];
int x0;
#endif
.cpp文件
#include <iostream>
#include "test.h"
using namespace std;
void splitfloat(int *x) //形参x为指针
{
int x1 = 1;
int y1 = 100;
for (int m = 0; m < 4; m++)
{
for (int n = 0; n < 2; n++)
{
a[m][n] = m+x1;
cout << "a[" << m << "]" << "[" << n << "]:" << a[m][n] << endl;
x1 += 1;
}
}
//for (int i = 0; i < 4; i++)
//{
// x0 = x1 + i;
//
//}
// //*x = x1 + i;
//
// *x = x0;
}
int main()
{
int n=0,f=0;
//int a[4][2] = {0};
splitfloat(&n); //变量地址作为实参
cout << "a[0][0]:" << a[0][0] << endl;
cout << "a[0][1]:" << a[0][1] << endl;
cout << "a[1][0]:" << a[1][0] << endl;
cout << "a[1][1]:" << a[1][1] << endl;
cout << "a[2][0]:" << a[2][0] << endl;
cout << "a[2][1]:" << a[2][1] << endl;
cout << "a[3][0]:" << a[3][0] << endl;
cout << "a[3][1]:" << a[3][1] << endl;
/*for (int j = 0; j < 4; j++)
{
for (int k = 0; k < 2; k++)
{
cout << "a[" << j << "]" << "[" << k << "]:" << a[j][k] << endl;
}
}*/
//cout << "f:" << f << endl;
/*cout << "a[0]:" << a[0] << endl;
cout << "a[1]:" << a[1] << endl;
cout << "a[2]:" << a[2] << endl;
cout << "a[3]:" << a[3] << endl;*/
}
5.指针的动态内存分配
指针数组的动态内存分配:
#include <iostream>
using namespace std;
int main()
{
// 开始为二维的动态数组设置内存容量
int **test2 = new int *[5];
for (int j = 0; j < 5; j++)
{
test2[j] = new int [3];
}
for (int i = 0; i < 5; i++)
{
for (int k = 0; k < 3; k++)
{
test2[i][k] = i + k;
}
}
for (int i = 0; i < 5; i++)
{
for (int k = 0; k < 3; k++)
{
cout << "test2[i][k]" << test2[i][k] << "\n";
}
}
// 释放内存
for (int k = 0; k < 3; k++)
{
delete[] test2[k];
}
delete[] test2;
return 0;
}
类指针的动态内存分配:
#include <iostream>
using namespace std;
class Box
{
public:
Box() {
cout << "调用构造函数!" << endl;
}
int test() {
cout << "调用test()函数!" << endl;
return 0;
}
~Box() {
cout << "调用析构函数!" << endl;
}
};
int main()
{
cout << "1调用析构函数!" << endl;
Box *myBoxArray = new Box;
cout << "2调用析构函数!" << endl;
int result = myBoxArray->test();
cout << "3调用析构函数!" << endl;
delete myBoxArray; // 删除数组
cout << "4调用析构函数!" << endl;
return 0;
}