文章目录

✨✨✨学习的道路很枯燥,希望我们能并肩走下来!
🎈🎈🎈编程真是一件很奇妙的东西。你只是浅尝辄止,那么只会觉得枯燥乏味,像对待任务似的应付它。但你如果深入探索,就会发现其中的奇妙,了解许多所不知道的原理。知识的力量让你沉醉,甘愿深陷其中并发现宝藏。
前言
C语言中必不可缺少的部分 - 指针,本篇是带初学编程者对指针有一个了解,后续有指针进阶的内容,这里我们先认识一下!如有错误,请在评论区指正,让我们一起交流,共同进步!
本文开始
学习指针我们就要先知道指针式什么,让我们来了解一下!
1.指针是什么?
- 指针是内存中一个最小的单元编号,也就是地址
- 平时口语中的指针,通常指的是指针变量,用来存放内存地址的变量 - int* a;
指针就是地址,口语中说的指针通常指的是指针变量
内存:
指针变量:使用来存放地址的变量.
通过&(取地址操作符)取出变量的内存地址,把地址存放到一个变量中.
地址 == 编号 == 指针
内存中最小的单元是1个字节,1个字节对应一个编号
#include<stdio.h>
int main()
{
int a = 10;//内存中开辟空间存放10
int* p = &a;//存放a变量的空间,取出它的地址(编号),使用&
//整型a占用4个字节的空间,这里是将a的第一个字节的地址(编号)存放在p中
return 0;
}
如何编址?
其实它是由地址线产生的,对与不同的机器产生的地址就不同.
对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0);
32根地址线产生的地址:2的32次方个地址
每个地址标识一个字节,那我们就可以给4G的空间进行编址。
单位换算:2^32Byte == 2^32/1024KB ==
2^32/1024/1024MB == 2^32/1024/1024/1024GB == 4GB
- 在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以一个指针变量的大小就应该是4个字节。
- 在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地址
指针大小在不同平台下大小不同,与数据类型无关.
例如:32位平台下,int * a; char * b; 两个指针大小都是4个字节.
指针变量是用来存放地址的,地址是唯一标示一个内存单元的.
结论:指针的大小在32位平台是4个字节,在64位平台是8个字节
2.指针和指针类型
指针类型:
我们知道变量都有不同类型,整型,浮点型等,指针当然也有对应的类型!
指针定义:类型 + *
例如:
int a=10;
int* b=&a;
//这里指针变量b是整型,
//* 这里代表b是指针,存放a的地址,那它的类型呢?
//b指向a,a的类型为整型,所以b就是整型了
//int + * + b;->整型指针
char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址。
2.1指针+ - 整数
指针类型决定指针向前向后走一步有多大
代码演示:
#include<stdio.h>
int main()
{
int n = 10;
char* pc = (char*)&n;
int* p = &n;
printf("%p\n", &n);
printf("%p\n", pc);
printf("%p\n", pc+1);
printf("%p\n", p);
printf("%p\n", p+1);
return 0;
}
代码结果:
2.2指针的解引用
指针类型决定了,能解引用几个字节
例如:char* 的指针解引用只能访问一个字节,int* 的指针解引用就能访问4个字节.
3.野指针
野指针:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的).
3.1野指针成因
- 指针未初始化
#include<stdio.h>
int main()
{
int* p1;//局部变量指针未初始化,默认随机值
*p1 = 20;
return 0;
}
- 指针越界访问
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
int* p2 = arr;
int i = 0;
for (i = 0; i <= 11; i++)
{
//指针指向超出数组arr范围,p2就为野指针了
*p2 = i;
p2++;
}
return 0;
}
- 指针指向的空间释放free();
动态内存开辟时会讲解,这里知道就可以了.
3.2如何规避野指针?
- 指针记得初始化
- 指针不要越界
- 指针指向空间释放,及时置NULL
- 避免返回局部变量的地址
- 指针使用前坚持有效性,可以用assert(指针);防止指针为空
4.指针运算
4.1指针+ - 整数
前面讲解过,这里简单过一下
float * p=arr[0];
p++;
4.2指针 - 指针
用途:可以求出一个数组中元素的个数,运用数组的地址是连续的.(双指针,一个指向数组首元素地址,一个指向数组尾元素地址,相减即可)
int my_strlen(char* s)
{
char* p = s;//s首元素指针保留
while (*p != '\0')
{
p++;
}
//出循环指针p指向末尾
return p - s;
}
4.3指针的关系运算
标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
允许比较地址,但我们还是不要这样写,可以实现,但不一定一定可以.一定要注意!!!
//vp是地址,&va[0]也是地址
for(vp = &va[N_VALUES-1]; vp >= &va[0];vp--)
{
*vp = 0;
}
5.数组和指针
让我们从一段代码中分析一下吧!
#include<stdio.h>
int main()
{
int arr[5] = { 1, 2, 3, 4, 5 };
printf("arr = %p\n", arr);
printf("&arr[0] = %p\n", &arr[0]);
return 0;
}
结果显示:
我们会发现数组名和数组首元素地址是一样的. 但他们的意义不同,但都指向数组首地址.但是+1后的一样不同,想要了解可以看之前的文章,有详细介绍哦!
由此我们可以得出结论:数组名表示数组首元素地址
数组名可以当作地址存放到指针,那我们是不是可以用指针来访问数组呢?
#include<stdio.h>
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 的地址
例如:p[ 1 ] = arr[ 1 ]
所以我们就可以用指针来直接访问数组了
示例使用指针打印数组:
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5 };
int* p = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", *(p + i));
}
return 0;
}
6.二级指针
有我们所学的指针,变量就有地址,那指针变量就存在地址,它又存放到哪里呢? =》这就是我们要说的二级指针
int a = 10;
int* pa = &a;
int** ppa = &pa;
a的地址存放到pa, pa的地址存放在ppa中
int * 是pa的地址,* 说明ppa是指针 =》int ** ppa;ppa是二级指针
运算:
int b = 20;
*ppa = &b; // <=> pa = &b;
// ** ppa => * ppa 先找到 pa ,然后再解引用 * pa, 找到a
** ppa = 30; // <=>*pa = 30; <=> a = 30;
7.指针数组
指针数组:是存放指针的数组
int arr1[5];// 存放整形 int
char arr2[6]; // 存放字符型 char
int* arr3[5]; // 存放整形指针 int *
// []优先级大于 * ,arr3先于[]结合变成数组,数组中存放 int * ;
这里先简单的了解一下初级指针的内容,如果想进一步了解,可以看指针进阶这篇文章,相信会对你有进一步的帮助!!!
总结
✨✨✨各位读友,本篇分享到内容是否更好的让你理解了初级指针的内容,如果对你有帮助给个👍赞鼓励一下吧!!
🎉🎉🎉一遇挫折就灰心丧气的人,永远是个失败者。而一向努力奋斗,坚韧不拔的人会走向成功。
🎆🎆🎆感谢每一位一起走到这的伙伴,我们可以一起交流进步!!!一起加油吧!!!
