那些C语言指针你不知道的秘密(1)

  • 本篇会加入个人的所谓‘鱼式疯言’
  • ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言,而是理解过并总结出来通俗易懂的大白话,我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的,可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念。
    那些C语言指针你不知道的秘密(1)_第1张图片

前言

在本篇文章中,小编将带大家进入指针的世界,人人都说指针难,那不妨看看小编的指针解读之后,看看会不会有什么不一样呢?
我们将学习到:

  • 指针变量和地址
  • 指针运算和泛型指针(void*)
  • const修饰指针的内容.

❤️❤️❤️下面,下面,下面 !!!我们开始吧吧吧!!!

一.指针变量和地址

在讲指针变量之前,下编认为有必要让大家知道一旦,C语言的指针和指针变量是不一样,在理解这个之前我们就要知道内存这个玩意

1.内存

举个生活的例子:
假设有⼀栋宿舍楼,把你放在楼⾥,楼上有100个房间,但是房间没有编号,你的⼀个朋友来找你玩,如果想找到你,就得挨个房⼦去找,这样效率很低,但是我们如果根据楼层和楼层的房间的情况,给每个房间编上号,有了房间号,如果你的朋友得到房间号,就可以快速的找房间,找到你。
所以生活中我们有了房间号就可以很轻松的找到房间.
那么我们如果需要读取数据呢?我们就需要找到对应的地址,当我们需要存储数据时,就会放入对应的地址,而我们所放的这些区域就叫做内存.

<1>.内存大小

通常我们把每一个内存单元记住一个字节(byte)
而内存最小的单位是比特(bit).
字节继续往上走就是我们的千字节(kb),兆字节(MB)…
换算单位如下(宝子们签收下哈):

1byte = 8bit
1KB = 1024byte
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB
1PB= 1024TB

2.指针变量,指针和地址的异同

上面我们理解了内存和指针的关系,我们在回到C语言,在C语言创建变量其实就是向内存申请空间

#include 
int main()
{
 int a = 10;
 return 0; 
 }

那些C语言指针你不知道的秘密(1)_第2张图片

上述代码中我们在内存中申请了4个字节,用来存放整数10,上图中4个字节的地址分别是:
0x006FFD70
0x006FFD71
0x006FFD72
0x006FFD73

<1>.取地址符(&)和解应用操作符(*)

鱼式疯言

在我们C语言中,指针就是地址,地址就是指针,只是我们生活中总是把指针变量说成指针.
那我们如何能得到a的地址呢? 这⾥就得学习⼀个操作符(&)-取地址操作符

#include 
int main()
{
 int a = 10;
 int *pa = &a;//取出a的地址
printf("%p\n", &a);
 printf("%p\n", pa);
 return 0; 
 }

那些C语言指针你不知道的秘密(1)_第3张图片

按照我画图的例⼦,会打印处理:006FFD70
&a 取出的是 a 所占 4 个字节中地址较⼩的字节的地址
指针变量的基本形式:
int pa=&a;
&a 含义就是把 a 的地址放入以
为标记的指针变量 p 中,
怎么理解呢?请看鱼式疯言:

鱼式疯言

int 代表的是原变量a的数据类型为 int,而 *+ pa 的含义就是告诉我们 pa是指针变量,是用来存放a的地址的

那些C语言指针你不知道的秘密(1)_第4张图片
下面我们看看解引用(*)

#include
int main()
{
	int a = 10;
	int* pa = &a;
	printf("%d\n", *pa);
	*pa = 20;
	printf("%d\n", a);
}

那些C语言指针你不知道的秘密(1)_第5张图片
看到效果了吧,pa的本质就是从pa的地址中重新得到a*,并且是可以修改的哦(下面我也会讲解不能修改的情况).

<2>.指针变量的大小

鱼式疯言

指针变量也有自己的类型的哦,比如int *** char double *** …而这些没有具体变量名但和我们平常用的int* char double 相似的,我们就把他们称为指针变量类型.

#include
int main()
{
	printf("%zd\n", sizeof(char*));
	printf("%zd\n", sizeof(short*));
	printf("%zd\n", sizeof(int*));
	printf("%zd\n", sizeof(double*));
	return 0;
}

那些C语言指针你不知道的秘密(1)_第6张图片
那些C语言指针你不知道的秘密(1)_第7张图片
这时就有小伙伴问了:
这里为什么会有两种不同的运行结果 ,而且不同的指针数据类型还内存大小相同 ???
其实啊 !!!
在我们C语言规定:
我们指针变量的大小与类型种类无关,与当时所处的环境有关,当编译器为X86环境时,我们指针大小为4个字节,当编译器为X64的环境时,我们指针大小为8个字节.

二.指针运算

指针的基本运算有三种,分别是:
• 指针± 整数
• 指针-指针
• 指针的关系运算

1.指针±整数

因为数组在内存中是连续存放的,只要知道第⼀个元素的地址,顺藤摸⽠就能找到后⾯的所有元素。
那些C语言指针你不知道的秘密(1)_第8张图片

#include
//指针+-整数
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));//p+i 这⾥就是指针+整数
	}
	return 0;
}

那些C语言指针你不知道的秘密(1)_第9张图片
指针加减整数的本质:
指针以指针变量类型为单位进行跳跃
什么意思呢?
et:
p 为int *类型指针,p+1就会跳过int大小的四个字节的地址,可能有0x1122->0x1126

鱼式疯言

虽然指针大小指针类型无关,但是指针进行加减整数时,跳多少个字节是与指针类型密切相关的
, char+1就跳过一个字节, short+1就跳过2个字节…

2.指针-指针

