C++ 学习(七)指针、const修饰指针、指针与数组、指针与函数

21 篇文章 11 订阅

1、指针

一个指针变量指向了一个值的内存地址,因此可以通过指针可以间接访问内存。

在32位操作系统中,指针占用内存空间为4字节,64位操作系统中,指针占用内存空间为8字节,所有数据类型指针占用的内存空间都相同。

C++指针

语法: 数据类型 * 指针变量名;

空指针:定义指针变量并没有赋值,指针变量指向内存编号为0的空间;空指针指向的内存是不可以访问的。

野指针:指针变量指向非法的内存空间,在程序中避免出现野指针。

#include<iostream>
using namespace std;

int main()
{
	//指针定义变量
	int * p;
	int a = 5; 

	//空指针:定义指针变量并没有赋值,指针变量指向内存编号为0的空间
	//空指针指向的内存是不可以访问的
	// cout << "访问空指针 p = " << p << endl; // 此处会报错:使用了未初始化的局部变量p

	//野指针:指针变量指向非法的内存空间,在程序中避免出现野指针
	int* p1 = (int*)0x0022;
	// cout << "访问野指针 *p1" << *p1 << endl; //此处会报异常

	//指针变量赋值
	p = &a;
	cout << "指针地址:p = " << p << ", &a = " << &a << endl;

	//访问指针变量指向地址中的值
	cout << "指针变量地址中存储的值 *p = " << *p << ", a = " << a << endl;

	//修改指针值的内容
	*p = 12;
	cout << "指针值修改后:*p = " << *p << ", a = " << a << endl;

	//指针占用内存空间
	//在32位操作系统中,指针占用内存空间为4字节,64位操作系统中,指针占用内存空间为8字节
	//所有数据类型指针占用的内存空间都相同
	cout << "指针占用内存空间:" << sizeof(p) << endl;
	cout << "指针占用内存空间:" << sizeof(int *) << endl;
	cout << "指针占用内存空间:" << sizeof(float *) << endl;
	cout << "指针占用内存空间:" << sizeof(string *) << endl;

	system("pause");

	return 0;
}

输出结果

指针地址:p = 000000029DAFF664, &a = 000000029DAFF664
指针变量地址中存储的值 *p = 5, a = 5
指针值修改后:*p = 12, a = 12
指针占用内存空间:8
指针占用内存空间:8
指针占用内存空间:8
指针占用内存空间:8

Go语言指针

语法:

  1. var  指针变量名 *数据类型 
  2. 指针变量名 := new(数据类型)  //new返回数据类型的指针,即 *数据类型 ,值为数据类型的零值
package main

import (
	"fmt"
	"unsafe"
)

func main() {
	//指针定义变量
	var p *int
	var a int = 5

	//空指针:定义指针变量并没有赋值,指针变量指向内存编号为0的空间
	//空指针指向的内存是不可以访问的
	fmt.Println("空指针 p = ", p)
	// fmt.Println("访问空指针 *p = ", *p) //访问空指针指向的内存时报错

	//指针变量赋值
	p = &a
	fmt.Printf("p = %x, &a = %x\n", p, &a)

	//访问指针变量指向地址中的值
	fmt.Println("指针变量地址中存储的值 *p = ", *p, ", a = ", a)

	//修改指针值的内容
	*p = 12
	fmt.Println("指针值修改后:*p = ", *p, ", a = ", a)

	//指针占用内存空间
	//在32位操作系统中,指针占用内存空间为4字节,64位操作系统中,指针占用内存空间为8字节
	//所有数据类型指针占用的内存空间都相同
	fmt.Println("指针占用内存空间:", unsafe.Sizeof(p))


	//使用new关键字创建指针
	fmt.Println("---- 使用new关键字创建指针 ----")
	p1 := new(int)
	var b int = 3

	fmt.Println("new指针结果 p1 = ", p1, ", *p1 = ", *p1)

	fmt.Printf("p1数据类型:%T\n", p1)

	p1 = &b
	fmt.Printf("p1 = %x, &b = %x\n", p1, &b)

	//访问指针变量指向地址中的值
	fmt.Println("p1指针变量地址中存储的值 *p = ", *p1, ", b = ", b)

	//修改指针值的内容
	*p1 = 27
	fmt.Println("p1指针值修改后:*p = ", *p1, ", b = ", b)
}

 输出结果

空指针 p =  <nil>
p = c00000a0a0, &a = c00000a0a0
指针变量地址中存储的值 *p =  5 , a =  5
指针值修改后:*p =  12 , a =  12
指针占用内存空间: 8
---- 使用new关键字创建指针 ----
new指针结果 p1 =  0xc00000a0a8 , *p1 =  0
p1数据类型:*int
p1 = c00000a0d0, &b = c00000a0d0
p1指针变量地址中存储的值 *p =  3 , b =  3
p1指针值修改后:*p =  27 , b =  27

2、const修饰指针

C++ const 修饰指针

(1)const修饰指针 - 常量指针

指针的指向可以修改,但指针指向的值不可以修改。

语法:const 数据类型* 变量名 = 初始化值;

(2)const修饰常量 - 指针常量

指针的指向不可以修改,但指针指向的值可以修改。

语法:数据类型 * const 变量名 = 初始化值;

(3)const既修饰指针又修饰常量

指针的指向不可以修改,指针指向的值也不可以修改。

语法:const 数据类型* const 变量名 = 初始化值;

#include<iostream>
using namespace std;

