0
点赞
收藏
分享

微信扫一扫

嵌入式系统中的GPIO控制:从理论到实践与高级应用

左小米z 2023-08-02 阅读 65

【C语言】初识指针

【前言】

一、指针是什么?

指针理解的2个要点:

从生活中举例,指针就好比我们家的门牌号一样,每个房间都有自己的门牌号,而我们则可以通过门牌号找到我们想要找到的人,别人也可以通过门牌号找到你。为此我们可以初步的了解指针就表示地址,通过指针我们可以找到相应类型的变量。

总结:指针就是地址,口语中说的指针通常指的是指针变量。

那我们就可以这样理解:

“内存”就好比一个大房子,里面有很多房间,为了能快速找到“内存”里面的值,我们给每个房间一个编号,这就是“内存编号”,这样就可以通过编号找到相应的值。

#include <stdio.h>
int main()
{
	int a = 10;//在内存中开辟一块空间
	int *p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。
	//a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址
    存放在p变量中,p就是一个之指针变量。
return 0;
}

总结:
指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。
那这里的问题是:
一个小的单元到底是多大?(1个字节)
如何编址?
经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的。
对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电
平(低电压)就是(1或者0)
那么32根地址线产生的地址就会是:

00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
...
11111111 11111111 11111111 11111111

这里就有2的32次方个地址。
每个地址标识一个字节,那我们就可以给
(2^32Byte == 2^32/1024KB ==2^32/1024/1024MB
==2 ^32/1024/1024/1024GB == 4GB )4G的空闲进行编址。
同样的方法,那64位机器,如果给64根地址线,那能编址多大空间,自己计算。
这里我们就明白:

总结:

二、指针和指针类型

这里我们在讨论一下:指针的类型
我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢?
准确的说:有的。
当有这样的代码:

int num = 10;
p = &num;

要将&num(num的地址)保存到p中,我们知道p就是一个指针变量,那它的类型是怎样的呢?
我们给指针变量相应的类型。

char  *pc = NULL;
int  *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;

这里可以看到,指针的定义方式是: type + * 。
其实:

那指针类型的意义是什么?

1. 指针±整数

代码示例:

#include <stdio.h>
int main()
{
	int n = 10;
	char *pc = (char*)&n;
	int *pi = &n;
	printf("%p\n", &n);
	printf("%p\n", pc);
	printf("%p\n", pc+1);
	printf("%p\n", pi);
	printf("%p\n", pi+1);
	return  0;
}

代码结果:

003FFB44
003FFB44
003FFB45
003FFB44
003FFB48

总结:指针的类型决定了指针向前或者向后走一步有多大(距离)。

2. 指针的解引用

代码示例:

#include <stdio.h>
int main()
{
	int n = 0x11223344;
	char *pc = (char *)&n;
	int *pi = &n;
	*pc = 0;  //重点在调试的过程中观察内存的变化。
	*pi = 0;  //重点在调试的过程中观察内存的变化。
	return 0;
}

总结:
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。

三、野指针

1.野指针成因

1.1 指针未初始化

代码示例:

#include <stdio.h>
int main()
{
	int *p;//局部变量指针未初始化,默认为随机值
	*p = 20;
	return 0;
}

2.2指针越界访问

代码示例:

#include <stdio.h>
int main()
{
	int arr[10] = {0};
    int *p = arr;
    int i = 0;
    for(i=0; i<=11; i++)
   {
      //当指针指向的范围超出数组arr的范围时,p就是野指针
      *(p++) = i;
   }
    return 0;
}

3.3指针指向的空间释放

2 .如何规避野指针

2.1 指针初始化
2.2小心指针越界
2.3指针指向空间释放即使置NULL
2.4避免返回局部变量的地址
2.5 指针使用之前检查有效性

代码示例:

#include <stdio.h>
int main()
{
    int *p = NULL;
    int a = 10;
    p = &a;
    if(p != NULL)
   {
      *p = 20;
   }
    return 0;
}

四、指针运算

1.指针±整数

代码示例:一维数组的打印

#include <stdio.h>
int main()
{
	int arr[6] = { 1,2,3,4,5,6 };
	int sz = 0, i = 0;
	int* p = arr;//定义一个整形指针,指向arr数组的首元素
	sz = sizeof(arr) / sizeof(arr[0]);//计算元素的个数
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *p + i);
	}
	return 0;
}

代码结果:

1 2 3 4 5 6

2 .指针-指针

代码示例:自定义字符串长度计算函数

#include <stdio.h>
int my_strlen(const char* right)
{
	char *left = right;//保存数组的首元素地址
	while (*(right)!='\0')//指向'\0'
	{
		right++;
	}
	return right - left;//指向'\0'的指针-指向首元素的指针
}
int main()
{
	char c[] = { "primary-cattle still needs to study hard !" };
	int sz=my_strlen(c);
	printf("%d\n", sz);
	return 0;
}

代码结果:

42

3.指针的关系运算

标准规定:

五、二级指针

在这里插入图片描述

对于二级指针的运算有:

int b = 20;
*ppa = &b;//等价于 pa = &b;
**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;

以此类推,还有三级指针和其他多级指针,常见的指针多为一级指针和二级指针,其他的几乎遇见不到。

七、指针数组

int arr1[5];
char arr2[6];

在这里插入图片描述

那指针数组是怎样的?

int* arr3[5];//是什么?

arr3是一个数组,有五个元素,每个元素是一个整形指针。

在这里插入图片描述

代码示例:

int main()
{
	//使用指针数组,模拟一个二维数组
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };
	//指针数组
	int* arr[] = { arr1, arr2, arr3 };

	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

好了,今天有关c语言初识指针的基础知识就讲到这里了,相信大家现在对指针应该有所了解了,后续会将指针更深层的理解。🎉

举报

相关推荐

0 条评论