C语言基础:初识指针(二)

当你不知道指针变量初始化什么时,可以初始化为空指针

cpp 复制代码
int *p=NULL;

我们看NULL的定义,可以看出NULL是0被强制转化为Void* 类型的0;实质还是个0;


如何避免野指针:

  1. 指针初始化
  2. 小心指针越界
  3. 指针指向空间释放即使置 NULL
  4. 避免返回局部变量的地址
  5. 指针使用之前检查有效性

指针运算

  • 指针+- 整数
  • 指针-指针
  • 指针的关系运算

指针+- 整数

下面这段代码实现的是打印数组的元素。

cpp 复制代码
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int* p = arr;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *p);
		p = p + 1;
	}
	return 0;
}

指针 - 指针

cpp 复制代码
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%d\n", & arr[9] - &arr[0]);
	return 0;
}

指针-指针得到的是中间元素的个数

例如:求字符串的长度。模拟实现strlen这个函数

cpp 复制代码
int my_strlen(char* str)
{
	char* start = str;
	char* end = str;
	while (*end != '\0')
	{
		end++;
	}
	return end - start;
}
int main()
{
	char arr[] = "bit";
	int len = my_strlen(arr);
	printf("%d\n", len);

	return 0;
}

指针与数组

数组名是首元素地址,怎么证明呢?通过下面的代码进行证明

cpp 复制代码
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	return 0;
}

注意:两个例外

1.&arr - &数组名 - 数组名不是首元素地址-数组名表示整个数组 ,所以&数组名取出的是整个数组的地址,

2.sizeof(arr) - sizeof(数组名)-数组名表示整个数组,sizeof(数组名)计算的是整个数组的大小。单位字节

下面的代码我们来看看他们的区别

cpp 复制代码
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	printf("%p\n", arr);
	printf("%p\n", arr+1);

	printf("%p\n", &arr[0]);
	printf("%p\n", &arr[0]+1);

	printf("%p\n", &arr);
	printf("%p\n", &arr + 1);
	return 0;
}

调试代码如下:

前面两个都是地址加4,最后一个加了40,(16进制的运算)

可以看出&arr是整个数组的地址,整个数组的地址加1,是跳过(整型)4*10(元素个数)=40

既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问其中任意一个就成为可能。

看下面的代码:

cpp 复制代码
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,0 };
	int* p = arr; //指针存放数组首元素的地址
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("&arr[%d] = %p   <====> p+%d = %p\n", i, &arr[i], i, p + i);
	}
	return 0;
}

可以看出是是一一对应的关系,所以 p+i 其实计算的是数组 arr 下标为i的地址。 那我们就可以直接通过指针来访问数组。

打印数组元素

cpp 复制代码
int main()
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
	int* p = arr; //指针存放数组首元素的地址
	int sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
 	}
    for (i = 0; i < sz; i++)
	{
		printf("%d \n", arr[i]);
	}
	return 0;
}

二级指针

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?

所以我们就有二级指针

a 的类型是int

pa 的类型是int*

ppa 的类型是int** 最后一个*表示是指针,指向的对象是int*

cpp 复制代码
int main()
{
	int a = 10;
	int* pa = &a;
	int** ppa = &pa;
	printf("%d\n", **ppa);
}

指针数组

与数组指针的区别 就像好孩子,重点是孩子,

指针数组-数组 --存放指针的数组。

数组指针-指针。

为啥要与指针数组,跟数组的由来一样,看下面的代码,对同一类型的地址存储,如果一个一个写下去,太麻烦了,所以我们要有指针数组来存放,这样就方便多了。

cpp 复制代码
int main()
{
	int a = 10;
	int b = 20;
	int c = 30;
	int* pa = &a;
	int* pb = &b;
	int* pc = &c;
	return 0;
}

怎么初始化呢?

cpp 复制代码
int arr[10];
int* arr1[3];//指针数组初始化

存放的类型都是int* 的类型

cpp 复制代码
int* arr1[3] = { &a,&b,&c };
cpp 复制代码
int main()
{
	int a = 10;
	int b = 20;
	int c = 30;
	int* arr2[3] = { &a,&b,&c };
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		printf("%d \n", *(arr2[i]));
	}
	return 0;
}
相关推荐
C++ 老炮儿的技术栈4 小时前
我们在设计tcp协议时,要传一个字符串过去,报文:头十长度十内容,是否要把‘\0‘也填入,长度是否包含‘\0‘
开发语言·数据结构·c++·mfc·c
传奇开心果编程5 小时前
【Rust入门练中学】第2课:变量、可变性与常量
开发语言·学习·rust
zr想努力5 小时前
从0开始配置Perforce4环境
开发语言
Navigator_Z6 小时前
LeetCode //C - 1252. Cells with Odd Values in a Matrix
c语言·算法·leetcode
幸运小圣6 小时前
PointerEvent 常用属性与事件整理【JavaScript】
开发语言·javascript·ecmascript
长谷深风1117 小时前
评测AI Agent:三种裁判各司其职
java·大数据·开发语言·人工智能·ai agent
边境悍匪7 小时前
蜗牛学苑 Java 智能体学习 Day42|项目周开发技术汇总 1 思维导图复盘
java·开发语言·spring boot·学习·spring
君顾17 小时前
本地托管机构管理源码实战:需求拆解、数据建模与多端部署
java·开发语言·托管
是隼人8 小时前
buuctf-pwn [NewStarCTF 2023 公开赛道]stack migration(64位栈迁移)题解(学习过程持续更新)
c语言·学习·安全·pwn入门·ctf入门
传奇开心果编程9 小时前
【Rust入门练中学】 第3课:数据类型
开发语言·学习·rust