黑马程序员C++笔记--第一阶段基础:【指针和引用】

一、指针定义:

在32位操作系统下 ,指针只占4个空间字节大小
在64位操作系统下 ,指针只占8个空间字节大小

**空指针用于给指针变量进行初始化,不可以进行访问
	int *p=NULL;**
#include<iostream>
using namespace std;
int mian()
{ 
	//1.定义指针
	int a = 10;  //整型变量
	int *p;

	//int *p = &a;   **也可以这样定义**
	//野指针 : int *p = (int *)0x100
	//在程序中尽量避免野指针的出现 

	//指针变量指向变量a的地址
	p = &a;
	cout << "&a=" << &a<<endl;
	cout << p << endl;

	*p = 1000;  //代表解引用
	cout << "*p=" << *p << endl;

	system("pause");
	return 0;
}

引用作函数参数:

1. 值传递
(形参不会修饰实参)
(形参(函数体里的参数)可以发生改变。但是实参永远不会发生变化)

void mySwap01(int a, int b) {
	int temp = a;
	a = b;
	b = temp;
}

2. 地址传递
(形参会修饰实参)

void mySwap02(int* a, int* b) {
	int temp = *a;
	*a = *b;
	*b = temp;
}

3. 引用传递
(形参会修饰实参)

void mySwap03(int& a, int& b) {
	int temp = a;
	a = b;
	b = temp;
}
int main() {

	int a = 10;
	int b = 20;

	mySwap01(a, b);
	cout << "a:" << a << " b:" << b << endl;

	mySwap02(&a, &b);
	cout << "a:" << a << " b:" << b << endl;

	mySwap03(a, b);
	cout << "a:" << a << " b:" << b << endl;

	system("pause");

	return 0;
}

引用作函数返回值

作用:引用是可以作为函数的返回值存在的
注意:不要返回局部变量引用

用法:函数调用作为左值

//返回局部变量引用
int& test01() {
	int a = 10; //局部变量
	return a;
}

//返回静态变量引用
int& test02() {
	static int a = 20;  //静态变量,存在全局区
	return a;
}

int main() {

	//不能返回局部变量的引用
	int& ref = test01();
	cout << "ref = " << ref << endl;
	cout << "ref = " << ref << endl;

	//如果函数做左值,那么必须返回引用
	int& ref2 = test02();
	cout << "ref2 = " << ref2 << endl;
	cout << "ref2 = " << ref2 << endl; 

	test02() = 1000;

	cout << "ref2 = " << ref2 << endl;  //输出还是1000
	cout << "ref2 = " << ref2 << endl;

	system("pause");

	return 0;
}

引用的本质

本质:引用的本质在c++内部实现是一个指针常量.

讲解示例:

//发现是引用,转换为 int* const ref = &a;
void func(int& ref){
	ref = 100; // ref是引用,转换为*ref = 100
}
int main(){
	int a = 10;
    
    //自动转换为 int* const ref = &a; 指针常量是指针指向不可改,也说明为什么引用不可更改
	int& ref = a; 
	ref = 20; //内部发现ref是引用,自动帮我们转换为: *ref = 20;
    
	cout << "a:" << a << endl;
	cout << "ref:" << ref << endl;
    
	func(a);
	return 0;
}

常量引用

作用:常量引用主要用来修饰形参,防止误操作
在函数形参列表中,可以加const修饰形参,防止形参改变实参

//引用使用的场景,通常用来修饰形参
void showValue(const int& v) {
	//v += 10;
	cout << v << endl;
}

int main() {

	//int& ref = 10;  引用本身需要一个合法的内存空间,因此这行错误
	//加入const就可以了,编译器优化代码,int temp = 10; const int& ref = temp;
	const int& ref = 10;

	//ref = 100;  //加入const后不可以修改变量
	cout << ref << endl;

	//函数中利用常量引用防止误操作修改实参
	int a = 10;
	showValue(a);

	system("pause");

	return 0;
}

二、const 修饰指针

(1).常量指针

   const int * p = &a; 
	* p = 20 //错误 指针指向的值不可以改变
   	p = &b  //正确,指针指向可以改变

(2).指针常量

 int * const p = &a;
 * p = 20  //正确 指针指向的值可以改变
 p = &b   //错误 指针的指向不可以改变 

【常量指针和指针常量指向的区别】

#include<iostream>
using namespace std;
int mian()
{
	//1.const 修饰指针  常量指针
	int a;
	int b;
	const int * p1 = &a;
	//*p1 = 20;错误 指针指向的值不可以改变
	 p1 = &b;
	 //2.const 修饰常量 指针常量
	 int * const  p2 = &a;
	 *p2 = 100;
	 //p2 = &b; 错误 指针的指向不可以改变
	 
	 //3..const 修饰指针和常量
	 //都不可以修改了就
	system("pause");
	return 0;
}

三、指针运算

(1).赋值运算

