2021.12.19 关于c语言指针初阶

目录

指针是什么

指针类型

指针的类型如下:

指针类型的意义:

野指针

指针运算

指针和数组

二级指针 


指针是什么

定义:

指针,是C语言中的一个重要 概念 及其 特点 ,也是掌握 C语言 比较困难的部分。 指针也就是 内存地址 ,指针变量是用来存放内存地址的变量,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的 存储空间 长度也不同。

举例1:

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int main()
{
	int a = 10;
	int* p = &a;  //取 a 的地址,用指针变量 p 来接收其地址
	printf("%p\n", &a);
	printf("%p\n", p);  
	return 0;
}

结果为: (我们由结果而知指针变量 p 中存储的是整型 a 的地址)

2021.12.19 关于c语言指针初阶

举例2:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
 
int main()
{
	int a = 10;
	printf("%p\n", &a); // & 为取地址操作符   
	int* pa = &a;  // 这里的 * 代表 pa 为指针变量,pa是用来存放 a 的地址
	*pa = 20;  // * 间接访问操作符(解引用操作符)  pa 根据 a 的地址将 a 的值进行改变                
	printf("%d\n", a);
    return 0;
}
 

结果为:

2021.12.19 关于c语言指针初阶


指针类型

指针的类型如下:

2021.12.19 关于c语言指针初阶

各类型指针指针所占字节的大小又为多少呢?

举例:

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int main()
{
	int* pa;
	short* ps;
	char* pc;
	float* pf;
	double* pd;
	printf("%d\n", sizeof(pa));
	printf("%d\n", sizeof(ps));
	printf("%d\n", sizeof(pc));
	printf("%d\n", sizeof(pf));
	printf("%d\n", sizeof(pd));
	return 0;
}

结果为:(我们由结果可得不管指针为啥类型,其字节大小都为4!)

2021.12.19 关于c语言指针初阶


指针类型的意义:

注意:虽然每种类型指针的字节大小都为4,但是各类型指针还有所区别的。

a:指针的类型决定了  指针解引用的权限有多大。

举例:(我们用不同类型的指针对整型 a 来解引用,并看其存储的改变)

int a =0x11223344;(此时的 a 为16进制数)

整型 a 初始地址中的存储为:

2021.12.19 关于c语言指针初阶

(int 类型指针可解引用4个字节)

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int main()
{
	int a = 0x11223344; 
	int* pa = &a;
	*pa = 0;
	return 0;
}

整型 a 地址中的存储改变为:

2021.12.19 关于c语言指针初阶

(char 类型的指针可解引用1个字节)

int main()
{
	int a = 0x11223344;
	char* pa = &a;
	*pa = 0;
	return 0;
}

整型 a 地址中的存储改变为:

2021.12.19 关于c语言指针初阶

b:指针的类型决定了 指针走一步的距离有多长。

举例:

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int main()
{
	int arr[10] = { 0 };
	int* pa = arr;
	char* pc = arr;
	printf("%p\n", pa);
	printf("%p\n", pa+1);
	printf("%p\n", pc);
	printf("%p\n", pc+1);
	return 0;
}

结果为:(可以得出 整型指针+1走了4个字节,字符型指针+1走了1个字节)

2021.12.19 关于c语言指针初阶


野指针

定义:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)指针变量在定义时如果未初始化,其值是随机的,指针变量的值是别的变量的地址,意味着指针指向了一个地址是不确定的变量,此时去解引用就是去访问了一个不确定的地址,所以结果是不可知的。

举例:

情况1   (指针未初始化)

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS


int main()
{
	int* p;    
	*p = 20;  
	return 0;
}

注意: 局部变量指针不初始化,默认为随机值 ,此时我们对其指针变量解引用时,便是非法访问了。因为所访问的地址并不属于我们当前程序,则此时的 p 叫做野指针。

情况2   (指针越界访问)

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int main()
{
	int i = 0;
	int arr[10] = { 0 };
	int* pa = arr;
	for (i = 0; i <= 10; i++)
	{
		*pa = i;
		 pa++;
	}
	return 0;
}

图解如下: 

2021.12.19 关于c语言指针初阶

情况3 (指针指向的空间释放) 

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int* test()
{
	int a = 10;
	return &a;     //此时我们的变量 p 储存了 a 的地址     (空间释放)
}                  //但出了test()函数,a 的生命周期结束,其空间地址返还给了操作系统

