Day 05 C++ 入门之指针
一、指针的基本概念
指针的作用:可以通过指针间接访问内存空间
内存是有编号的(每一个空间都有属于自己的编号),内存编号是从0开始记录的,一般用十六进制数字表示;可以利用指针变量保存地址。
简单来说,指针就是一个地址,指针是一个变量,这个变量保存的是一个空间(地址)的编号
1.1 指针变量的定义和使用
指针变量的定义语法:数据类型 * 变量名;
c++
int a = 7;
// 定义一个指针
int* p;
// 让指针记录变量a的地址
p = &a;// 建立关系
cout << "a的地址为:" << &a <<endl;
cout << "a的地址为:" << p <<endl;// 二者输出的值相同
p指向变量a所存在的空间
1.2 指针的使用
解引用使用指针,表示指针p所指向的内存空间的数值
c++
//解引用来使用 *指针变量名
*p = 8;//将p所指向的内存的变量进行了赋值为8,即a变成了8
1.3 指针所占的内存空间:
指针也是一种数据类型,不管什么类型,都占内存空间为4个字节(32位(x86)操作系统下),64位(x64)操作系统下占8个字节。
c++
int* p;
sizeof(p);
sizeof(int*);
sizeof(char*);
sizeof(double*);
二、空指针
指针变量指向内存中编号为0的空间;被用于初始化指针变量;空指针(指向的内存)不可以访问。
c++
int* p;
int* p = NULL;//空指针
空指针不可以访问,不可以解引用赋值。0~255之间的内存编号是系统占用的,因此不可以访问
三、野指针
指针变量指向非法的内存空间,不指向已有变量,也不指向空指针
c++
int* p = (int*)0x1100;// 一个数,强制转为地址+(int*)
这个地址空间我们没有去申请,就去使用他,这是不行的,是一个常见的一种错误,要尽量避免出现野指针
空指针和野指针都不是我们申请的空间,不要随意的去使用。
四、const修饰指针
const修饰指针有三种情况:
1. const修饰指针----常量指针
这个指针的指向可以改,但是指针指向的值不可以改。可以改指向,即原来指向a,现在进行更改,指向b、c、d等;但是不能更改指针指向的值,即指针指向的值不可以被更改,现在指向a,a的值不可以被修改。
2. const修饰常量----指针常量
指针指向不可以修改,但是指针指向的值可以被修改
3. const既修饰指针,又修饰常量
指针的指向和指向的值都不可以更改。即认定了,只能是它,不接受更改
c++
int a =7;
int b = 8;
int* p = &a;
//1. const修饰指针----常量指针
const int* p = &a;
p = &b;//正确,可以修改指向
*p =6;//错误,不可以修改指向的值
//2. const修饰常量----指针常量
int* const p = &a;
*p = 6;//正确
p = &b; //错误
//3. const既修饰指针,又修饰常量
const int* const p = &a;
注:常量指针,可以修改指针指向,(可以换男朋友,但不可以换底线(值));指针常量,可以修改值,(不换男朋友,一直换底线!!!)
只要被const修饰的就不可以改,const后面的就不可以改
五、指针和数组
利用指针访问数组中的元素。创建指针指向数组名(数组的数组名 = 数组首地址)即可。解引用就可以访问一个数组的首元素。
c++
int A[7]={1,2,3,4,5,6,7};
int* p = A;
cout << "第一个元素是" << *p << endl;
for(int i =0;i<7;i++)
{
cout << "第" << i+1 <<" 个元素是" << *p << endl;
p++;//是一个整型指针,所以+1就是往后移动一个整型数据所占空间的大小
}
指针指向数组之后,指针+1=向后移动一个数组元素的空间大小,即指向下一个元素
六、指针和函数
利用指针作函数的参数,可以修改实参的值。指针作为参数传递,传的是参数的地址
c++
//值传递
void swap1(int num1,int num2)
{
int temp = num1;
num1 = num2;
num2 = temp;
}
//址传递
void swap2(int* p,int* q)
{
int temp = *p;
*p = *q;
*q = temp;
}
int main()
{
int a = 7;
int b = 6;
swap1(a, b);
cout << "现在a、b的值为" << a << " 、" << b << endl;//7、6
swap2(&a, &b);
cout << "现在a、b的值为" << a << " 、" << b << endl;//6、7
system("pause");
return 0;
}
前面函数讲的是值传递,值传递是在另一片空间新开几个空间进行赋值,实参和形参是两个不同的空间。
这里讲的是址传递,传的是参数的地址,而内存空间的地址是没有重复的完全一样的编号的,所以这样实参和形参指向的是同一个地址,所以形参的改变会影响实参的改变,也就是说,形参的改变就是实参的改变。
七、指针配合数组和函数的例子
封装一个函数,利用冒泡排序,实现对整型数组的升序排序。
{4,3,6,9,1,2,10,8,7,5}
c++
//冒泡排序函数
//传数组,传的是数组的首地址。
void bubbleSort(int* A, int n)
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
if (A[j] > A[j+1])
{
int temp = A[j];
A[j] = A[j + 1];
A[j+1] = temp;
}
}
}
}
int main()
{
int A[10] = {4,3,6,9,1,2,10,8,7,5};
int* p = A;
bubbleSort(p,10);
for(int i=0;i<10;i++){
cout << A[i] << endl;
}
system("pause");
return 0;
}