C语言指针超详细讲解下篇

 更新时间:2022年04月13日 12:38:27   作者:初学C语言者  
指针提供了对地址操作的一种方法,因此,使用指针可使得 C 语言能够更高效地实现对计算机底层硬件的操作。另外,通过指针可以更便捷地操作数组。在一定意义上可以说,指针是 C 语言的精髓

前言

本文接着上一篇内容,继续学习指针相关知识点。

指针运算

  • 指针±整数
  • 指针-指针
  • 指针的关系运算

指针±整数

#define VALUE 5
int main()
{
	float values[VALUE];
	float *vp;
	//指针+-指针,关系运算
	for (vp = &values[0]; vp < &values[VALUE];)
	{
		*vp++ = 0;//通过这样完成初始化
	}
	for (int i = 0; i < VALUE; i++)
	{
		printf("%d ", values[i]);
	}
	return 0;
}

在这里插入图片描述

指针-指针

int main()
{
	int arr[10] = { 0 };
	printf("%d\n", &arr[9] - &arr[0]);//得到元素的个数
	printf("%d\n", sizeof(arr)/sizeof(arr[0]));//计算元素个数
	int* p0 = &arr[0];
	int* p9 = &arr[9];
	printf("%d\n", (p9 - p0));//得到元素的个数
	return 0;
}

通过数组首尾元素的地址相减,得出的就是数组元素的个数,

-int*表示指针指向的地址里面,存放的数据类型是整形,占用4个字节

  • 数组元素地址+1,就是寻找下一个元素的地址,就会移动4个字节

在这里插入图片描述

通过调试更加清楚的观察到这一现象,int 数组每个元素占用四个字节:

  • &arr[0]: 0x005cf7f8
  • &arr[0]+1: 0x005cf7fc,地址移动1位,即int*指针移动1位,字节增加4个。

在这里插入图片描述

前提条件:两个指针必须指向同一块空间:

char ch[5];
int arr[6];
%arr[4]-&ch[3];//错误的

前面的文章介绍了字符串长度的方法两种方法:

  • 循环
  • 递归

这里介绍第三种方法, 指针

int mylen(char* pa)//传参是数组首元素的地址
{
	char* p = pa;//首元素地址
	while (*pa)//元素不是‘0'
	{
		pa++;//通过地址访问字符串
	}
	//结尾字符0的地址减首元素地址
	return pa - p;//指针相减是元素的个数
}
int main()
{
	char arr[] = "abcdef";
	int len = mylen(arr);
	printf("%d", len);
	return 0;
}

指针的关系运算

标准规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与

指向第一个元素之前的那个内存位置的指针进行比较

int main()
{
	//
	for (vp = &values[5]; vp > &values[0];)
	{
		*--vp = 0;
	}
	for (vp = &values[5-1]; vp >= &values[0];vp--)//不允许
	//地址会指向首元素前面的地址,这是不允许的
	{
		*vp = 0;
	}
	return 0;
}

指针和数组

int main()
{
	int arr[10] = {1,2,3,4,5,6,7,8,9,0};
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	int *p = arr;//p存放的是数组首元素的地址
	return 0;
}

数组名和数组首元素的地址是一样的。数组名表示的是数组首元素的地址。(2种情况除外,数组系列文章详细介绍了)

在这里插入图片描述

既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个就成为可能

int main()
{
	int arr[] = {1,2,3,4,5,6,7,8,9,0};
	int *p = arr; //指针存放数组首元素的地址
	int sz = sizeof(arr)/sizeof(arr[0]);
	for(int 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 元素的地址。那就可以直接通过指针来访问数组:

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

在这里插入图片描述

二级指针

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?这就是 二级指针

int main()
{
	int a = 10;
	int* pa = &a;
	int** ppa = &pa;
	return 0;
}
  • a的地址存放在指针pa中,pa是一级指针
  • pa的地址存放在ppa中,ppa是二级指针

在这里插入图片描述

对于二级指针的运算有:

*ppa 通过对ppa中的地址进行解引用,这样找到的是 pa , *ppa 其实访问的就是 pa .

int b = 20;
*ppa = &b;//等价于 pa = &b;

**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a

**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;

指针数组

指针数组是指针还是数组?

是数组。是存放指针的数组

在数组系列文章中,已经介绍了整形数组,字符数组:

int arr1[5];//占用20个字节
char arr2[5];//占用5个字节

在这里插入图片描述

举例 1

指针数组:

int main()
{
	int data1[] = { 1,2,3,4,5 };
	int data2[] = { 2,3,4,5,6 };
	int data3[] = { 3,4,5,6,7 };
	//看成二维数组
	int* arr[3] = { data1,data2,data3 };
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 5; j++)
		{//[]是操作符
			printf("%d ", arr[i][j]);//不需要解引用
		}
		printf("\n");
	}
	   
	return 0;
}

