资讯专栏INFORMATION COLUMN

C语言指针篇(一篇文章让你不再晕“针”)!!!

zsirfs / 1367人阅读

摘要:指针的大小在位平台是个字节,在位平台是个字节。比如的指针解引用就只能访问一个字节,而的指针的解引用就能访问四个字节。所以是一个指针,指向一个数组,叫数组指针。

准备

博主:大大怪先森(记得关注哦!)
编程环境:vs2013


提示:基于C语言所写的关于指针的内容,小白也能看懂!!!


前言

C语言指针的问题,是否是最让我们头晕眼花???
无限的套娃行为,成为我们惧怕c语言的首要障碍,各位小可爱不要担心。
博主大大已经为各位准备好了学习过程中可能遇到的问题!让我们一起揭开指针的全貌吧!!!!


提示:以下是本篇文章正文内容,内容原创,版权必究!!!

一、指针是什么?

指针:
在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元

除此之外大多数的程序猿的理解即是:指针 = 地址
小结:
指针是用来存放地址的,地址是唯一标示一块地址空间的。
指针的大小在32位平台是4个字节,在64位平台是8个字节。

二、指针和指针类型

1.指针类型

我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢?
将&num(变量num的地址)保存到p指针中,我们知道p就是一个指针变量,那它的类型是怎样的呢?