int main()
{
	int a = 5;
	int b = 3;

	//1、const修饰指针 - 常量指针:指针的指向可以修改,但指针指向的值不可以修改。
	const int* p = &a;
	p = &b; //指针的指向可以修改
	// *p = 8; //指针指向的值不可以修改
	//可以通过修改b的值修改指针指向的值
	cout << "修改变量b值前:*p = " << *p << ", b = " << b << endl;
	b = 8;
	cout << "修改变量b值后:*p = " << *p << ", b = " << b << endl;

	//2、const修饰常量 - 指针常量:指针的指向不可以修改,但指针指向的值可以修改。
	int* const p2 = &a;
	// p2 = &b; //指针的指向不可以修改
	*p2 = 8;  //指针指向的值可以修改

	//3、const既修改指针又修饰常量:指针的指向不可以修改,指针指向的值也不可以修改。
	const int* const p3 = &a;
	// p3 = &b; //指针的指向不可以修改
	// *p3 = 8; //指针指向的值也不可以修改
	//可以通过修改a的值修改指针指向的值
	cout << "修改变量a值前:*p3 = " << *p3 << ", a = " << a << endl;
	a = 9;
	cout << "修改变量a值后:*p3 = " << *p3 << ", a = " << a << endl;

	system("pause");

	return 0;
}

输出结果

修改变量b值前:*p = 3, b = 3
修改变量b值后:*p = 8, b = 8
修改变量a值前:*p3 = 8, a = 8
修改变量a值后:*p3 = 9, a = 9

Go语言中没有const修饰指针

3、指针和数组

C++ 指针和数组

#include<iostream>
using namespace std;

int main()
{
	int arr[] = { 1,2,3,4,5 };

	//定义一个指针指向数组首地址
	int* p = arr;

	cout << "指针访问第一个元素:*p = " << *p << endl;

	//利用指针遍历数组
	for (int i = 0;i < 5; i++)
	{
		cout << "第 " << i << " 个元素值:" << *p << endl;
		p++;
	}

	system("pause");

	return 0;
}

输出结果

指针访问第一个元素:*p = 1
第 0 个元素值:1
第 1 个元素值:2
第 2 个元素值:3
第 3 个元素值:4
第 4 个元素值:5

Go语言指针数组

Go语言中把数组地址赋值给一个变量,这个变量类型其实是对应数据类型的指针数组;而不能像C++一样把数组地址赋值给一个*int(整型指针)变量。

package main

import "fmt"

func main() {
	arr := []int{1, 2, 3, 4, 5}

	//定义一个指针指向数组地址, 可以看到结果是一个指针数组,而不是数组的首地址
	p := &arr
	fmt.Printf("p数据类型是:%T\n", p)
	fmt.Printf("数组arr地址:%p,变量p地址:%p\n", &arr, p)

	//修改数组元素值
	arr[2] = 7

	//遍历指针数组
	for i := range *p {
		fmt.Printf("(*p)[%d] = %d\n", i, (*p)[i])
	}
}

在Go语言中, 运算符[]优先级高于*, 因此获取指针数组元素时需要加上小括号(*p),先取指针数组的首地址,(*p)[i] 再取对应元素的值

输出结果

p数据类型是:*[]int
数组arr地址:0xc000004480,变量p地址:0xc000004480
(*p)[0] = 1
(*p)[1] = 2
(*p)[2] = 7
(*p)[3] = 4
(*p)[4] = 5

4、指针和函数(地址传参)

C++ 函数(地址传参)

以下使用了头文件函数声明,基于上章节中 "C++函数分文件编写部分" ,可参考:C++ 学习(六)函数 及 函数的分文件编写_瘦身小蚂蚁的博客-CSDN博客

(可将以下代码内容合并一个文件中进行测试)  

在函数章节定义的头文件swap.h中增加函数声明:

//两数交换函数声明 - 地址传递
void swap(int *p1, int *p2);

在swap.cpp中添加函数定义: 

//定义函数(地址传递):交换两个数值(参数地址传递,形参发生改变影响实参改变)
void swap(int* p1, int* p2)
{
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

增加测试.cpp文件,调用swap地址传参函数: 

#include<iostream>
#include "swap.h"
using namespace std;

int main()
{
	int a = 5;
	int b = 3;

	cout << "交换前 a = " << a << ", b = " << b << endl;

	//调用交换两数函数(地址传参)
	swap(&a, &b);
	cout << "交换后 a = " << a << ", b = " << b << endl;

	system("pause");

	return 0;
}

输出结果

交换前 a = 5, b = 3
交换后 a = 3, b = 5

Go语言函数(地址传参)

以下基于上章节中 "Go语言调用其它包中的函数",可参考:C++ 学习(六)函数 及 函数的分文件编写_瘦身小蚂蚁的博客-CSDN博客

(可将以下2部分代码内容合并一个文件中进行测试) 

在公共函数common.go文件中新增交换函数(地址传参):

//定义函数(地址传递):交换两个数值(参数地址传递,形参发生改变影响实参改变)
func Swap2(a *int, b *int) {
	*a, *b = *b, *a
}

 新增测试文件

package main

import (
	"fmt"
	common "testProject/CPlus/19-函数-公用函数"
)

func main() {
	a, b := 5, 3
	fmt.Printf("交换前 a = %d, b = %d\n", a, b)
	common.Swap2(&a, &b)
	fmt.Printf("交换后 a = %d, b = %d\n", a, b)
}

输出结果

交换前 a = 5, b = 3
交换后 a = 3, b = 5 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值