arr3是一个数组,有五个元素,每个元素是一个整形指针,就是一个地址:

  • arr[0],为元素data1,是指针变量,本身也是一维数组 { 1,2,3,4,5 } 的数组名,代表首元素地址
  • arr[1],为元素data2,是指针变量,本身也是一维数组 { 2,3,4,5,6 } 的数组名,代表首元素地址
  • arr[2],为元素data3,是指针变量,本身也是一维数组 { 3,4,5,6,7 } 的数组名,代表首元素地址

在这里插入图片描述

在这里插入图片描述

通过调试也能发现:

  • 指针数组首元素data,是指针变量,也是一维数组首元素的地址
  • 通过数组名 + i 就能访问数组里的元素
  • 指针数组可看成二维数组
arr[0]=data1;//指针数组首元素data,是指针变量,也是一维数组首元素的地址
arr[0][0]=data1[0];//看成一维数组
arr[0][1]=data1[1];
arr[0][2]=data1[2];
arr[0][3]=data1[3];
arr[0][4]=data1[4];

在这里插入图片描述

打印结果见下图:

在这里插入图片描述

代码换成下面这个效果一样,从地址的解引用角度去写:

int main()
{
	int data1[] = { 1,2,3,4,5 };
	int data2[] = { 2,3,4,5,6 };
	int data3[] = { 3,4,5,6,7 };
	//看成二维数组
	int* arr[3] = { data1,data2,data3 };
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 5; j++)
		{
			printf("%d ", *(arr[i]+j));//地址访问解引用
		}
		printf("\n");
	}   
	return 0;
}

在这里插入图片描述

举例 2

指针数组中元素都是指针变量,就是地址

int main()
{
	int a = 10;
	int b = 11;
	int c = 12;
	int d = 13;
	int e = 14;
	int* arr[5] = { &a,&b,&c,&d,&e };//指针数组存放的元素是指针变量,就是地址
	for (int  i = 0; i < 5; i++)
	{
		printf("%d ", *(arr[i]));//地址解引用
	}
	return 0;
}

在这里插入图片描述

总结

本文继续学习了指针相关的知识点,指针是C语言的重中之重,在基础阶段,指针的学习就告一段落了。

下一篇将学习结构体的知识点。(链接直达

到此这篇关于C语言指针超详细讲解下篇的文章就介绍到这了,更多相关C语言 指针内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 深入浅析 C++ 调用 Python 模块

    深入浅析 C++ 调用 Python 模块

    Python 提供了 C++ 库,使得开发者能很方便地从 C++ 程序中调用 Python 模块。接下来通过本文给大家介绍 C++ 调用 Python 模块的相关知识,需要的朋友参考下吧
    2016-03-03
  • VSCode IDE 配置环境过程解析

    VSCode IDE 配置环境过程解析

    这篇文章主要介绍了VSCode IDE 环境配置,这里说的是仅使用 VSCode 创建C/CPP项目时的配置,VSCode 有代码提示, 定位来源和各种快捷键, 更适合日常编码工作,需要的朋友可以参考下
    2022-02-02
  • VS2019创建c++动态链接库dll与调用方法实践

    VS2019创建c++动态链接库dll与调用方法实践

    动态链接库是一个包含可由多个程序同时使用的代码和数据的库,本文主要介绍了VS2019创建c++动态链接库dll与调用方法,具有一定的参考价值,感兴趣的可以了解一下
    2024-06-06
  • C语言数据结构实例讲解单链表的实现

    C语言数据结构实例讲解单链表的实现

    单链表是后面要学的双链表以及循环链表的基础,要想继续深入了解数据结构以及C++,我们就要奠定好这块基石!接下来就和我一起学习吧
    2022-03-03
  • C语言实现加密解密功能

    C语言实现加密解密功能

    这篇文章主要为大家详细介绍了C语言实现加密解密功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-02-02
  • C语言进阶学习之指针

    C语言进阶学习之指针

    关于指针,其是C语言的重点,C语言学的好坏,其实就是指针学的好坏。其实指针并不复杂,学习指针,要正确的理解指针,本片文章能给就来学习一下
    2021-09-09
  • C语言实现520表白代码 祝你表白成功!

    C语言实现520表白代码 祝你表白成功!

    这篇文章主要为大家详细介绍了C语言实现520表白代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-05-05
  • C++中两种字符串定义方式和区别介绍

    C++中两种字符串定义方式和区别介绍

    大家好,本篇文章主要讲的是C++中两种字符串定义方式和区别介绍,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • 如何使用C++结合OpenCV进行图像处理与分类

    如何使用C++结合OpenCV进行图像处理与分类

    在计算机视觉领域,OpenCV与C++结合能高效处理和分类图像,C++的高执行效率适合大规模数据处理,OpenCV提供丰富的功能,如图像预处理和机器学习算法,安装OpenCV需要配置环境和添加库文件,本文详细介绍了使用C++和OpenCV进行图像分类的过程,包括使用SVM和深度学习模型
    2024-09-09
  • C++中fstream,ifstream及ofstream用法浅析

    C++中fstream,ifstream及ofstream用法浅析

    这篇文章主要介绍了C++中fstream,ifstream及ofstream用法,适合C++初学者学习文件流的操作,需要的朋友可以参考下
    2014-08-08

最新评论