int main(){	int a = 0;	char ch = 0;	float p = 0.0f;	int* ptr = &a; //整形指针	char* ptr = &ch;//字符指针	float* ptc = &p;//单精度浮点数指针	//...	return 0;}

小结:我们不难看出存放字符变量的地址就是字符指针,存放整形变量的地址的就是整形指针

2.指针类型的解引用

int main(){	int a = 10;	int*  pa = &a;	char* pc = &a;		printf("%p/n", pa);	printf("%p/n", pc);	printf("%p/n", pa+2);	printf("%p/n", pc+2);	//指针类型的意义2:	//指针类型决定了,指针+-整数的时候的步长(指针+-整数的时候,跳过几个字节)	//int* 指针 +1 跳过4个字节	//char* 指针+1 跳过1个字节		//int a = 0x11223344;	//char* pc = &a;//int*	//*pc = 0;	//int*pa = &a;	//*pa = 0;	//指针类型的意义1:	//指针类型决定了指针解引用操作的时候,一次访问几个字节(访问内存的大小)	//char* 指针解引用访问1个字节	//int* 指针解引用访问4个字节	return 0;}

小结:指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。

3.野指针

3.1.野指针的成因

  1. 指针未初始化
int main(){	int* p;//局部变量为初始化默认为随机值	*p = 20;	return 0;}
  1. .指针越界访问
int main(){    int arr[10] = {0};    int *p = arr;    int i = 0;    for(i=0; i<=11; i++)   {        //当指针指向的范围超出数组arr的范围时,p就是野指针        *(p++) = i;   }    return 0; }

3.指针指向的空间内存未释放
详细讲解:请观看博主大大的另一篇文章《动态内存管理》
为了防止小可爱们下次走丢了,赶紧…

3.2.如何规避野指针

我们到底应该怎么规避这些问题?
各位小可爱在运用指针的时候一定要注意一下几点

  1. 指针初始化
  2. 小心指针越界
  3. 指针指向空间释放即使置NULL
  4. 避免返回局部变量的地址
  5. 指针使用之前检查有效性

所以说一个优秀的程序猿代码规范非常重要!!!!
在此给各位小可爱推荐一本书《高质量的c/c++编程》,小编不是在此打广告哦,

静下心好好看一看,我相信各位小可爱一定会受益匪浅!!!

三、指针数组

指针数组是指针还是数组?
答案:是数组。是存放指针的数组。
数组我们已经知道整形数组,字符数组。

int main(){	int a = 10;	int b = 20;	int c = 30;	int* arr[3] = {&a, &b, &c};	int i = 0;	for (i = 0; i < 3; i++)	{		printf("%d/n", *(arr[i]));	}	//int* pa = &a;	//int* pb = &b;	//int* pc = &c;	return 0;}

四、数组指针

1.数组指针的定义

数组指针是指针?还是数组?
答案是:指针。
我们已经熟悉整形指针,浮点数指针,那么数组指针就是指向数组的指针

int* pa[10];int (*pb)[10];到底哪一个是数组指针呢?

答案是:int (*pb)[10]

解释:pb先和*结合,说明pb是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。这里要注意:[]的优先级要高于星号*号的,所以必须加上()来保证pb先和*相结合

2.数组指针的使用

代码如下(示例):

//void print1(int arr[], int sz)//{//	int i = 0;//	for (i = 0; i < sz; i++)//	{//		printf("%d ", arr[i]);//	}//}//void print2(int* arr, int sz)//{//	int i = 0;//	for (i = 0; i < sz; i++)//	{//		printf("%d ", *(arr + i));//	}//}//数组指针//void print3(int (*parr)[10], int sz)//这是一个错误的示范//{//	int i = 0;//	for (i = 0; i < sz; i++)//	{//		printf("%d ", parr[i]);//parr[i] == *(parr+i)//	}//}void print4(int(*pa)[10], int sz){	int i = 0;	for (i = 0; i < sz - 1; i++)	{		//printf("%d ", *(pa + i));//错误 		//printf("%d ", pa[i]);//erro		printf("%d ", (*pa)[i]);//*(pa +0)[i]  == pa[0][i] ==   *(*(pa) + i)		printf("%d ", pa[0][i]);		printf("%d ", *(*(pa)+i));		}}int main(){	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };		int sz = sizeof(arr) / sizeof(arr[0]);		print4(&arr, sz);		//print3(&arr, sz);		//print2(arr, sz);		//print1(arr, sz);//打印arr数组的内容	return 0;}

学习了数组指针你是否对数值指针有更加深刻的理解了~~~
各位下可爱再看看下面的代码的意思吧!

int arr[10];int* arr2[10];int (*pa)[10];int* (*pa[10])(10);

五、指针的传参

1.一维数组传参

思考如下代码(示例):

#include    void test(int arr[])//ok?   {}   void test(int arr[10])//ok?   {}   void test(int *arr)//ok?   {}   void test2(int *arr[20])//ok?   {}   void test2(int **arr)//ok?   {}int main(){   int arr[10] = {0};   int *arr2[20] = {0};   test(arr);   test2(arr2);

1.× 2.√ 3.√ 4.× 5.√

2.二维数组传参

代码如下(示例):

void print2( int(*p)[5], int r, int c){	int i = 0;	for (i = 0; i < r; i++)	{		int j = 0;		for (j = 0; j < c; j++)		{			//printf("%d ", *(*(p + i) + j));			printf("%d ", p[i][j]);		}		printf("/n");	}}int main(){	int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6,3,4,5,6,7 };	//二维数组传参	//print1(arr, 3, 5);	print2(arr, 3, 5);//arr 是数组名,数组名是首元素地址	return 0;}

小结:二维数组传参arr是相当于第一个行的数组名

其他接收参数:int* arr or int** arr or int arr[3][5]

3.一级指针传参

代码如下(示例):

#include void print(int *p, int sz) {     int i = 0;    for(i=0; i<sz; i++)   {    printf("%d/n", *(p+i));   }}int main(){   int arr[10] = {1,2,3,4,5,6,7,8,9};   int *p = arr;   int sz = sizeof(arr)/sizeof(arr[0]);   //一级指针p,传给函数    print(p, sz);   return 0; }

当一个函数的参数部分为一级指针的时候,函数能接收什么参数?

in* p or in** pa or int arr[10];

4.二级指针传参

void test(char **p) {}int main(){    char c = "b";    char*pc = &c;   char**ppc = &pc;   char* arr[10];   test(&pc);   test(ppc);   test(arr);//Ok?   return 0; }

六、函数指针

代码如下(示例):

#include void test(){   printf("hehe/n");}int main(){   printf("%p/n", test);   printf("%p/n", &test);   return 0; }

输出结果:

思考:两者的地址相同,那如何吧地址存放在指针当中?

答案:void (*fun)(int,int)

这就是所谓的函数指针 ,fun是变量名,void (*)(int,int)则是变量的类型,表示fun指向的函数的两个参数分别都是int类型。

七、函数指针数组

数组是一个存放相同类型数据的存储空间,那我们已经学习了指针数组,
比如:

int *arr[10];数组的每个元素是int*

那么那要把函数的地址存到一个数组中,那这个数组就叫函数指针数组,
那函数指针的数组如何定义呢?

int (*pa)(int,int)
int (*pa[10])(int,int)
[]的优先级高于高于解引用的星号所以int (*pa[10])(int,int)的本质上是一个数组,而每一个数组的元素存放的都是一个函数的地址即函数指针,每个函数指针所指向的都是含有两个int类型的参数

小练习:使用函数指针数组实现的简易计算机

#include int add(int a, int b){	return a + b;}int sub(int a, int b){	return a - b;}int mul(int a, int b){	return a*b;}int div(int a, int b){	return a / b;}int main(){	int x, y;	int input = 1;	int ret = 0;	int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表	while (input)	{		printf("*************************/n");		printf(" 1:add           2:sub /n");		printf(" 3:mul           4:div /n");		printf("*************************/n");		printf("请选择:");		scanf("%d", &input);		if ((input <= 4 && input >= 1))		{			printf("输入操作数:");			scanf("%d %d", &x, &y);			ret = (*p[input])(x, y);		}		else			printf("输入有误/n");		printf("ret = %d/n", ret);	}	return 0;}

八、回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一
个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该
函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或
条件进行响应。
详细了解:请关于博主的下一篇文章《指针和数组笔试题》


结语

希望本篇文章能给各位带来帮助,如有不足还请指正!!!码字不易,各位大大给个收藏点赞吧!!!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/121542.html

相关文章

  • C语言】超详讲解☀️是个什么?(次性搞定问题)

    目录 前言 一、 什么是指针? 引例 计算机是怎么对内存单元编号的呢? 内存空间的地址如何得到 想存地址怎么办? ​ 本质目的不是为了存地址  二、指针和指针类型 为什么有不同类型的指针 1.指针的解引用 2.指针+-整数 三、野指针 造成野指针的原因 1.未主动初始化指针  2.指针越界访问 3.指针指向的空间释放 规避野指针 四、指针运算 1.指针+-整数  2.指针-指针  3.指针的关系运...

    tigerZH 评论0 收藏0
  • C语言够了(万二千字,包含与数组,函数等详解)

    摘要:指针变量可以存放基本类型数据的地址,也可以存放数组函数以及其他指针变量的地址。数组名表示的是整个数组所占的字节数。在这里数组指针的类型是。这也是我们可以用数组指针来接收二维数组数组名的原因。 目录 零.前言 一.指针的定义 二.指针类型的意义 1.指针类型决定了指针解引用时一次访问几个字...

    My_Oh_My 评论0 收藏0
  • 五分钟杀穿 pointer——C语言专题

    摘要:另外,通过指针可以更便捷地操作数组。在一定意义上可以说,指针是语言的精髓。野指针成因除了未初始化还有就是越界访问或者指针指向空间已经释放。所以不难知道两个地址相减就是元素的个数,这个表达式的前提是两个指针指向同一块空间。 ...

    MycLambert 评论0 收藏0
  • 21_09_25 C语言杂谈

    摘要:多维数组本质上和一维数组没区别,他的维数仅仅只是作为比例因子和偏移,拿来计算地址偏移用的,但是多级指针用数组访问的时候,他的维数仅仅只做偏移用,他的过程是加偏移,解引用,加偏移,解引用。。。。 类型 c语言中规定类型这样一个事情,主要是出于一个怎样的原因呢? char sho...

    JerryZou 评论0 收藏0
  • 【硬核】用C语言来写学生成绩管理系统,让你的课设不再是难题

    摘要:嗨这里是狐狸大家的期末课设要来了吧,有想法做什么了嘛,有没有为此熬夜,有没有为此努力呢,今天,我们来写一个学生成绩管理系统,一方面是让大家复习一下自己学过的知识,一方面是为了给大家的期末课设提供一点思路。 目录 序 嗨!这里是狐狸~~ 一、需求分析说明 二、概要设计说明 三、详细设计说明 1...

    seanHai 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<