int c = 16,d = 20; 
	float x = 26.4f, y = 56.2f;
	int *pc, *pd = &d; // 使pb指向变量b;
	float *px, *py = NULL; //使py的值为0;
	px = &x; //使指针px指向变量x;
	pc = pd; //两个指针变量赋值相等,并使他们指向同一个内存单元;

(2).算数运算

int x, y, *p = &y; 
x = *p++; //x=*(p++),x的值就是y;
x = *++p;//x=*(++p),先进行自增运算,再进行赋值运算;
x == (*p)++;// 就是y++;
x = ++(*p); //就是y+1

(3).指针运算案例

【输入两个整数,用指针将它们从大到小的顺序输出;】

#include<iostream>
using namespace std;
int main()
{
	int a, b, t;
	int *p = &a, *q = &b;

	cout << "请输入两个数:" << endl;
	cin >> a >> b;

	if (a < b)
	{
		t = *p;       //交换值
		*p = *q;
		*q = t;
	}

	cout << "交换后的数字为:" << endl;
	cout << a << "\t" << b << endl;
	cout << *p << "\t" << *q << endl;

	system("pause");
	return 0;
}

四、指针和数组

【指针和数组比较】:
在这里插入图片描述

(1).指针和一维数组

数组元素的指针:
p=a 跟 p=&a[0]是等价的;

【利用指针访问数组元素读取数组元素】;

#include<iostream>
using namespace std;
int main()
{
	//利用指针访问数组元素读取数组元素;
	//先定义一个数组;
	int app[10] = { 1,2,3,4,5,6,7,8,9,10 }, *p2 = app;
	int bpp[10],*p1=bpp;

	//随机的数组元素:
	cout << "输出随机的数组元素2x 的值" << endl;
	for (int j = 0; j < 10; j++)
	{
		*p1++ = 2 * (j + 1);   //就是等价于*(p++)=2 * (j + 1)
	}
	for (p1 = bpp; p1 < bpp + 10;)
	{
		cout << *p1++ << endl;
	}
	cout << "输出指定数组的元素app[10]:" <<endl;

	//指定数组的元素
	for (int i = 0; i < 10;i++)
	{
		//cout << app[i]<< endl;
		//利用指针访问数组 app[10];
		cout << *p2 << endl;
		p2++;  
	}


	system("pause");
	return 0;
}

(2).指针与二维数组

与一维数组不同的是:除了有元素的地址外,还有标识各行起始位置的行首地址

指针就是间接的访问数据,首先取得指针的内容,把它作为地址,然后从这个地址提取数据。通常用于动态数据结构;
【用指向元素的指针变量生成由自然数1-25组成的5*5方阵】

#include<iostream>
using namespace std;
int main()
{
	int a[5][5];
	int *jp = *a;  //就是代表a[0][0]的地址;
	int i, j;
	for (i = 1; jp < *a + 25; jp++)  //*a + 25 遍历数组的所有元素并对其进行赋值;
	{
		*jp = i++;
		//cout << *jp;
		if ((i - 1) % 5==0)
			cout << endl;
	}
	for (i = 0; i < 5; i++)
	{
		for (j = 0; j < 5; j++)
			cout << a[i][j]<<"	";
			cout<<endl;
	}
	system("pause");
	return 0;
}

五、指针与一维数组(指向整个一维数组)

int b[3][5]={12,45,46,14,48,46,48,87,56,47,16,38,92,75,73}
int (*p)[5]=b;
*表示这是一个指针变量;
说明这种指针变量指向的是整个一维数组

 p+i;p[i];*p+i 就表示b[i][0];
 *(p+i)+j;p[i]+j;&p[i][j] 就表示b[i][j];

【输出数组中每个元素的首地址】

#include<iostream>
using namespace std;
int main()
{
	int b[3][5] = {12,45,46,14,48,46,48,87,56,47,16,38,92,75,73};
	int(*p)[5] = b;  //p是一个行指针变量;*p+i和p[i]是列指针;

	//输出每行的首地址  p+i;p[i];*p+i 就表示b[i][0];
	cout << "输出每行的首地址(p+i):" << endl;
	for (int i = 0; i < 3; i++)
	{
		cout << *(p + i) << "---";  //p+i;*(p+i)都代表每行的首地址
	}cout << endl << endl;

	cout << "输出每行的首地址p[i]:" << endl;
	for (int i = 0; i < 3; i++)
	{
		cout << p[i] << "---";
	}cout << endl << endl;


	//输出数组每个元素的地址  *(p+i)+j;  ;&p[i][j] 就表示b[i][j];
	cout << "输出数组每个元素的地址 *(p+i)+j:" << endl;
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 5; j++)
		{
			cout << *(p + i) + j << "---";
		}
		cout << endl;
	}
	cout << endl;
	cout << "输出数组每个元素的地址 p[i]+j:" << endl;
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 5; j++)
		{
			cout << p[i] + j << "---";
		}
		cout << endl;
	}
	cout << endl;

	//输出数组每个元素的值;
	cout << "输出数组每个元素的值(普通方法)" << endl;
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 5; j++)
		{
			cout <<p[i][j] << "---";
		}
		cout << endl;
	}
	cout << endl;
	cout << "输出数组每个元素的值(指针方法)" << endl;
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 5; j++)
		{
			cout <<*(*(p+i)+j) << "---";
		}
		cout << endl;
	}
	system("pause");
	return 0;
}

