一、指针的定义和使用
可以通过指针来保存一个变量的地址
例如:
int a=2;
就相当于内存中分出了一个内存块给变量a,而这个内存块中储存的数值为2;
假设这个内存块的地址为0x2e
;
则可以通过定义一个指针来储存这个地址0x2e
指针就是一个地址
1、定义指针
指针定义的语法:数据类型*指针变量名;
int * p;
让指针记录变量a的地址:
p=&a;//&为取地址符号
cout<<"a的地址为:"<<&a<<endl;
cout<<"指针p为:"<<p<<endl;
out:
x的地址为:0053FC70
指针p为:0053FC70
2、使用指针
可以通过解引用的方式来找到指针指向的内存;
解引用:*p
指针前加*
代表解引用,找到指针指向的内存中的数据;
当然也可以直接通过*p
来访问变量a
的内存,并对内存中的内容做修改;
*p=1000;
cout<<"x="<<x<<endl;
cout<<"*p="<<*p<<endl;
out:
x=1000
*p=1000
二、指针所占内存空间
c++规定在32位操作系统下,不管什么类型的指针都占用4个字节的空间;
64位操作系统下,占8个字节空间。
cout << "指针p占用的空间为:" << sizeof(p) << endl;
out:
32位操作系统:指针p占用的空间为:4
64位操作系统:指针p占用的空间为:8
三、空指针和野指针
1、空指针
空指针:指针变量指向内存中编号为0的空间
用途:初始化指针变量
注意:空指针指向的内存是不可以访问的
当一个指针不确定指向哪的时候可以暂时指向空指针。
//1.空指针用于给指针变量进行初始化
int * p = NULL;
//2.空指针是不可以进行访问的
*p = 100;
out:
输出会报错
空指针内存编号是系统占用的,因此不可访问
2、野指针
野指针:指针变量指向非法的内存空间
//野指针
//在程序中,尽量避免操纵野指针
int * p = (int *)0x1100;
cout << *p << endl;
out:
输出会报错
野指针操作的内存空间0x1100
并没用经过申请,因此没有权限访问。
四、const修饰指针
const修饰指针有三种情况:
int a = 10;
int b = 10;
int *p =&a;
1.const修饰指针 - - -常量指针
const int * p=&a;
常量指针
特点:指针的指向可以修改,但是指针指向的值不可以修改
*p = 20;错误:指针指向的值不可以修改
p = &b; 正确:指针的指向可以修改
2.const修饰常量 - - -指针常量
int * const p = &a;
指针常量
特点:指针的指向不可以改,指针指向的值可以修改
*p = 20;正确:指针指向的值可以修改
p = &b; 错误:指针的指向不可以修改
3.const即修饰指针,又修饰常量
const int * const p = &a
特点:指针的指向和指向的值都不可以修改
*p = 20;错误:指针指向的值不可修改
p = &b; 错误:指针的指向不可修改
技巧:看const右侧紧跟着的是指针还是常量,是指针就是常量指针,是常量就是指针常量
五、指针和数组
作用:利用指针访问数组元素
int numbers[10] = { 0,1,2,3,4,5,6,7,8,9 };
int * p = numbers;//numbers就是数组的首地址
for (int i = 0; i < 10; i++) {
cout << *p << " " << p << endl;
p++;
}
out:
0 003CF9C8
1 003CF9CC
2 003CF9D0
3 003CF9D4
4 003CF9D8
5 003CF9DC
6 003CF9E0
7 003CF9E4
8 003CF9E8
9 003CF9EC
六、指针和函数
作用:利用指针做函数参数,可以修改实参的值
在值传递中,函数里面对形参的修改不可以修改函数外实参的值;
地址传递可以直接对地址进行修改,可以通过形参来修改实参。
值传递函数swap():
void swap(int num1, int num2)
{
cout << "转换前:" << endl;
cout << "num1=" << num1 << endl;
cout << "num2=" << num2 << endl;
int temp = num1;
num1 = num2;
num2 = temp;
cout << endl << "转换后:" << endl;
cout << "num1=" << num1 << endl;
cout << "num2=" << num2 << endl;
}
int a = 2, b = 7;
swap(a, b);
cout << "a=" << a << endl;
cout << "b=" << b << endl;
out:
转换前:
num1=2
num2=7
转换后:
num1=7
num2=2
a=2
b=7
地址传递函数swap_p():
void swap_p(int *p1, int *p2)
{
//swap(*p1,*p2);
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
int a = 2, b = 7;
swap_p(&a, &b);//地址交换
cout << "a=" << a << endl;
cout << "b=" << b << endl;
out:
a=7
b=2
七、指针、数组、函数
利用指针对数组进行冒泡排序
打印数组的函数:
void PrintArr(int *arr, int len)
{
for (int i = 0; i < len; i++)
{
cout << arr[i] << " ";
}
cout << endl;
}
通过Bulling_point()函数中的形参(int *arr)来将数组地址传入函数中,通过指针直接操作数组中各元素,进行冒泡排序。
void Bulling_point(int *arr, int len)//传入数组首地址和数组长度
{
for (int i = 0; i < len-1; i++) {
for (int j = 0; j < len-1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
PrintArr(arr, len);
}
在main文件中直接调用上述函数;
而因为数组名即可代表整个数组的首地址,所以可以直接将numbers直接带入函数中的形参
(即int *arr = numbers
)
若此时带入形参的不是数组,而是变量,则需要取变量的地址后再代入(即int *p = &a
)
int numbers[10] = { 6,8,7,5,9,4,0,2,1,3 };
Bulling_point(numbers, 10);