int main()
{
	int* p = test(); //此时我们调用 test()函数
//调用完后,我们任然对指针变量p所存储的 a 的地址进行访问,此时便为非法访问且 p 为野指针    
    *p = 20;     
	return 0;
}

避免野指针的方法:

a:指针需要初始化,若不知初始化为啥,可直接初始化为 NULL (空指针)

b:注意指针的越界!

c:当指针指向的空间释放时,我们要即使将指针变量置成 NULL

d:指针使用之前要检查其有效性

举例:

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int main()
{
	int* p = NULL;
	*p = 10;
	return 0;
}

 注意:NULL 为0 ,而0这个地址的空间时不属于我们用户的,从而不能直接解引用!

为判断指针的有效性我们可修改该代码为:(先判读是否为空指针)

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int main()
{
	int* p = NULL;
	if(p!=NULL)
	*p = 10;
	return 0;
}


指针运算

指针 +- 整数

举例:

(int 类型指针+1 = +4字节 +2=+8字节)(char 类型指针+1= +1字节 +2= +2字节)

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int main()
{
	int arr[5];
	int* pa;
	for (pa = &arr[0]; pa < &arr[5];)
	{
		*pa++ = 0;
	}
	return 0;
}

  该代码将arr数组全初始化为0,此时的 *pa++=0 ,便根据其指针变量类型加其对应的字节大小,从而完成数组的初始化。

应用:(利用指针打印数组中各元素)

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	int* pa=arr;
	int* pc = arr + 9;
	while (pa<=pc)
	{
		printf("%d ", *pa);
		pa++;
	}
	return 0;
}

结果为:

2021.12.19 关于c语言指针初阶


指针 - 指针

举例:

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	int* pa=arr;
	int* pc = arr + 9;
	int a = pc - pa ;
	printf(" %d\n", a);
}

结果为:(可以看出指针 - 指针得到的是两指针间的元素个数)

2021.12.19 关于c语言指针初阶

注意:两指针要指向同一块空间!

举例:(错误使用)(这是典型的两指针指向不同空间)

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	int* pa=arr;
	char brr[5];
	char* pd = brr;
	int a = pd - pa ;
	printf(" %d\n", a);
}

应用:(利用指针求字符串长度)

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int my_strlen(char* start)
{
	 char * end = start;
	 while (*end != '\0')
	 {
		 end++;
	 }
	 return end-start;
}

int main() 
{
	char arr[] = { "abc" };
	char* pa = arr;
	int ret = my_strlen(pa);
	printf(" %d\n", ret);
	return 0;
}

结果:

2021.12.19 关于c语言指针初阶


指针和数组

我们需了解的数组知识点:

知识点1:

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("%d\n", arr[2]);
	printf("%d\n", 2[arr]);
	// arr[2] --> *(arr+2) --> *(2+arr)--> 2[arr]
	return 0;
}

结果为:

2021.12.19 关于c语言指针初阶 

知识点2:数组名是数组首元素的地址

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int main()
{
	int arr[10]={ 1,2,3,4,5,6,7,8,9,10 };
	printf(" %p\n", arr);
	printf(" %p\n", &arr[0]);
	return 0;
}

结果为:     

2021.12.19 关于c语言指针初阶

 应用:(指针初始化数组并打印数组各元素)

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int main()
{
	int i = 0;
	int arr[10] = { 0 };
	int* p = arr;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}

结果为: 

2021.12.19 关于c语言指针初阶


二级指针 

举例:

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int main()
{
	int a = 10;
	int* pa = &a;      // pa为指针变量     一级指针
	int**ppa = &pa;	  //  pa既然是变量就会有其地址, &pa 取出其地址存入ppa中
	// 此时的 paa 为二级指针  解引用  *ppa ==pa  *pa ==a   * *ppa ==a
	return 0;
}

一定要理解  int**ppa = &pa    这里为啥有两个 ‘*’ 

我们首先观察一级指针 int *pa =&a  这里整型变量a的类型为 int

其次观察二级指针 int**ppa = &pa  这里整型指针变量pa的类型为 int* 


初级指针的内容就是这么多了,博主后期还会更进阶指针的内容。

谢谢浏览,博主写文章不易,可以留下您的点赞,或收藏激励博主!

若文章有错误,请各大佬多多指出,我会及时更正! 

上一篇:每日工作流程


下一篇:2021-12-19 接口性能优化的11个小技巧