/*
程序输出:
输出每行的首地址(p+i):
001AFCF4---001AFD08---001AFD1C---
输出每行的首地址p[i]:
001AFCF4---001AFD08---001AFD1C---
输出数组每个元素的地址 *(p+i)+j:
001AFCF4---001AFCF8---001AFCFC---001AFD00---001AFD04---
001AFD08---001AFD0C---001AFD10---001AFD14---001AFD18---
001AFD1C---001AFD20---001AFD24---001AFD28---001AFD2C---
输出数组每个元素的地址 p[i]+j:
001AFCF4---001AFCF8---001AFCFC---001AFD00---001AFD04---
001AFD08---001AFD0C---001AFD10---001AFD14---001AFD18---
001AFD1C---001AFD20---001AFD24---001AFD28---001AFD2C---
输出数组每个元素的值(普通方法)
12---45---46---14---48---
46---48---87---56---47---
16---38---92---75---73---
输出数组每个元素的值(指针方法)
12---45---46---14---48---
46---48---87---56---47---
16---38---92---75---73---
*/

六、指针数组

指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身决定。它是“储存指针的数组”的简称。

数组指针:首先它是一个指针,它指向一个数组。在32 位系统下永远是占4 个字节,至于它指向的数组占多少字节,不知道。它是“指向数组的指针”的简称。

*格式:类型名 数组名[数组长度]
【按照数组元素的大小对数组元素地址进行排序(冒泡排序)】

//sort 排序函数
#include<iostream>
using namespace std;
void sort(int *x[],int n)   //按照指针数组x所指向变量的值的大小,对指针数组x进行排序;
{
	int t;
	for (int i = 0; i < n - 1;i++)  //冒泡排序
	{ 
		for (int j = 0; j < n - i - 1; j++)  //相邻元素的比较
		{
			if (*x[j] > *x[j + 1])
			{
				t = *x[j];  //*x[j]为元素值;
				*x[j] = *x[j + 1];
				*x[j + 1] = t;
			}
		}
	}
		
		
}
int main()
{
	int i;
	int a[10] = { 12,45,78,89,56,23,14,25,36,47 };
	//先声明指针数组;
	int *b[10]; 
	//将a数组里的地址赋值给b[i];
	for (int i = 0; i < 10; i++)
	{
		b[i] = &a[i];  //&a[i]为a[10]中的每一个地址;
	}
	sort(b, 10); //调用函数就行排序
	cout << "输出排序后的序列:" << endl;
	for (i = 0; i < 10; i++)
	{
		cout << *b[i] << "   ";
	}


	system("pause");
	return 0;
}

七、指针与函数

利用指针做函数的参数,可以改变

【值传递与地址传递 输出数字】

#include<iostream>
using namespace std;
//1.值传递:如果主函数中定义了形参的值,那么相应的实参是不受影响的;
void swap1(int x, int y)
{
	int t;
	t = x;
	x = y;
	y = t;
	cout << "x=" << x << endl;
	cout << "y=" << y << endl;
}
//2.地址传递:实参不会改变;
void swap2(int *p1, int *p2)
{
	int t;
	t = *p1;
	*p1 = *p2;
	*p2 = t;
	cout << "地址传递的结果为:" << endl;
	cout << "a1=" << *p1 << endl;
	cout << "b1=" << *p2 << endl;

}
//引用传递:
int main()
{
	int a = 99;
	int b = 11;
	swap1(a, b);
	swap2(&a, &b);
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;

	system("pause");
	return 0;
}

/*
程序输出:
x=11
y=99
地址传递的结果为:
a=11
b=99
a=11
b=99
*/

【调用排序函数对数组里的元素进行排序】

#include<iostream>
using namespace std;
//声明冒泡排序函数;
void sort(int *arr, int len)
{
	for (int i = 0; i < len - 1; i++)
	{
		for (int j = 0; j < len - i - 1; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int t;
				t = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = t;
			}
		}
	}

}

//也可以创建一个打印函数的数组;
void print(int *arr, int len)
{
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << endl;
	}
}


int main()
{
	//创建一个数组;
	int arr[10] = { 12,45,78,89,56,23,14,25,36,39 };

	//求数组长度;
	int len = sizeof(arr) / sizeof(arr[0]);

	//调用函数,实现冒泡排序;
	sort(arr, len);

	//打印排序后的数组;(也可以用调用函数的形式打印)
	for (int i = 0; i < len; i++)
	{
		cout << arr[i] << endl;
	}
	cout << "用调用函数的形式输出为:" << endl;
	print(arr, len);
	system("pause");
	return 0;
} 

一起加油吧!

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值