//指针-指针 
#include 
size_t my_strlen(char* s)
// size_t <=> 无符号整型 unsigned
{
	char* p = s;
	while (*p != '\0')
		p++;
	return p - s;
}
int main()
{
	printf("%zd\n", my_strlen("abc"));
	return 0;
}

那些C语言指针你不知道的秘密(1)_第10张图片
指针减去指针得到的两个指针变量的之间元素个数的绝对值.
啊啊啊!!!
为什么是绝对值呢???
因为啊,咱们内存地址的是有高低之分的,高地址-低地址得正,低地址减高地址得负.元素个数肯定为正的,所以我们要取绝对值

鱼式疯言

两个指针变量相减时,一定要注意是指向同一块内存才可以,什么意思呢? 比如我创建了arr1数组和arr2数组,我只能单独在arr1或者arr2数组中取用指针相减.,
不可以同时取arr1的地址又取arr2的地址然后相减,否则得到的是随机值.

3.指针的关系运算

//指针的关系运算 
#include 
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]);
	while (p < arr + sz) //指针的⼤⼩⽐较
	{
		printf("%d ", *p);
		p++;
	}
	return 0;
}

那些C语言指针你不知道的秘密(1)_第11张图片
前面我们说到了指针是有高低地址之分的,所以我们就可以根据高低地址的大小来判断不等号是否成立。

4.泛型指针(void*)

在指针类型中有⼀种特殊的类型是 void* 类型的,可以理解为⽆具体类型的指针。(或者叫泛型指针)
这种类型的指针可以⽤来接受任意类型地址。但是也有局限性。
void* 类型的指针不能直接进 ⾏ 指针的± 整数和解引⽤的运算。

#include 
int main()
{
	int a = 10;
	void* pa = &a;
	void* pc = &a;

	*pa = 10;
	*pc = 0;
	return 0;
}

那些C语言指针你不知道的秘密(1)_第12张图片
友友们都看到了吧,咱们的泛型指针 (void*) 是可以用来接受但是是不可以用来解引用的。

#include 
int main()
{
	int a = 10;
	void* pa = &a;
	printf("%p", pa + 1);
	return 0;
}

那些C语言指针你不知道的秘密(1)_第13张图片
友友们都看到了吧,咱们的泛型指针(void*)也是不可以用来指针加减的。

鱼式疯言

当我们需要用泛型指针时,那我们该怎么办呢?
这时我们就需要用到我们前面所讲的一个内容了,我们可以对泛型指针进行强制类型转化成我们想要的指针类型
et:下面示例:

#include 
int main()
{
	int a = 10;
	void* pa = &a;
	printf("%p\n", pa);
	printf("%p", (char*)pa + 1);
	return 0;
}

那些C语言指针你不知道的秘密(1)_第14张图片

三 const修饰的指针

1.const 的普通用法

变量是可以修改的,如果把变量的地址交给⼀个指针变量,通过指针变量的也可以修改这个变量。
但是如果我们希望⼀个变量加上⼀些限制,不能被修改,怎么做呢?
❤️接下来就要请我我们的专属嘉宾 const 来帮忙了!!!
const修饰普通常量:

 #include 
int main()
{
	int m = 0;
	m = 20;//m是可以修改的
	const int n = 0;
	n = 20;//n是不能被修改的
	return 0;
}

那些C语言指针你不知道的秘密(1)_第15张图片
这里我们看到cosnt修饰普通变量是不可更改的。

2.const 修饰指针变量

#include 
int main()
{
	const int n = 0;
	printf("n = %d\n", n);
	const int*  p = &n;
	*p = 20;
	printf("n = %d\n", n);
}

那些C语言指针你不知道的秘密(1)_第16张图片
如果我们直接修饰 指针变量p,我们无法通过p拥有的a地址来篡改n的数据。编译器就会报错。
那如果是下面这种呢?

#include 
int main()
{
	**const int n = 0;
	printf("n = %d\n", n);**
	int* const p = &n;
	*p = 20;
	printf("n = %d\n", n);
}

那些C语言指针你不知道的秘密(1)_第17张图片
上面我们看到了,这里的const我们修饰的是指针 p 本身和和变量 n
这时小伙伴们是不是又连发??????呢
那么让小编来解释下吧!
前面 cosnt 修饰n我们是没问题的
那么这边我们可以 const 修饰 p 怎么解释呢?
const 修饰 p 指的是修饰p自身这个变量的地址,而失去 *的 p 再也不能指向我们的 n,那么也不能通过锁定我们的n的地址来修改n的数值啦,我们这时就可以修改。

鱼式疯言

我们修改数据的时候可以通过两个方面修改:
1.通过变量名修改
2.通过该变量在内存存储的地址进行修改。

总结

在本篇博文中,我们主要就讲解了指针的三个点
1.指针变量和地址中,内存是什么以及其大小转化关系,指针和地址的区别 ,& 和 * 的运用。
2.我们还说明了,指针可以加上或减去一个整数,指针之间可以想减,指针可以关系判断,
还有一个比较特殊的指针类型 void* 的解释
3最后我们提了一嘴我们的关键字 const 的在普通变量和指针变量的用法。
小伙伴们有没有收获到呢?

本次博文就到这里了,感觉各位小伙伴的赏脸品读小编写的拙作哦,如果觉得小编写的还不错的咱可支持三关下,不妥当的咱评论区指正,希望我的文章能给各位家人们带来哪怕一点点的收获就是小编创作的最大动力
那些C语言指针你不知道的秘密(1)_第18张图片

你可能感兴趣的:(#,C语言与粉红色回忆,c语言,开发语言)