C语言——深入解析C语言指针:从基础到实践从入门到精通(一)
文章目录
- 一.内存和地址
- 1.1内存
- 1.2地址
- 二.指针变量和地址
- 2.1 取地址操作符(&)
- 2.2 指针变量和解引用操作符(*)
- 2.2.1 指针变量
- 2.2.2 拆解指针变量
- 2.2.3 解引用操作符
- 2.3 指针变量的大小
- 三.指针变量类型的意义
- 3.1 指针的解引用
- 3.2 指针+-整数
- 3.3 void*指针
- 四.指针运算
- 4.1 指针+-整数
- 4.2指针-指针
- 4.3 指针的关系运算
- 总结
前言
前面分享了我对于函数使用的一些理解和看法,同样指针在C语言中也占有举足轻重的地位!博主将会以最大的努力将我对于指针的理解,以实践和运用的角度分享给大家!
一.内存和地址
说起内存和地址,我们可能对于这两个概念感到有些抽象到底什么是地址?什么是内存?只是知道这两个东西是电脑上才会出现的特征,那么我们就引出来一个例子帮助大家更好的理解这两个概念!
假设你住在学校的一栋宿舍楼🏢,楼里面有100个房间,你的朋友来你宿舍找你玩,他应该怎么才能找到你?难道需要一间房间一间房间的找吗,肯定是需要先知道你是的宿舍门牌号,才能找的到你!有了房间号才能更好更高效的找到需要的房间,那么对照生活中的例子,计算机中也是需要“房间号”的,这样计算和运行才能更加的高效和快捷!
1.1内存
在计算机电脑CPU处理数据的时候,是需要在内存上读取数据的,处理之后的数据也会放在内存中,电脑内存是8G、16G,32G等那么内存是如何高效而快捷的处理的?
内存会分成一个个小的内存单元,每个单元占一个字节
单位 | 字节 |
---|---|
Byte | 8 bit |
1KB | 1024 Byte |
1MB | 1024 KB |
1GB | 1024 MB |
1TB | 1024 GB |
1PB | 1024 TB |
我们可以把一个内存单元类比成一个宿舍,一个宿舍有8个人,一个内存单元里面有8个比特位,也就是一个字节里面有8bit,每个内存单元都有一个编号,相当于“宿舍号”,有了这个“宿舍号”就可以很快的访问内存单元了,我们生活中称之为门牌号,宿舍号。在计算机中被叫称为地址,在C语言中有个新的名字叫指针 即
内存单元编号== 地址==指针🫵
1.2地址
CPU在访问某个字节空间的时候,需要知道空间在内存中的什么位置,就需要给内存一个地址(内存单元编号),内存单元编号是不需要额外存储到其他空间中的,就像钢琴中的每个音键都有自己独有的声音这是钢琴制造商设计好的,是一种共识!同样计算机中也有这样的共识,因此只要知道了内存单元编号,计算机就能自己找到内存中对应的位置!
那么地址是怎么来的呢?
在理解地址之前我们必须知道,计算机是一个有很多软硬件组成的,每个硬件之间都需要相互协作才能完成工作,每个硬件都是靠线连接起来的,其中包括了地址总线
下面示意图表示更为直观
二.指针变量和地址
2.1 取地址操作符(&)
理解了地址和内存的关系接下来,我们回到C语言本身,其实创建变量就是在向内存申请空间用来存放数据
int main()
{int a = 10;return 0;
}
向内存申请4个单位字节,用来存放10名字叫a,但是这个a不是给编译器看的是给人看的
上述就是变量a在内存中申请空间并赋值的过程(VS2022采用的是小端字节序后期会介绍)
那么如何得到a的地址呢?
就要引入&操作符——取地址操作符
#include<stdio.h>
int main()
{int a = 10;&a;printf("%p\n", &a);return 0;
}
取出的是a所占字节中较小的字节
虽然变量a占四个字节但是取出第一个字节顺藤摸瓜就能访问到四个字节的数据
2.2 指针变量和解引用操作符(*)
2.2.1 指针变量
通过取地址操作符(&)取出变量的地址 例如:00000028312FFBD4,这个数值有时候也是需要存起来的,我们就可以把这个值存在变量中,这个变量叫指针变量
int main()
{int a = 10;int* pa = &a;printf("%d\n", *pa);return 0;
}
指针变量也是变量,这种变量就是专门用来留存地址的,放在指针变量中的值我们都会理解为地址
2.2.2 拆解指针变量
我们看到pa的类型是int*
,那我们该怎样理解指针类型呢?
int a = 10;
int* pa = &a;
演示
pa左边写的是int*
,* 表示为指针变量,int是说明pa指向的是变量是(int)类型的变量
🐱照猫画虎🐯
怎么把char型变量放在指针中
int main()
{char ch = 'w';char* pc = &ch;return 0;
}
2.2.3 解引用操作符
会把指针(地址)存起来也要把(地址)取出来,这时候我们就要用到解引用操作符——(*)也叫(间接访问操作符)
int main()
{char ch = 'w';char* pc = &ch;printf("%c\n", *pc);*pc = 'a';printf("%c\n", *pc);return 0;
}
当然我们也可以通过把解引用操作符改变所指变量的地址
但是为什么要这么麻烦改变一个变量的值还要放在一个指针变量中再通过指针改变变量的值?直接改变变量的值不是跟简单吗?
其实把变量交给指针处理就是为了多增加一种访问途径,多一个途径就会方便很多,后期文章介绍中就会体现出来!
2.3 指针变量的大小
指针变量也是变量,既然是变量系统就会向内存申请空间,指针变量的大小是多大呢?
32位机器有32个bit位就需要占4个字节的空间
64位机器有64个bit位就需要占8个字节的空间
地址存储需要多大空间,指针变量就申请多大空间
int main()
{printf("%zd\n", sizeof(char*));printf("%zd\n", sizeof(int*));printf("%zd\n", sizeof(short*));printf("%zd\n", sizeof(double*));printf("%zd\n", sizeof(long*));printf("%zd\n", sizeof(long long*));printf("%zd\n", sizeof(float*));return 0;
}
总结
指针变量的大小和类型是无关的,只要是指针变量,在相同的平台下大小都是相同的,有可能是占4/8个字节。
三.指针变量类型的意义
指针变量的大小和类型无关,只要是指针变量,在同一个平台下都相同那么,各种类型的指针其作用是什么?
3.1 指针的解引用
两段代码介绍指针在内存中的变化
int main()
{int n = 0x11223344;int* pn = &n;*pn = 0;return 0;
}
当指针类型是int*类型
的时候一次访问内存空间4个字节
int main()
{int n = 0x11223344;char * pn = &n;*pn = 0;return 0;
}
当指针类型是char*类型
的时候一次访问内存空间1个字节
3.2 指针±整数
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;
}
运行结果
char类型指针(±1)一次跳过一个字节
int类型指针(±1)一次跳过四个字节
结论
指针的类型决定了指针向前向后一次跳过几个字节(距离)
3.3 void*指针
void*类型的指针表示为具体类型的指针(泛型指针),这种指针可以接受任意类型的指针,不会引起冲突
但是void*类型
的指针不能直接进行+-
和解引用运算
int main()
{int a = 10;char* pc = &a;char ch = &a;void* pv = &a;pv = &ch;*pv='e';//errpv++//errreturn 0;
}
有上述可见,void*指针是可以接受任意类型的地址,但是无法直接进行指针运算!
(void*类型的作用一般是作为函数的参数的部分,用来接收不用类型数据的地址,后期会分享!)
四.指针运算
分为三种:
指针±整数
指针-指针
指针的关系运算
4.1 指针±整数
数组在内存中是连续存放的,只要找到第一个元素就能找到剩余的元素
int arr[10]={1,2,3,4,5,6,7,8,9,10};
之前访问数字组可以通过遍历循化一个个打印,现在也可以用指针
数组寻常遍历
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]);for ( i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}
指针
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* p = &arr[0];int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);for (i = 0; i < sz; i++){printf("%d ", *(p+i));}return 0;
}
打印字符串
//打印字符串
int main()
{char arr[] ="hello world";char* pc = &arr[0];while (*pc!='\0'){printf("%c", *pc);pc++;}return 0;
}
4.2指针-指针
前提:两个地址必须指向同一块空间,否则不能相减;
结果是的到两个指针间的个数
求字符串长度
size_t my_strlen(char*pc)
{int count = 0;while (*pc != '\0'){count++;pc++;}return count;
}
int main()
{char arr[] ="hello world";char* pc = &arr[0];printf("%d\n", my_strlen(arr));return 0;
}
结果
4.3 指针的关系运算
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* p = &arr[0];int sz = sizeof(arr) / sizeof(arr[0]);while (p<arr+sz){printf("%d ", *p);p++;}return 0;
}
总结
以上就是内容是对指针的初步认识,下期继续分享指针在数组,函数,以及在各种常见情况下的应用和实例!感谢大家的观看!