【C语言】初阶指针 •̀ᴗ•
❤️前言
大家好呀ʕ•ﻌ•ʔ!,今天我为大家带来的是一篇关于我最近刚学的C语言指针方面的博客。指针和结构体都是C语言独有的特殊符号,可以说学好了它们,你就拿下了C语言的半壁江山。希望大家能喜欢我的这篇文章(•̀ᴗ• )ya~ 😘 😘 😘
👉 一、对于指针及指针变量的理解
🔎 1、地址(指针)
在程序运行时我们会调用内存空间来完成一系列的操作,那么就像我们在拜访别人的家时需要知道对方的地址那样,当我们需要访问内存空间时,我们就需要知道其对应的地址(指针)。比如我们在创建一个变量时就需要申请一块内存空间来存放它,这些内存空间中的每个小单元(一个字节)都对应着一个地址(指针)。
🔑 内存和编址
💡这里补充一些关于内存和编址的知识,便于大家理解指针的知识:
我们以32位机器为例进行讲解,32位机器的内存以32根地址线进行编址,地址线分别以高电平1和低电平0的电信号来显示状态,这些不同的状态可以带我们寻址不同的空间,如下图:
由于地址线的状态以高低电平的两种形式显示,那么32根地址线的状态便可以表示为32位的二进制数:
依据这些二进制数,我们便可以寻址内存单元并访问内存单元,经过仔细地运算和权衡,最终我们可以发现一个字节给一个对应的地址即——一个地址管理一个字节的空间大小是合适的,这样我们的寻址空间便是4GB的大小。
🔎 2、指针变量(指针)
温馨提示:我们在口语中常常直接将指针变量称为指针,所以有的时候大家需要分辨一下“指针”指的是变量地址还是指针变量。(为防止大家搞混指针和指针变量,在本文中,我会将指针变量称为指针或者直接称为指针变量,内存地址就直接称为地址)
想必经过上述的文章说明,你也已经对地址和指针有了一定的了解。那么我们继续来聊存放地址对应值的变量——指针变量。
我们知道,在32位机器上,地址是由32位的二进制数字表示,那么我们就可以推断出32位机器上一个指针变量的大小是4个字节(即32bit / 8 = 4byte),类比到64位机器上指针变量的大小便是8个字节。ps:64位机器以64根地址线进行编址。
注意,接下来我的讲解都以32位机器作为标准。
32位机器上,管理1个字节大小的地址却用固定4个字节大小的指针变量来存储,那么我们在利用指针访问变量时,难道要用多个指针变量来存储对应的多个地址吗(以int类型为例,难道我们要用4个指针变量才能访问这个变量吗)?。
用过指针的友友应该知道,我们只需要用一个指针变量就可以了,那么一个指针变量是如何完成这一点的呢?
.
答:在为创建的指针变量初始化时(不包括初始化为NULL),我们的指针变量只记录对应变量的低地址,这点和数组名即为数组首元素地址有一定的相似性,这样我们就能保证在机器不变的情况下,指针的大小不变:
👉 二、指针类型
在了解了上述的知识之后,你是否对指针类型存在的意义产生了疑惑?现在我们继续聊指针类型的相关内容:
指针类型的意义
🔎 1、访问视角的大小
- 指针类型决定了指针解引用的权限有多大,即能够访问多少字节的数据(或者理解为访问变量的视角大小)。
如:char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。
🔎 2、针对指针的变化幅度
- 决定了指针向前向后变化一个单位的大小(可以理解为走一步或退一步的步幅)
以下题为例:
//请你想想这段代码最后打印出的内容
#include <stdio.h>
int main()
{
int arr[] = {1,2,3,4,5};
short *p = (short*)arr;
int i = 0;
for(i=0; i<4; i++)
{
*(p+i) = 0;
}
for(i=0; i<5; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
//答: 0 0 3 4 5
此题中,我们以 short* 的指针类型来访问更改我们创建的一个整形数组中的元素。(注:short 类型占2个字节大小)用short*类型的指针改了四个0,移动一个单位即是移动两个字节,最后就是把1,2两个元素改成了0。
👉 三、野指针
野指针指 ”指向的位置是不可知的(随机的、不正确的、没有明确限制的)的指针“
造成野指针现象的原因大致有:
1.局部变量未初始化
2.越界访问
3.指针指向空间释放
如何规避野指针
1.指针初始化
1)当前不知道要初始化为什么地址的时候,直接初始化为NULL。
2)明确知道初始化的值。
2.避免指针越界访问
由于C语言本身不会检查数组越界的行为,所以我们在编写代码的时候要注意是否出现越界访问的情况。
3.指针指向空间释放时及时置NULL。
例:当空指针被函数调用后需要置空,否则原来的记录的地址会留在指针中。
4.指针使用之前检查有效性。
👉 四、指针运算
- 指针 ± 整数
地址由低到高变化,变化单位为指针类型的大小
- 指针 - 指针
指针减指针得到之间的元素个数。(指针和指针相减的前提是两个指针指向一块空间)
- 指针的关系运算
关系运算中值得注意的是,
👉 五、指针与数组
在数组中,每个元素对应着一个地址,而这些地址依照下标顺序由低到高排列,即下标零0对应元素地址(也即首地址)是最低地址。
具体运用以经典的C语言字符串逆序代码展现:
#include <stdio.h>
#include <string.h>
void rev(char* str)
{
int len = strlen(str);
char* left = str;
char* right = str + len - 1;
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
int main()
{
char str[10000] = { 0 };
gets(str);
rev(str);
printf("%s", str);
return 0;
}
👉 六、二级(多级)指针
我们的指针变量也是变量的一种,那么它也会被存储在一块由地址管理的内存空间中,这样我们也可以用指针来指向这个指针变量。这样我们就得到了二级(多级)指针了。
就像这样(՞• •՞):
注意解引用符( * )是可以叠加使用的,也就是说可以由二级指针解引用两次得到一级指针对应变量。
需要注意的一点是二级指针创建时需要使用两个(*),像这样int** pp = &p;
。
👉 七、指针数组
指针数组顾名思义即为以指针作为元素的数组,下面演示指针数组的创建:
例:整型指针的数组
int* parr[5]
//parr即为整形指针数组,可存5个整型指针
指针数组的应用:
#include <stdio.h>
int main()
{
int arr[3] = { 1, 2 ,4 };
int arr1[3] = { 1, 3 ,5 };
int* parr[2] = { arr, arr1 };
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 3; j++)
{
printf("%d ", parr[i][j]);
}
printf("\n");
}
return 0;
}
运行结果:
这里演示的是指针数组存数组名(即数组首地址)的应用,感觉上与二维数组有一定的相似性,二维数组存储数组作为元素,而指针数组存储数组名也可访问对应的数组。
🍀 结语
在以上的文章中,我们一起学习了C语言的 初阶指针 的知识,阅读了上述内容后,希望大家能够或有所得,学有所得后我相信大家肯定能通过指针来完成一些新的代码 ๐•ᴗ•๐ !
最后,希望正在看我的博客的你,能够天天进步,事事顺心,每天都有开心的好心情呀₍ᐢ •͈ ༝ •͈ ᐢ₎♡